diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 3c7f63def07..2d38281560e 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -4,6 +4,8 @@ steps: sleep 5 && ln -s "$(pwd)" /data/job && cd /data/job && \ echo "+++ Building :hammer:" && \ echo 1 | ./eosio_build.sh && \ + echo "+++ Validating:" && \ + echo 1 | ./tools/validate_reflection.py plugins/ programs/ libraries/ --recurse --extension "cpp" --extension "hpp" -e && \ echo "--- Compressing build directory :compression:" && \ tar -pczf build.tar.gz build/ label: ":darwin: High Sierra Build" @@ -17,6 +19,8 @@ steps: sleep 5 && ln -s "$(pwd)" /data/job && cd /data/job && \ echo "+++ Building :hammer:" && \ echo 1 | ./eosio_build.sh && \ + echo "+++ Validating:" && \ + echo 1 | ./tools/validate_reflection.py plugins/ programs/ libraries/ --recurse --extension "cpp" --extension "hpp" -e && \ echo "--- Compressing build directory :compression:" && \ tar -pczf build.tar.gz build/ label: ":darwin: Mojave Build" @@ -29,6 +33,8 @@ steps: - command: | echo "+++ :hammer: Building" && \ echo 1 | ./eosio_build.sh && \ + echo "+++ Validating:" && \ + echo 1 | ./tools/validate_reflection.py plugins/ programs/ libraries/ --recurse --extension "cpp" --extension "hpp" -e && \ echo "--- :compression: Compressing build directory" && \ tar -pczf build.tar.gz build/ label: ":ubuntu: Build" @@ -44,6 +50,8 @@ steps: - command: | echo "+++ :hammer: Building" && \ echo 1 | ./eosio_build.sh && \ + echo "+++ Validating:" && \ + echo 1 | ./tools/validate_reflection.py plugins/ programs/ libraries/ --recurse --extension "cpp" --extension "hpp" -e && \ echo "--- :compression: Compressing build directory" && \ tar -pczf build.tar.gz build/ label: ":ubuntu: 18.04 Build" @@ -59,6 +67,8 @@ steps: - command: | echo "+++ :hammer: Building" && \ echo 1 | ./eosio_build.sh && \ + echo "+++ Validating:" && \ + echo 1 | ./tools/validate_reflection.py plugins/ programs/ libraries/ --recurse --extension "cpp" --extension "hpp" -e && \ echo "--- :compression: Compressing build directory" && \ tar -pczf build.tar.gz build/ label: ":fedora: Build" @@ -74,6 +84,8 @@ steps: - command: | echo "+++ :hammer: Building" && \ echo 1 | ./eosio_build.sh && \ + echo "+++ Validating:" && \ + echo 1 | ./tools/validate_reflection.py plugins/ programs/ libraries/ --recurse --extension "cpp" --extension "hpp" -e && \ echo "--- :compression: Compressing build directory" && \ tar -pczf build.tar.gz build/ label: ":centos: Build" @@ -89,6 +101,8 @@ steps: - command: | echo "+++ :hammer: Building" && \ echo 1 | ./eosio_build.sh && \ + echo "+++ Validating:" && \ + echo 1 | ./tools/validate_reflection.py plugins/ programs/ libraries/ --recurse --extension "cpp" --extension "hpp" -e && \ echo "--- :compression: Compressing build directory" && \ tar -pczf build.tar.gz build/ label: ":aws: Build" diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7e186303e51..b150791495d 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,20 +1,23 @@ - + ## Change Description + - ## Consensus Changes - +- [ ] Consensus Changes + ## API Changes - +- [ ] API Changes + ## Documentation Additions - - +- [ ] Documentation Additions + + diff --git a/.gitignore b/.gitignore index db49e70c299..6ab1edbaa7e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,9 @@ *.dylib *.ll *.bc +*.wasm *.wast *.wast.hpp -*.wasm *.s *.dot *.abi.hpp diff --git a/.gitmodules b/.gitmodules index 7d0f8a37f7b..6ac601cdcc2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,27 +6,12 @@ path = libraries/appbase url = https://github.com/eosio/appbase ignore = dirty -[submodule "contracts/musl/upstream"] - path = contracts/musl/upstream - url = https://github.com/EOSIO/musl.git - branch = eosio -[submodule "contracts/libc++/upstream"] - path = contracts/libc++/upstream - url = https://github.com/EOSIO/libcxx.git - branch = eosio -[submodule "externals/binaryen"] - path = externals/binaryen - url = https://github.com/EOSIO/binaryen - [submodule "libraries/softfloat"] path = libraries/softfloat url = https://github.com/eosio/berkeley-softfloat-3 -[submodule "externals/magic_get"] - path = externals/magic_get - url = https://github.com/EOSIO/magic_get [submodule "libraries/fc"] path = libraries/fc url = https://github.com/EOSIO/fc [submodule "libraries/wabt"] path = libraries/wabt - url = http://github.com/EOSIO/wabt + url = https://github.com/EOSIO/wabt diff --git a/CMakeLists.txt b/CMakeLists.txt index a12c1b58c8c..127c7b919e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,12 +72,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") set(BUILD_DOXYGEN FALSE CACHE BOOL "Build doxygen documentation on every make") set(BUILD_MONGO_DB_PLUGIN FALSE CACHE BOOL "Build mongo database plugin") -#set (USE_PCH 1) - -if (USE_PCH) - include (cotire) -endif(USE_PCH) - # add defaults for openssl if ("${OPENSSL_ROOT_DIR}" STREQUAL "") if (NOT "$ENV{OPENSSL_ROOT_DIR}" STREQUAL "") @@ -207,7 +201,6 @@ if(ENABLE_COVERAGE_TESTING) endif() include(utils) -add_subdirectory( externals ) if ("${CORE_SYMBOL_NAME}" STREQUAL "") set( CORE_SYMBOL_NAME "SYS" ) @@ -227,9 +220,7 @@ endif() message( STATUS "Using '${EOSIO_ROOT_KEY}' as public key for 'eosio' account" ) -include(wasm) add_subdirectory( libraries ) -add_subdirectory( contracts ) add_subdirectory( plugins ) add_subdirectory( programs ) add_subdirectory( scripts ) @@ -270,16 +261,19 @@ configure_file(${CMAKE_SOURCE_DIR}/libraries/fc/secp256k1/upstream/COPYING ${CMAKE_BINARY_DIR}/licenses/eosio/LICENSE.secp256k1 COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/libraries/fc/src/network/LICENSE.go ${CMAKE_BINARY_DIR}/licenses/eosio/LICENSE.go COPYONLY) -configure_file(${CMAKE_SOURCE_DIR}/externals/binaryen/LICENSE - ${CMAKE_BINARY_DIR}/licenses/eosio/LICENSE.binaryen COPYONLY) - -install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/) -install(FILES libraries/wabt/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.wabt) -install(FILES libraries/softfloat/COPYING.txt DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.softfloat) -install(FILES libraries/wasm-jit/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.wavm) -install(FILES libraries/fc/secp256k1/upstream/COPYING DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.secp256k1) -install(FILES externals/binaryen/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.binaryen) -install(FILES libraries/fc/src/network/LICENSE.go DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ ) + +install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ COMPONENT base) +install(FILES libraries/wabt/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.wabt COMPONENT base) +install(FILES libraries/softfloat/COPYING.txt DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.softfloat COMPONENT base) +install(FILES libraries/wasm-jit/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.wavm COMPONENT base) +install(FILES libraries/fc/secp256k1/upstream/COPYING DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ RENAME LICENSE.secp256k1 COMPONENT base) +install(FILES libraries/fc/src/network/LICENSE.go DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/eosio/ COMPONENT base) + +add_custom_target(base-install + COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" + COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=base -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + USES_TERMINAL +) include(package) include(doxygen) diff --git a/CMakeModules/FindWasm.cmake b/CMakeModules/FindWasm.cmake deleted file mode 100644 index 99d78772612..00000000000 --- a/CMakeModules/FindWasm.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# - Try to find WASM - -# TODO: Check if compiler is able to generate wasm32 -if ("${WASM_ROOT}" STREQUAL "") - if (APPLE) - set( WASM_ROOT "/usr/local/wasm" ) - elseif (UNIX AND NOT APPLE) - set( WASM_ROOT "$ENV{HOME}/opt/wasm" ) - else() - message(FATAL_ERROR "WASM not found and don't know where to look, please specify WASM_ROOT") - endif() -endif() -find_program(WASM_CLANG clang PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH) -find_program(WASM_LLC llc PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH) -find_program(WASM_LLVM_LINK llvm-link PATHS ${WASM_ROOT}/bin NO_DEFAULT_PATH) - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set EOS_FOUND to TRUE -# if all listed variables are TRUE - -find_package_handle_standard_args(WASM REQUIRED_VARS WASM_CLANG WASM_LLC WASM_LLVM_LINK) - diff --git a/CMakeModules/cotire.cmake b/CMakeModules/cotire.cmake deleted file mode 100644 index ab611007dc4..00000000000 --- a/CMakeModules/cotire.cmake +++ /dev/null @@ -1,4008 +0,0 @@ -# - cotire (compile time reducer) -# -# See the cotire manual for usage hints. -# -#============================================================================= -# Copyright 2012-2016 Sascha Kratky -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation -# files (the "Software"), to deal in the Software without -# restriction, including without limitation the rights to use, -# copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following -# conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -#============================================================================= - -if(__COTIRE_INCLUDED) - return() -endif() -set(__COTIRE_INCLUDED TRUE) - -# call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode -# cmake_minimum_required also sets the policy version as a side effect, which we have to avoid -if (NOT CMAKE_SCRIPT_MODE_FILE) - cmake_policy(PUSH) -endif() -cmake_minimum_required(VERSION 2.8.12) -if (NOT CMAKE_SCRIPT_MODE_FILE) - cmake_policy(POP) -endif() - -set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}") -set (COTIRE_CMAKE_MODULE_VERSION "1.7.9") - -# activate select policies -if (POLICY CMP0025) - # Compiler id for Apple Clang is now AppleClang - cmake_policy(SET CMP0025 NEW) -endif() - -if (POLICY CMP0026) - # disallow use of the LOCATION target property - cmake_policy(SET CMP0026 NEW) -endif() - -if (POLICY CMP0038) - # targets may not link directly to themselves - cmake_policy(SET CMP0038 NEW) -endif() - -if (POLICY CMP0039) - # utility targets may not have link dependencies - cmake_policy(SET CMP0039 NEW) -endif() - -if (POLICY CMP0040) - # target in the TARGET signature of add_custom_command() must exist - cmake_policy(SET CMP0040 NEW) -endif() - -if (POLICY CMP0045) - # error on non-existent target in get_target_property - cmake_policy(SET CMP0045 NEW) -endif() - -if (POLICY CMP0046) - # error on non-existent dependency in add_dependencies - cmake_policy(SET CMP0046 NEW) -endif() - -if (POLICY CMP0049) - # do not expand variables in target source entries - cmake_policy(SET CMP0049 NEW) -endif() - -if (POLICY CMP0050) - # disallow add_custom_command SOURCE signatures - cmake_policy(SET CMP0050 NEW) -endif() - -if (POLICY CMP0051) - # include TARGET_OBJECTS expressions in a target's SOURCES property - cmake_policy(SET CMP0051 NEW) -endif() - -if (POLICY CMP0053) - # simplify variable reference and escape sequence evaluation - cmake_policy(SET CMP0053 NEW) -endif() - -if (POLICY CMP0054) - # only interpret if() arguments as variables or keywords when unquoted - cmake_policy(SET CMP0054 NEW) -endif() - -include(CMakeParseArguments) -include(ProcessorCount) - -function (cotire_get_configuration_types _configsVar) - set (_configs "") - if (CMAKE_CONFIGURATION_TYPES) - list (APPEND _configs ${CMAKE_CONFIGURATION_TYPES}) - endif() - if (CMAKE_BUILD_TYPE) - list (APPEND _configs "${CMAKE_BUILD_TYPE}") - endif() - if (_configs) - list (REMOVE_DUPLICATES _configs) - set (${_configsVar} ${_configs} PARENT_SCOPE) - else() - set (${_configsVar} "None" PARENT_SCOPE) - endif() -endfunction() - -function (cotire_get_source_file_extension _sourceFile _extVar) - # get_filename_component returns extension from first occurrence of . in file name - # this function computes the extension from last occurrence of . in file name - string (FIND "${_sourceFile}" "." _index REVERSE) - if (_index GREATER -1) - math (EXPR _index "${_index} + 1") - string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt) - else() - set (_sourceExt "") - endif() - set (${_extVar} "${_sourceExt}" PARENT_SCOPE) -endfunction() - -macro (cotire_check_is_path_relative_to _path _isRelativeVar) - set (${_isRelativeVar} FALSE) - if (IS_ABSOLUTE "${_path}") - foreach (_dir ${ARGN}) - file (RELATIVE_PATH _relPath "${_dir}" "${_path}") - if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")) - set (${_isRelativeVar} TRUE) - break() - endif() - endforeach() - endif() -endmacro() - -function (cotire_filter_language_source_files _language _target _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar) - if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) - set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}") - else() - set (_languageExtensions "") - endif() - if (CMAKE_${_language}_IGNORE_EXTENSIONS) - set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}") - else() - set (_ignoreExtensions "") - endif() - if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS) - set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}") - else() - set (_excludeExtensions "") - endif() - if (COTIRE_DEBUG AND _languageExtensions) - message (STATUS "${_language} source file extensions: ${_languageExtensions}") - endif() - if (COTIRE_DEBUG AND _ignoreExtensions) - message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}") - endif() - if (COTIRE_DEBUG AND _excludeExtensions) - message (STATUS "${_language} exclude extensions: ${_excludeExtensions}") - endif() - if (CMAKE_VERSION VERSION_LESS "3.1.0") - set (_allSourceFiles ${ARGN}) - else() - # as of CMake 3.1 target sources may contain generator expressions - # since we cannot obtain required property information about source files added - # through generator expressions at configure time, we filter them out - string (GENEX_STRIP "${ARGN}" _allSourceFiles) - endif() - set (_filteredSourceFiles "") - set (_excludedSourceFiles "") - foreach (_sourceFile ${_allSourceFiles}) - get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY) - get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT) - get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC) - if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic) - cotire_get_source_file_extension("${_sourceFile}" _sourceExt) - if (_sourceExt) - list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex) - if (_ignoreIndex LESS 0) - list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex) - if (_excludeIndex GREATER -1) - list (APPEND _excludedSourceFiles "${_sourceFile}") - else() - list (FIND _languageExtensions "${_sourceExt}" _sourceIndex) - if (_sourceIndex GREATER -1) - # consider source file unless it is excluded explicitly - get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED) - if (_sourceIsExcluded) - list (APPEND _excludedSourceFiles "${_sourceFile}") - else() - list (APPEND _filteredSourceFiles "${_sourceFile}") - endif() - else() - get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE) - if ("${_sourceLanguage}" STREQUAL "${_language}") - # add to excluded sources, if file is not ignored and has correct language without having the correct extension - list (APPEND _excludedSourceFiles "${_sourceFile}") - endif() - endif() - endif() - endif() - endif() - endif() - endforeach() - # separate filtered source files from already cotired ones - # the COTIRE_TARGET property of a source file may be set while a target is being processed by cotire - set (_sourceFiles "") - set (_cotiredSourceFiles "") - foreach (_sourceFile ${_filteredSourceFiles}) - get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET) - if (_sourceIsCotired) - list (APPEND _cotiredSourceFiles "${_sourceFile}") - else() - get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS) - if (_sourceCompileFlags) - # add to excluded sources, if file has custom compile flags - list (APPEND _excludedSourceFiles "${_sourceFile}") - else() - list (APPEND _sourceFiles "${_sourceFile}") - endif() - endif() - endforeach() - if (COTIRE_DEBUG) - if (_sourceFiles) - message (STATUS "Filtered ${_target} ${_language} sources: ${_sourceFiles}") - endif() - if (_excludedSourceFiles) - message (STATUS "Excluded ${_target} ${_language} sources: ${_excludedSourceFiles}") - endif() - if (_cotiredSourceFiles) - message (STATUS "Cotired ${_target} ${_language} sources: ${_cotiredSourceFiles}") - endif() - endif() - set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE) - set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE) - set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE) -endfunction() - -function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type) - set (_filteredObjects "") - foreach (_object ${ARGN}) - get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (_propertyValue) - list (APPEND _filteredObjects "${_object}") - endif() - endif() - endforeach() - set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) -endfunction() - -function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type) - set (_filteredObjects "") - foreach (_object ${ARGN}) - get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (NOT _propertyValue) - list (APPEND _filteredObjects "${_object}") - endif() - endif() - endforeach() - set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_file_property_values _valuesVar _property) - set (_values "") - foreach (_sourceFile ${ARGN}) - get_source_file_property(_propertyValue "${_sourceFile}" ${_property}) - if (_propertyValue) - list (APPEND _values "${_propertyValue}") - endif() - endforeach() - set (${_valuesVar} ${_values} PARENT_SCOPE) -endfunction() - -function (cotire_resolve_config_properites _configurations _propertiesVar) - set (_properties "") - foreach (_property ${ARGN}) - if ("${_property}" MATCHES "") - foreach (_config ${_configurations}) - string (TOUPPER "${_config}" _upperConfig) - string (REPLACE "" "${_upperConfig}" _configProperty "${_property}") - list (APPEND _properties ${_configProperty}) - endforeach() - else() - list (APPEND _properties ${_property}) - endif() - endforeach() - set (${_propertiesVar} ${_properties} PARENT_SCOPE) -endfunction() - -function (cotire_copy_set_properites _configurations _type _source _target) - cotire_resolve_config_properites("${_configurations}" _properties ${ARGN}) - foreach (_property ${_properties}) - get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property}) - set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}") - endif() - endforeach() -endfunction() - -function (cotire_get_target_usage_requirements _target _targetRequirementsVar) - set (_targetRequirements "") - get_target_property(_librariesToProcess ${_target} LINK_LIBRARIES) - while (_librariesToProcess) - # remove from head - list (GET _librariesToProcess 0 _library) - list (REMOVE_AT _librariesToProcess 0) - if (TARGET ${_library}) - list (FIND _targetRequirements ${_library} _index) - if (_index LESS 0) - list (APPEND _targetRequirements ${_library}) - # BFS traversal of transitive libraries - get_target_property(_libraries ${_library} INTERFACE_LINK_LIBRARIES) - if (_libraries) - list (APPEND _librariesToProcess ${_libraries}) - list (REMOVE_DUPLICATES _librariesToProcess) - endif() - endif() - endif() - endwhile() - set (${_targetRequirementsVar} ${_targetRequirements} PARENT_SCOPE) -endfunction() - -function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - set (_flagPrefix "[/-]") - else() - set (_flagPrefix "--?") - endif() - set (_optionFlag "") - set (_matchedOptions "") - set (_unmatchedOptions "") - foreach (_compileFlag ${ARGN}) - if (_compileFlag) - if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}") - # option with separate argument - list (APPEND _matchedOptions "${_compileFlag}") - set (_optionFlag "") - elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$") - # remember option - set (_optionFlag "${CMAKE_MATCH_2}") - elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$") - # option with joined argument - list (APPEND _matchedOptions "${CMAKE_MATCH_3}") - set (_optionFlag "") - else() - # flush remembered option - if (_optionFlag) - list (APPEND _matchedOptions "${_optionFlag}") - set (_optionFlag "") - endif() - # add to unfiltered options - list (APPEND _unmatchedOptions "${_compileFlag}") - endif() - endif() - endforeach() - if (_optionFlag) - list (APPEND _matchedOptions "${_optionFlag}") - endif() - if (COTIRE_DEBUG AND _matchedOptions) - message (STATUS "Filter ${_flagFilter} matched: ${_matchedOptions}") - endif() - if (COTIRE_DEBUG AND _unmatchedOptions) - message (STATUS "Filter ${_flagFilter} unmatched: ${_unmatchedOptions}") - endif() - set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE) - set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE) -endfunction() - -function (cotire_is_target_supported _target _isSupportedVar) - if (NOT TARGET "${_target}") - set (${_isSupportedVar} FALSE PARENT_SCOPE) - return() - endif() - get_target_property(_imported ${_target} IMPORTED) - if (_imported) - set (${_isSupportedVar} FALSE PARENT_SCOPE) - return() - endif() - get_target_property(_targetType ${_target} TYPE) - if (NOT _targetType MATCHES "EXECUTABLE|(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") - set (${_isSupportedVar} FALSE PARENT_SCOPE) - return() - endif() - set (${_isSupportedVar} TRUE PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compile_flags _config _language _target _flagsVar) - string (TOUPPER "${_config}" _upperConfig) - # collect options from CMake language variables - set (_compileFlags "") - if (CMAKE_${_language}_FLAGS) - set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}") - endif() - if (CMAKE_${_language}_FLAGS_${_upperConfig}) - set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}") - endif() - if (_target) - # add target compile flags - get_target_property(_targetflags ${_target} COMPILE_FLAGS) - if (_targetflags) - set (_compileFlags "${_compileFlags} ${_targetflags}") - endif() - endif() - if (UNIX) - separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}") - elseif(WIN32) - separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}") - else() - separate_arguments(_compileFlags) - endif() - # target compile options - if (_target) - get_target_property(_targetOptions ${_target} COMPILE_OPTIONS) - if (_targetOptions) - list (APPEND _compileFlags ${_targetOptions}) - endif() - endif() - # interface compile options from linked library targets - if (_target) - set (_linkedTargets "") - cotire_get_target_usage_requirements(${_target} _linkedTargets) - foreach (_linkedTarget ${_linkedTargets}) - get_target_property(_targetOptions ${_linkedTarget} INTERFACE_COMPILE_OPTIONS) - if (_targetOptions) - list (APPEND _compileFlags ${_targetOptions}) - endif() - endforeach() - endif() - # handle language standard properties - if (CMAKE_${_language}_STANDARD_DEFAULT) - # used compiler supports language standard levels - if (_target) - get_target_property(_targetLanguageStandard ${_target} ${_language}_STANDARD) - if (_targetLanguageStandard) - set (_type "EXTENSION") - get_property(_isSet TARGET ${_target} PROPERTY ${_language}_EXTENSIONS SET) - if (_isSet) - get_target_property(_targetUseLanguageExtensions ${_target} ${_language}_EXTENSIONS) - if (NOT _targetUseLanguageExtensions) - set (_type "STANDARD") - endif() - endif() - if (CMAKE_${_language}${_targetLanguageStandard}_${_type}_COMPILE_OPTION) - list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_${_type}_COMPILE_OPTION}") - endif() - endif() - endif() - endif() - # handle the POSITION_INDEPENDENT_CODE target property - if (_target) - get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE) - if (_targetPIC) - get_target_property(_targetType ${_target} TYPE) - if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE) - list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIE}") - elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC) - list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIC}") - endif() - endif() - endif() - # handle visibility target properties - if (_target) - get_target_property(_targetVisibility ${_target} ${_language}_VISIBILITY_PRESET) - if (_targetVisibility AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY) - list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY}${_targetVisibility}") - endif() - get_target_property(_targetVisibilityInlines ${_target} VISIBILITY_INLINES_HIDDEN) - if (_targetVisibilityInlines AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN) - list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN}") - endif() - endif() - # platform specific flags - if (APPLE) - get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig}) - if (NOT _architectures) - get_target_property(_architectures ${_target} OSX_ARCHITECTURES) - endif() - if (_architectures) - foreach (_arch ${_architectures}) - list (APPEND _compileFlags "-arch" "${_arch}") - endforeach() - endif() - if (CMAKE_OSX_SYSROOT) - if (CMAKE_${_language}_SYSROOT_FLAG) - list (APPEND _compileFlags "${CMAKE_${_language}_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}") - else() - list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}") - endif() - endif() - if (CMAKE_OSX_DEPLOYMENT_TARGET) - if (CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG) - list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}") - else() - list (APPEND _compileFlags "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") - endif() - endif() - endif() - if (COTIRE_DEBUG AND _compileFlags) - message (STATUS "Target ${_target} compile flags: ${_compileFlags}") - endif() - set (${_flagsVar} ${_compileFlags} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_include_directories _config _language _target _includeDirsVar _systemIncludeDirsVar) - set (_includeDirs "") - set (_systemIncludeDirs "") - # default include dirs - if (CMAKE_INCLUDE_CURRENT_DIR) - list (APPEND _includeDirs "${CMAKE_CURRENT_BINARY_DIR}") - list (APPEND _includeDirs "${CMAKE_CURRENT_SOURCE_DIR}") - endif() - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) - # parse additional include directories from target compile flags - if (CMAKE_INCLUDE_FLAG_${_language}) - string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag) - string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") - if (_includeFlag) - set (_dirs "") - cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags}) - if (_dirs) - list (APPEND _includeDirs ${_dirs}) - endif() - endif() - endif() - # parse additional system include directories from target compile flags - if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language}) - string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag) - string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") - if (_includeFlag) - set (_dirs "") - cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags}) - if (_dirs) - list (APPEND _systemIncludeDirs ${_dirs}) - endif() - endif() - endif() - # target include directories - get_directory_property(_dirs DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" INCLUDE_DIRECTORIES) - if (_target) - get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _dirs ${_targetDirs}) - endif() - get_target_property(_targetDirs ${_target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _systemIncludeDirs ${_targetDirs}) - endif() - endif() - # interface include directories from linked library targets - if (_target) - set (_linkedTargets "") - cotire_get_target_usage_requirements(${_target} _linkedTargets) - foreach (_linkedTarget ${_linkedTargets}) - get_target_property(_linkedTargetType ${_linkedTarget} TYPE) - if (CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE AND NOT CMAKE_VERSION VERSION_LESS "3.4.0" AND - _linkedTargetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") - # CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE refers to CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR - # at the time, when the target was created. These correspond to the target properties BINARY_DIR and SOURCE_DIR - # which are only available with CMake 3.4 or later. - get_target_property(_targetDirs ${_linkedTarget} BINARY_DIR) - if (_targetDirs) - list (APPEND _dirs ${_targetDirs}) - endif() - get_target_property(_targetDirs ${_linkedTarget} SOURCE_DIR) - if (_targetDirs) - list (APPEND _dirs ${_targetDirs}) - endif() - endif() - get_target_property(_targetDirs ${_linkedTarget} INTERFACE_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _dirs ${_targetDirs}) - endif() - get_target_property(_targetDirs ${_linkedTarget} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _systemIncludeDirs ${_targetDirs}) - endif() - endforeach() - endif() - if (dirs) - list (REMOVE_DUPLICATES _dirs) - endif() - list (LENGTH _includeDirs _projectInsertIndex) - foreach (_dir ${_dirs}) - if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE) - cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}") - if (_isRelative) - list (LENGTH _includeDirs _len) - if (_len EQUAL _projectInsertIndex) - list (APPEND _includeDirs "${_dir}") - else() - list (INSERT _includeDirs _projectInsertIndex "${_dir}") - endif() - math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1") - else() - list (APPEND _includeDirs "${_dir}") - endif() - else() - list (APPEND _includeDirs "${_dir}") - endif() - endforeach() - list (REMOVE_DUPLICATES _includeDirs) - list (REMOVE_DUPLICATES _systemIncludeDirs) - if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES) - list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES}) - endif() - if (WIN32) - # convert Windows paths in include directories to CMake paths - if (_includeDirs) - set (_paths "") - foreach (_dir ${_includeDirs}) - file (TO_CMAKE_PATH "${_dir}" _path) - list (APPEND _paths "${_path}") - endforeach() - set (_includeDirs ${_paths}) - endif() - if (_systemIncludeDirs) - set (_paths "") - foreach (_dir ${_systemIncludeDirs}) - file (TO_CMAKE_PATH "${_dir}" _path) - list (APPEND _paths "${_path}") - endforeach() - set (_systemIncludeDirs ${_paths}) - endif() - endif() - if (COTIRE_DEBUG AND _includeDirs) - message (STATUS "Target ${_target} include dirs: ${_includeDirs}") - endif() - set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE) - if (COTIRE_DEBUG AND _systemIncludeDirs) - message (STATUS "Target ${_target} system include dirs: ${_systemIncludeDirs}") - endif() - set (${_systemIncludeDirsVar} ${_systemIncludeDirs} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_export_symbol _target _exportSymbolVar) - set (_exportSymbol "") - get_target_property(_targetType ${_target} TYPE) - get_target_property(_enableExports ${_target} ENABLE_EXPORTS) - if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR - (_targetType STREQUAL "EXECUTABLE" AND _enableExports)) - get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL) - if (NOT _exportSymbol) - set (_exportSymbol "${_target}_EXPORTS") - endif() - string (MAKE_C_IDENTIFIER "${_exportSymbol}" _exportSymbol) - endif() - set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compile_definitions _config _language _target _definitionsVar) - string (TOUPPER "${_config}" _upperConfig) - set (_configDefinitions "") - # CMAKE_INTDIR for multi-configuration build systems - if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") - list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"") - endif() - # target export define symbol - cotire_get_target_export_symbol("${_target}" _defineSymbol) - if (_defineSymbol) - list (APPEND _configDefinitions "${_defineSymbol}") - endif() - # directory compile definitions - get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - # target compile definitions - get_target_property(_definitions ${_target} COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - # interface compile definitions from linked library targets - set (_linkedTargets "") - cotire_get_target_usage_requirements(${_target} _linkedTargets) - foreach (_linkedTarget ${_linkedTargets}) - get_target_property(_definitions ${_linkedTarget} INTERFACE_COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - endforeach() - # parse additional compile definitions from target compile flags - # and don't look at directory compile definitions, which we already handled - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) - cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - list (REMOVE_DUPLICATES _configDefinitions) - if (COTIRE_DEBUG AND _configDefinitions) - message (STATUS "Target ${_target} compile definitions: ${_configDefinitions}") - endif() - set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compiler_flags _config _language _target _compilerFlagsVar) - # parse target compile flags omitting compile definitions and include directives - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) - set (_flagFilter "D") - if (CMAKE_INCLUDE_FLAG_${_language}) - string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag) - string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") - if (_includeFlag) - set (_flagFilter "${_flagFilter}|${_includeFlag}") - endif() - endif() - if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language}) - string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag) - string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") - if (_includeFlag) - set (_flagFilter "${_flagFilter}|${_includeFlag}") - endif() - endif() - set (_compilerFlags "") - cotire_filter_compile_flags("${_language}" "${_flagFilter}" _ignore _compilerFlags ${_targetFlags}) - if (COTIRE_DEBUG AND _compilerFlags) - message (STATUS "Target ${_target} compiler flags: ${_compilerFlags}") - endif() - set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE) -endfunction() - -function (cotire_add_sys_root_paths _pathsVar) - if (APPLE) - if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT) - foreach (_path IN LISTS ${_pathsVar}) - if (IS_ABSOLUTE "${_path}") - get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE) - if (EXISTS "${_path}") - list (APPEND ${_pathsVar} "${_path}") - endif() - endif() - endforeach() - endif() - endif() - set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar) - set (_extraProperties ${ARGN}) - set (_result "") - if (_extraProperties) - list (FIND _extraProperties "${_sourceFile}" _index) - if (_index GREATER -1) - math (EXPR _index "${_index} + 1") - list (LENGTH _extraProperties _len) - math (EXPR _len "${_len} - 1") - foreach (_index RANGE ${_index} ${_len}) - list (GET _extraProperties ${_index} _value) - if (_value MATCHES "${_pattern}") - list (APPEND _result "${_value}") - else() - break() - endif() - endforeach() - endif() - endif() - set (${_resultVar} ${_result} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar) - set (_compileDefinitions "") - if (NOT CMAKE_SCRIPT_MODE_FILE) - string (TOUPPER "${_config}" _upperConfig) - get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - endif() - cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN}) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - if (COTIRE_DEBUG AND _compileDefinitions) - message (STATUS "Source ${_sourceFile} compile definitions: ${_compileDefinitions}") - endif() - set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_files_compile_definitions _config _language _definitionsVar) - set (_configDefinitions "") - foreach (_sourceFile ${ARGN}) - cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions) - if (_sourceDefinitions) - list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-") - endif() - endforeach() - set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar) - set (_sourceUndefs "") - if (NOT CMAKE_SCRIPT_MODE_FILE) - get_source_file_property(_undefs "${_sourceFile}" ${_property}) - if (_undefs) - list (APPEND _sourceUndefs ${_undefs}) - endif() - endif() - cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN}) - if (_undefs) - list (APPEND _sourceUndefs ${_undefs}) - endif() - if (COTIRE_DEBUG AND _sourceUndefs) - message (STATUS "Source ${_sourceFile} ${_property} undefs: ${_sourceUndefs}") - endif() - set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_files_undefs _property _sourceUndefsVar) - set (_sourceUndefs "") - foreach (_sourceFile ${ARGN}) - cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs) - if (_undefs) - list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-") - endif() - endforeach() - set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) -endfunction() - -macro (cotire_set_cmd_to_prologue _cmdVar) - set (${_cmdVar} "${CMAKE_COMMAND}") - if (COTIRE_DEBUG) - list (APPEND ${_cmdVar} "--warn-uninitialized") - endif() - list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$") - if (COTIRE_VERBOSE) - list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON") - elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles") - list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)") - endif() -endmacro() - -function (cotire_init_compile_cmd _cmdVar _language _compilerLauncher _compilerExe _compilerArg1) - if (NOT _compilerLauncher) - set (_compilerLauncher ${CMAKE_${_language}_COMPILER_LAUNCHER}) - endif() - if (NOT _compilerExe) - set (_compilerExe "${CMAKE_${_language}_COMPILER}") - endif() - if (NOT _compilerArg1) - set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1}) - endif() - string (STRIP "${_compilerArg1}" _compilerArg1) - if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - # compiler launcher is only supported for Makefile and Ninja - set (${_cmdVar} ${_compilerLauncher} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) - else() - set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) - endif() -endfunction() - -macro (cotire_add_definitions_to_cmd _cmdVar _language) - foreach (_definition ${ARGN}) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - list (APPEND ${_cmdVar} "/D${_definition}") - else() - list (APPEND ${_cmdVar} "-D${_definition}") - endif() - endforeach() -endmacro() - -function (cotire_add_includes_to_cmd _cmdVar _language _includesVar _systemIncludesVar) - set (_includeDirs ${${_includesVar}} ${${_systemIncludesVar}}) - if (_includeDirs) - list (REMOVE_DUPLICATES _includeDirs) - foreach (_include ${_includeDirs}) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - file (TO_NATIVE_PATH "${_include}" _include) - list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_${_language}_SEP}${_include}") - else() - set (_index -1) - if ("${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" MATCHES ".+") - list (FIND ${_systemIncludesVar} "${_include}" _index) - endif() - if (_index GREATER -1) - list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}${_include}") - else() - list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_${_language}_SEP}${_include}") - endif() - endif() - endforeach() - endif() - set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE) -endfunction() - -function (cotire_add_frameworks_to_cmd _cmdVar _language _includesVar _systemIncludesVar) - if (APPLE) - set (_frameworkDirs "") - foreach (_include ${${_includesVar}}) - if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") - get_filename_component(_frameworkDir "${_include}" DIRECTORY) - list (APPEND _frameworkDirs "${_frameworkDir}") - endif() - endforeach() - set (_systemFrameworkDirs "") - foreach (_include ${${_systemIncludesVar}}) - if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") - get_filename_component(_frameworkDir "${_include}" DIRECTORY) - list (APPEND _systemFrameworkDirs "${_frameworkDir}") - endif() - endforeach() - if (_systemFrameworkDirs) - list (APPEND _frameworkDirs ${_systemFrameworkDirs}) - endif() - if (_frameworkDirs) - list (REMOVE_DUPLICATES _frameworkDirs) - foreach (_frameworkDir ${_frameworkDirs}) - set (_index -1) - if ("${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}" MATCHES ".+") - list (FIND _systemFrameworkDirs "${_frameworkDir}" _index) - endif() - if (_index GREATER -1) - list (APPEND ${_cmdVar} "${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}") - else() - list (APPEND ${_cmdVar} "${CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}") - endif() - endforeach() - endif() - endif() - set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE) -endfunction() - -macro (cotire_add_compile_flags_to_cmd _cmdVar) - foreach (_flag ${ARGN}) - list (APPEND ${_cmdVar} "${_flag}") - endforeach() -endmacro() - -function (cotire_check_file_up_to_date _fileIsUpToDateVar _file) - if (EXISTS "${_file}") - set (_triggerFile "") - foreach (_dependencyFile ${ARGN}) - if (EXISTS "${_dependencyFile}") - # IS_NEWER_THAN returns TRUE if both files have the same timestamp - # thus we do the comparison in both directions to exclude ties - if ("${_dependencyFile}" IS_NEWER_THAN "${_file}" AND - NOT "${_file}" IS_NEWER_THAN "${_dependencyFile}") - set (_triggerFile "${_dependencyFile}") - break() - endif() - endif() - endforeach() - if (_triggerFile) - if (COTIRE_VERBOSE) - get_filename_component(_fileName "${_file}" NAME) - message (STATUS "${_fileName} update triggered by ${_triggerFile} change.") - endif() - set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) - else() - if (COTIRE_VERBOSE) - get_filename_component(_fileName "${_file}" NAME) - message (STATUS "${_fileName} is up-to-date.") - endif() - set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE) - endif() - else() - if (COTIRE_VERBOSE) - get_filename_component(_fileName "${_file}" NAME) - message (STATUS "${_fileName} does not exist yet.") - endif() - set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) - endif() -endfunction() - -macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar) - set (${_relPathVar} "") - foreach (_includeDir ${_includeDirs}) - if (IS_DIRECTORY "${_includeDir}") - file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}") - if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.") - string (LENGTH "${${_relPathVar}}" _closestLen) - string (LENGTH "${_relPath}" _relLen) - if (_closestLen EQUAL 0 OR _relLen LESS _closestLen) - set (${_relPathVar} "${_relPath}") - endif() - endif() - elseif ("${_includeDir}" STREQUAL "${_headerFile}") - # if path matches exactly, return short non-empty string - set (${_relPathVar} "1") - break() - endif() - endforeach() -endmacro() - -macro (cotire_check_header_file_location _headerFile _insideIncludeDirs _outsideIncludeDirs _headerIsInside) - # check header path against ignored and honored include directories - cotire_find_closest_relative_path("${_headerFile}" "${_insideIncludeDirs}" _insideRelPath) - if (_insideRelPath) - # header is inside, but could be become outside if there is a shorter outside match - cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncludeDirs}" _outsideRelPath) - if (_outsideRelPath) - string (LENGTH "${_insideRelPath}" _insideRelPathLen) - string (LENGTH "${_outsideRelPath}" _outsideRelPathLen) - if (_outsideRelPathLen LESS _insideRelPathLen) - set (${_headerIsInside} FALSE) - else() - set (${_headerIsInside} TRUE) - endif() - else() - set (${_headerIsInside} TRUE) - endif() - else() - # header is outside - set (${_headerIsInside} FALSE) - endif() -endmacro() - -macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar) - if (NOT EXISTS "${_headerFile}") - set (${_headerIsIgnoredVar} TRUE) - elseif (IS_DIRECTORY "${_headerFile}") - set (${_headerIsIgnoredVar} TRUE) - elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$") - # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path - # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation - # with the error message "error: no include path in which to search for header.h" - set (${_headerIsIgnoredVar} TRUE) - else() - set (${_headerIsIgnoredVar} FALSE) - endif() -endmacro() - -macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar) - # check header file extension - cotire_get_source_file_extension("${_headerFile}" _headerFileExt) - set (${_headerIsIgnoredVar} FALSE) - if (_headerFileExt) - list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index) - if (_index GREATER -1) - set (${_headerIsIgnoredVar} TRUE) - endif() - endif() -endmacro() - -macro (cotire_parse_line _line _headerFileVar _headerDepthVar) - if (MSVC) - # cl.exe /showIncludes output looks different depending on the language pack used, e.g.: - # English: "Note: including file: C:\directory\file" - # German: "Hinweis: Einlesen der Datei: C:\directory\file" - # We use a very general regular expression, relying on the presence of the : characters - if (_line MATCHES "( +)([a-zA-Z]:[^:]+)$") - # Visual Studio compiler output - string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) - get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE) - else() - set (${_headerFileVar} "") - set (${_headerDepthVar} 0) - endif() - else() - if (_line MATCHES "^(\\.+) (.*)$") - # GCC like output - string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) - if (IS_ABSOLUTE "${CMAKE_MATCH_2}") - set (${_headerFileVar} "${CMAKE_MATCH_2}") - else() - get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH) - endif() - else() - set (${_headerFileVar} "") - set (${_headerDepthVar} 0) - endif() - endif() -endmacro() - -function (cotire_parse_includes _language _scanOutput _ignoredIncludeDirs _honoredIncludeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar) - if (WIN32) - # prevent CMake macro invocation errors due to backslash characters in Windows paths - string (REPLACE "\\" "/" _scanOutput "${_scanOutput}") - endif() - # canonize slashes - string (REPLACE "//" "/" _scanOutput "${_scanOutput}") - # prevent semicolon from being interpreted as a line separator - string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}") - # then separate lines - string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}") - list (LENGTH _scanOutput _len) - # remove duplicate lines to speed up parsing - list (REMOVE_DUPLICATES _scanOutput) - list (LENGTH _scanOutput _uniqueLen) - if (COTIRE_VERBOSE OR COTIRE_DEBUG) - message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes") - if (_ignoredExtensions) - message (STATUS "Ignored extensions: ${_ignoredExtensions}") - endif() - if (_ignoredIncludeDirs) - message (STATUS "Ignored paths: ${_ignoredIncludeDirs}") - endif() - if (_honoredIncludeDirs) - message (STATUS "Included paths: ${_honoredIncludeDirs}") - endif() - endif() - set (_sourceFiles ${ARGN}) - set (_selectedIncludes "") - set (_unparsedLines "") - # stack keeps track of inside/outside project status of processed header files - set (_headerIsInsideStack "") - foreach (_line IN LISTS _scanOutput) - if (_line) - cotire_parse_line("${_line}" _headerFile _headerDepth) - if (_headerFile) - cotire_check_header_file_location("${_headerFile}" "${_ignoredIncludeDirs}" "${_honoredIncludeDirs}" _headerIsInside) - if (COTIRE_DEBUG) - message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}") - endif() - # update stack - list (LENGTH _headerIsInsideStack _stackLen) - if (_headerDepth GREATER _stackLen) - math (EXPR _stackLen "${_stackLen} + 1") - foreach (_index RANGE ${_stackLen} ${_headerDepth}) - list (APPEND _headerIsInsideStack ${_headerIsInside}) - endforeach() - else() - foreach (_index RANGE ${_headerDepth} ${_stackLen}) - list (REMOVE_AT _headerIsInsideStack -1) - endforeach() - list (APPEND _headerIsInsideStack ${_headerIsInside}) - endif() - if (COTIRE_DEBUG) - message (STATUS "${_headerIsInsideStack}") - endif() - # header is a candidate if it is outside project - if (NOT _headerIsInside) - # get parent header file's inside/outside status - if (_headerDepth GREATER 1) - math (EXPR _index "${_headerDepth} - 2") - list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside) - else() - set (_parentHeaderIsInside TRUE) - endif() - # select header file if parent header file is inside project - # (e.g., a project header file that includes a standard header file) - if (_parentHeaderIsInside) - cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored) - if (NOT _headerIsIgnored) - cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored) - if (NOT _headerIsIgnored) - list (APPEND _selectedIncludes "${_headerFile}") - else() - # fix header's inside status on stack, it is ignored by extension now - list (REMOVE_AT _headerIsInsideStack -1) - list (APPEND _headerIsInsideStack TRUE) - endif() - endif() - if (COTIRE_DEBUG) - message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}") - endif() - endif() - endif() - else() - if (MSVC) - # for cl.exe do not keep unparsed lines which solely consist of a source file name - string (FIND "${_sourceFiles}" "${_line}" _index) - if (_index LESS 0) - list (APPEND _unparsedLines "${_line}") - endif() - else() - list (APPEND _unparsedLines "${_line}") - endif() - endif() - endif() - endforeach() - list (REMOVE_DUPLICATES _selectedIncludes) - set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE) - set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE) -endfunction() - -function (cotire_scan_includes _includesVar) - set(_options "") - set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_VERSION LANGUAGE UNPARSED_LINES SCAN_RESULT) - set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES - IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - if (NOT _option_LANGUAGE) - set (_option_LANGUAGE "CXX") - endif() - if (NOT _option_COMPILER_ID) - set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") - endif() - if (NOT _option_COMPILER_VERSION) - set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") - endif() - cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") - cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) - cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) - cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd) - # only consider existing source files for scanning - set (_existingSourceFiles "") - foreach (_sourceFile ${_sourceFiles}) - if (EXISTS "${_sourceFile}") - list (APPEND _existingSourceFiles "${_sourceFile}") - endif() - endforeach() - if (NOT _existingSourceFiles) - set (${_includesVar} "" PARENT_SCOPE) - return() - endif() - list (APPEND _cmd ${_existingSourceFiles}) - if (COTIRE_VERBOSE) - message (STATUS "execute_process: ${_cmd}") - endif() - if (_option_COMPILER_ID MATCHES "MSVC") - # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared - unset (ENV{VS_UNICODE_OUTPUT}) - endif() - execute_process( - COMMAND ${_cmd} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE _result - OUTPUT_QUIET - ERROR_VARIABLE _output) - if (_result) - message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.") - endif() - cotire_parse_includes( - "${_option_LANGUAGE}" "${_output}" - "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}" - "${_option_IGNORE_EXTENSIONS}" - _includes _unparsedLines - ${_sourceFiles}) - if (_option_INCLUDE_PRIORITY_PATH) - set (_sortedIncludes "") - foreach (_priorityPath ${_option_INCLUDE_PRIORITY_PATH}) - foreach (_include ${_includes}) - string (FIND ${_include} ${_priorityPath} _position) - if (_position GREATER -1) - list (APPEND _sortedIncludes ${_include}) - endif() - endforeach() - endforeach() - if (_sortedIncludes) - list (INSERT _includes 0 ${_sortedIncludes}) - list (REMOVE_DUPLICATES _includes) - endif() - endif() - set (${_includesVar} ${_includes} PARENT_SCOPE) - if (_option_UNPARSED_LINES) - set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE) - endif() - if (_option_SCAN_RESULT) - set (${_option_SCAN_RESULT} ${_result} PARENT_SCOPE) - endif() -endfunction() - -macro (cotire_append_undefs _contentsVar) - set (_undefs ${ARGN}) - if (_undefs) - list (REMOVE_DUPLICATES _undefs) - foreach (_definition ${_undefs}) - list (APPEND ${_contentsVar} "#undef ${_definition}") - endforeach() - endif() -endmacro() - -macro (cotire_comment_str _language _commentText _commentVar) - if ("${_language}" STREQUAL "CMAKE") - set (${_commentVar} "# ${_commentText}") - else() - set (${_commentVar} "/* ${_commentText} */") - endif() -endmacro() - -function (cotire_write_file _language _file _contents _force) - get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) - cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1) - cotire_comment_str("${_language}" "${_file}" _header2) - set (_contents "${_header1}\n${_header2}\n${_contents}") - if (COTIRE_DEBUG) - message (STATUS "${_contents}") - endif() - if (_force OR NOT EXISTS "${_file}") - file (WRITE "${_file}" "${_contents}") - else() - file (READ "${_file}" _oldContents) - if (NOT "${_oldContents}" STREQUAL "${_contents}") - file (WRITE "${_file}" "${_contents}") - else() - if (COTIRE_DEBUG) - message (STATUS "${_file} unchanged") - endif() - endif() - endif() -endfunction() - -function (cotire_generate_unity_source _unityFile) - set(_options "") - set(_oneValueArgs LANGUAGE) - set(_multiValueArgs - DEPENDS SOURCES_COMPILE_DEFINITIONS - PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (_option_DEPENDS) - cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS}) - if (_unityFileIsUpToDate) - return() - endif() - endif() - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - if (NOT _option_PRE_UNDEFS) - set (_option_PRE_UNDEFS "") - endif() - if (NOT _option_SOURCES_PRE_UNDEFS) - set (_option_SOURCES_PRE_UNDEFS "") - endif() - if (NOT _option_POST_UNDEFS) - set (_option_POST_UNDEFS "") - endif() - if (NOT _option_SOURCES_POST_UNDEFS) - set (_option_SOURCES_POST_UNDEFS "") - endif() - set (_contents "") - if (_option_PROLOGUE) - list (APPEND _contents ${_option_PROLOGUE}) - endif() - if (_option_LANGUAGE AND _sourceFiles) - if ("${_option_LANGUAGE}" STREQUAL "CXX") - list (APPEND _contents "#ifdef __cplusplus") - elseif ("${_option_LANGUAGE}" STREQUAL "C") - list (APPEND _contents "#ifndef __cplusplus") - endif() - endif() - set (_compileUndefinitions "") - foreach (_sourceFile ${_sourceFiles}) - cotire_get_source_compile_definitions( - "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions - ${_option_SOURCES_COMPILE_DEFINITIONS}) - cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS}) - cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS}) - if (_option_PRE_UNDEFS) - list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS}) - endif() - if (_sourcePreUndefs) - list (APPEND _compileUndefinitions ${_sourcePreUndefs}) - endif() - if (_compileUndefinitions) - cotire_append_undefs(_contents ${_compileUndefinitions}) - set (_compileUndefinitions "") - endif() - if (_sourcePostUndefs) - list (APPEND _compileUndefinitions ${_sourcePostUndefs}) - endif() - if (_option_POST_UNDEFS) - list (APPEND _compileUndefinitions ${_option_POST_UNDEFS}) - endif() - foreach (_definition ${_compileDefinitions}) - if (_definition MATCHES "^([a-zA-Z0-9_]+)=(.+)$") - list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}") - list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}") - else() - list (APPEND _contents "#define ${_definition}") - list (INSERT _compileUndefinitions 0 "${_definition}") - endif() - endforeach() - # use absolute path as source file location - get_filename_component(_sourceFileLocation "${_sourceFile}" ABSOLUTE) - if (WIN32) - file (TO_NATIVE_PATH "${_sourceFileLocation}" _sourceFileLocation) - endif() - list (APPEND _contents "#include \"${_sourceFileLocation}\"") - endforeach() - if (_compileUndefinitions) - cotire_append_undefs(_contents ${_compileUndefinitions}) - set (_compileUndefinitions "") - endif() - if (_option_LANGUAGE AND _sourceFiles) - list (APPEND _contents "#endif") - endif() - if (_option_EPILOGUE) - list (APPEND _contents ${_option_EPILOGUE}) - endif() - list (APPEND _contents "") - string (REPLACE ";" "\n" _contents "${_contents}") - if (COTIRE_VERBOSE) - message ("${_contents}") - endif() - cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE) -endfunction() - -function (cotire_generate_prefix_header _prefixFile) - set(_options "") - set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION) - set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS - INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH - IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (NOT _option_COMPILER_ID) - set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") - endif() - if (NOT _option_COMPILER_VERSION) - set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") - endif() - if (_option_DEPENDS) - cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS}) - if (_prefixFileIsUpToDate) - # create empty log file - set (_unparsedLinesFile "${_prefixFile}.log") - file (WRITE "${_unparsedLinesFile}" "") - return() - endif() - endif() - set (_prologue "") - set (_epilogue "") - if (_option_COMPILER_ID MATCHES "Clang") - set (_prologue "#pragma clang system_header") - elseif (_option_COMPILER_ID MATCHES "GNU") - set (_prologue "#pragma GCC system_header") - elseif (_option_COMPILER_ID MATCHES "MSVC") - set (_prologue "#pragma warning(push, 0)") - set (_epilogue "#pragma warning(pop)") - elseif (_option_COMPILER_ID MATCHES "Intel") - # Intel compiler requires hdrstop pragma to stop generating PCH file - set (_epilogue "#pragma hdrstop") - endif() - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - cotire_scan_includes(_selectedHeaders ${_sourceFiles} - LANGUAGE "${_option_LANGUAGE}" - COMPILER_LAUNCHER "${_option_COMPILER_LAUNCHER}" - COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}" - COMPILER_ARG1 "${_option_COMPILER_ARG1}" - COMPILER_ID "${_option_COMPILER_ID}" - COMPILER_VERSION "${_option_COMPILER_VERSION}" - COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS} - COMPILE_FLAGS ${_option_COMPILE_FLAGS} - INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES} - SYSTEM_INCLUDE_DIRECTORIES ${_option_SYSTEM_INCLUDE_DIRECTORIES} - IGNORE_PATH ${_option_IGNORE_PATH} - INCLUDE_PATH ${_option_INCLUDE_PATH} - IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS} - INCLUDE_PRIORITY_PATH ${_option_INCLUDE_PRIORITY_PATH} - UNPARSED_LINES _unparsedLines - SCAN_RESULT _scanResult) - cotire_generate_unity_source("${_prefixFile}" - PROLOGUE ${_prologue} EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders}) - set (_unparsedLinesFile "${_prefixFile}.log") - if (_unparsedLines) - if (COTIRE_VERBOSE OR _scanResult OR NOT _selectedHeaders) - list (LENGTH _unparsedLines _skippedLineCount) - message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFile}") - endif() - string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}") - endif() - file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}") -endfunction() - -function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - # cl.exe options used - # /nologo suppresses display of sign-on banner - # /TC treat all files named on the command line as C source files - # /TP treat all files named on the command line as C++ source files - # /EP preprocess to stdout without #line directives - # /showIncludes list include files - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes) - else() - # return as a flag string - set (_flags "${_sourceFileType${_language}} /EP /showIncludes") - endif() - elseif (_compilerID MATCHES "GNU") - # GCC options used - # -H print the name of each header file used - # -E invoke preprocessor - # -fdirectives-only do not expand macros, requires GCC >= 4.3 - if (_flags) - # append to list - list (APPEND _flags -H -E) - if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") - list (APPEND _flags "-fdirectives-only") - endif() - else() - # return as a flag string - set (_flags "-H -E") - if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") - set (_flags "${_flags} -fdirectives-only") - endif() - endif() - elseif (_compilerID MATCHES "Clang") - # Clang options used - # -H print the name of each header file used - # -E invoke preprocessor - # -fno-color-diagnostics don't prints diagnostics in color - if (_flags) - # append to list - list (APPEND _flags -H -E -fno-color-diagnostics) - else() - # return as a flag string - set (_flags "-H -E -fno-color-diagnostics") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - # Windows Intel options used - # /nologo do not display compiler version information - # /QH display the include file order - # /EP preprocess to stdout, omitting #line directives - # /TC process all source or unrecognized file types as C source files - # /TP process all source or unrecognized file types as C++ source files - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH) - else() - # return as a flag string - set (_flags "${_sourceFileType${_language}} /EP /QH") - endif() - else() - # Linux / Mac OS X Intel options used - # -H print the name of each header file used - # -EP preprocess to stdout, omitting #line directives - # -Kc++ process all source or unrecognized file types as C++ source files - if (_flags) - # append to list - if ("${_language}" STREQUAL "CXX") - list (APPEND _flags -Kc++) - endif() - list (APPEND _flags -H -EP) - else() - # return as a flag string - if ("${_language}" STREQUAL "CXX") - set (_flags "-Kc++ ") - endif() - set (_flags "${_flags}-H -EP") - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) - # cl.exe options used - # /Yc creates a precompiled header file - # /Fp specifies precompiled header binary file name - # /FI forces inclusion of file - # /TC treat all files named on the command line as C source files - # /TP treat all files named on the command line as C++ source files - # /Zs syntax check only - # /Zm precompiled header memory allocation scaling factor - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" - "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") - if (COTIRE_PCH_MEMORY_SCALING_FACTOR) - list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") - endif() - else() - # return as a flag string - set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (COTIRE_PCH_MEMORY_SCALING_FACTOR) - set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") - endif() - endif() - elseif (_compilerID MATCHES "GNU|Clang") - # GCC / Clang options used - # -x specify the source language - # -c compile but do not link - # -o place output in file - # note that we cannot use -w to suppress all warnings upon pre-compiling, because turning off a warning may - # alter compile flags as a side effect (e.g., -Wwrite-string implies -fconst-strings) - set (_xLanguage_C "c-header") - set (_xLanguage_CXX "c++-header") - if (_flags) - # append to list - list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}") - else() - # return as a flag string - set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) - # Windows Intel options used - # /nologo do not display compiler version information - # /Yc create a precompiled header (PCH) file - # /Fp specify a path or file name for precompiled header files - # /FI tells the preprocessor to include a specified file name as the header file - # /TC process all source or unrecognized file types as C source files - # /TP process all source or unrecognized file types as C++ source files - # /Zs syntax check only - # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" - "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "/Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} /Wpch-messages") - endif() - endif() - else() - # Linux / Mac OS X Intel options used - # -pch-dir location for precompiled header files - # -pch-create name of the precompiled header (PCH) to create - # -Kc++ process all source or unrecognized file types as C++ source files - # -fsyntax-only check only for correct syntax - # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - get_filename_component(_pchDir "${_pchFile}" DIRECTORY) - get_filename_component(_pchName "${_pchFile}" NAME) - set (_xLanguage_C "c-header") - set (_xLanguage_CXX "c++-header") - if (_flags) - # append to list - if ("${_language}" STREQUAL "CXX") - list (APPEND _flags -Kc++) - endif() - list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "-Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} -Wpch-messages") - endif() - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - # cl.exe options used - # /Yu uses a precompiled header file during build - # /Fp specifies precompiled header binary file name - # /FI forces inclusion of file - # /Zm precompiled header memory allocation scaling factor - if (_pchFile) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - if (_flags) - # append to list - list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") - if (COTIRE_PCH_MEMORY_SCALING_FACTOR) - list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") - endif() - else() - # return as a flag string - set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (COTIRE_PCH_MEMORY_SCALING_FACTOR) - set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") - endif() - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "/FI${_prefixFileNative}") - else() - # return as a flag string - set (_flags "/FI\"${_prefixFileNative}\"") - endif() - endif() - elseif (_compilerID MATCHES "GNU") - # GCC options used - # -include process include file as the first line of the primary source file - # -Winvalid-pch warns if precompiled header is found but cannot be used - # note: ccache requires the -include flag to be used in order to process precompiled header correctly - if (_flags) - # append to list - list (APPEND _flags "-Winvalid-pch" "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-Winvalid-pch -include \"${_prefixFile}\"") - endif() - elseif (_compilerID MATCHES "Clang") - # Clang options used - # -include process include file as the first line of the primary source file - # -include-pch include precompiled header file - # -Qunused-arguments don't emit warning for unused driver arguments - # note: ccache requires the -include flag to be used in order to process precompiled header correctly - if (_flags) - # append to list - list (APPEND _flags "-Qunused-arguments" "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-Qunused-arguments -include \"${_prefixFile}\"") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - # Windows Intel options used - # /Yu use a precompiled header (PCH) file - # /Fp specify a path or file name for precompiled header files - # /FI tells the preprocessor to include a specified file name as the header file - # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - if (_pchFile) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - if (_flags) - # append to list - list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "/Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} /Wpch-messages") - endif() - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "/FI${_prefixFileNative}") - else() - # return as a flag string - set (_flags "/FI\"${_prefixFileNative}\"") - endif() - endif() - else() - # Linux / Mac OS X Intel options used - # -pch-dir location for precompiled header files - # -pch-use name of the precompiled header (PCH) to use - # -include process include file as the first line of the primary source file - # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - if (_pchFile) - get_filename_component(_pchDir "${_pchFile}" DIRECTORY) - get_filename_component(_pchName "${_pchFile}" NAME) - if (_flags) - # append to list - list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "-Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} -Wpch-messages") - endif() - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\"") - endif() - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile) - set(_options "") - set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION LANGUAGE) - set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES SYS COMPILER_LAUNCHER) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (NOT _option_LANGUAGE) - set (_option_LANGUAGE "CXX") - endif() - if (NOT _option_COMPILER_ID) - set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") - endif() - if (NOT _option_COMPILER_VERSION) - set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") - endif() - cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") - cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) - cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) - cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_pch_compilation_flags( - "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd) - if (COTIRE_VERBOSE) - message (STATUS "execute_process: ${_cmd}") - endif() - if (_option_COMPILER_ID MATCHES "MSVC") - # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared - unset (ENV{VS_UNICODE_OUTPUT}) - endif() - execute_process( - COMMAND ${_cmd} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE _result) - if (_result) - message (FATAL_ERROR "cotire: error ${_result} precompiling ${_prefixFile}.") - endif() -endfunction() - -function (cotire_check_precompiled_header_support _language _target _msgVar) - set (_unsupportedCompiler - "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}") - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") - # supported since Visual Studio C++ 6.0 - # and CMake does not support an earlier version - set (${_msgVar} "" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") - # GCC PCH support requires version >= 3.4 - if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0") - set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) - else() - set (${_msgVar} "" PARENT_SCOPE) - endif() - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") - # all Clang versions have PCH support - set (${_msgVar} "" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") - # Intel PCH support requires version >= 8.0.0 - if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0") - set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) - else() - set (${_msgVar} "" PARENT_SCOPE) - endif() - else() - set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE) - endif() - get_target_property(_launcher ${_target} ${_language}_COMPILER_LAUNCHER) - if (CMAKE_${_language}_COMPILER MATCHES "ccache" OR _launcher MATCHES "ccache") - if (DEFINED ENV{CCACHE_SLOPPINESS}) - if (NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "pch_defines" OR NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "time_macros") - set (${_msgVar} - "ccache requires the environment variable CCACHE_SLOPPINESS to be set to \"pch_defines,time_macros\"." - PARENT_SCOPE) - endif() - else() - if (_launcher MATCHES "ccache") - get_filename_component(_ccacheExe "${_launcher}" REALPATH) - else() - get_filename_component(_ccacheExe "${CMAKE_${_language}_COMPILER}" REALPATH) - endif() - execute_process( - COMMAND "${_ccacheExe}" "--print-config" - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - RESULT_VARIABLE _result - OUTPUT_VARIABLE _ccacheConfig OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET) - if (_result OR NOT - _ccacheConfig MATCHES "sloppiness.*=.*time_macros" OR NOT - _ccacheConfig MATCHES "sloppiness.*=.*pch_defines") - set (${_msgVar} - "ccache requires configuration setting \"sloppiness\" to be set to \"pch_defines,time_macros\"." - PARENT_SCOPE) - endif() - endif() - endif() - if (APPLE) - # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64) - cotire_get_configuration_types(_configs) - foreach (_config ${_configs}) - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) - cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags}) - list (LENGTH _architectures _numberOfArchitectures) - if (_numberOfArchitectures GREATER 1) - string (REPLACE ";" ", " _architectureStr "${_architectures}") - set (${_msgVar} - "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})." - PARENT_SCOPE) - break() - endif() - endforeach() - endif() -endfunction() - -macro (cotire_get_intermediate_dir _cotireDir) - # ${CMAKE_CFG_INTDIR} may reference a build-time variable when using a generator which supports configuration types - get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE) -endmacro() - -macro (cotire_setup_file_extension_variables) - set (_unityFileExt_C ".c") - set (_unityFileExt_CXX ".cxx") - set (_prefixFileExt_C ".h") - set (_prefixFileExt_CXX ".hxx") - set (_prefixSourceFileExt_C ".c") - set (_prefixSourceFileExt_CXX ".cxx") -endmacro() - -function (cotire_make_single_unity_source_file_path _language _target _unityFileVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _unityFileExt_${_language}) - set (${_unityFileVar} "" PARENT_SCOPE) - return() - endif() - set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") - set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}") - cotire_get_intermediate_dir(_baseDir) - set (_unityFile "${_baseDir}/${_unityFileName}") - set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE) -endfunction() - -function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _unityFileExt_${_language}) - set (${_unityFileVar} "" PARENT_SCOPE) - return() - endif() - set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") - cotire_get_intermediate_dir(_baseDir) - set (_startIndex 0) - set (_index 0) - set (_unityFiles "") - set (_sourceFiles ${ARGN}) - foreach (_sourceFile ${_sourceFiles}) - get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE) - math (EXPR _unityFileCount "${_index} - ${_startIndex}") - if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes)) - if (_index GREATER 0) - # start new unity file segment - math (EXPR _endIndex "${_index} - 1") - set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") - list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") - endif() - set (_startIndex ${_index}) - endif() - math (EXPR _index "${_index} + 1") - endforeach() - list (LENGTH _sourceFiles _numberOfSources) - if (_startIndex EQUAL 0) - # there is only a single unity file - cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles) - elseif (_startIndex LESS _numberOfSources) - # end with final unity file segment - math (EXPR _endIndex "${_index} - 1") - set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") - list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") - endif() - set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE) - if (COTIRE_DEBUG AND _unityFiles) - message (STATUS "unity files: ${_unityFiles}") - endif() -endfunction() - -function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _unityFileExt_${_language}) - set (${_prefixFileVar} "" PARENT_SCOPE) - return() - endif() - set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") - set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") - string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}") - string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}") - set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE) -endfunction() - -function (cotire_prefix_header_to_source_file_path _language _prefixHeaderFile _prefixSourceFileVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _prefixSourceFileExt_${_language}) - set (${_prefixSourceFileVar} "" PARENT_SCOPE) - return() - endif() - string (REGEX REPLACE "${_prefixFileExt_${_language}}$" "${_prefixSourceFileExt_${_language}}" _prefixSourceFile "${_prefixHeaderFile}") - set (${_prefixSourceFileVar} "${_prefixSourceFile}" PARENT_SCOPE) -endfunction() - -function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar) - cotire_setup_file_extension_variables() - if (NOT _language) - set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") - set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}") - elseif (DEFINED _prefixFileExt_${_language}) - set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") - set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}") - else() - set (_prefixFileBaseName "") - set (_prefixFileName "") - endif() - set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE) - set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE) -endfunction() - -function (cotire_make_prefix_file_path _language _target _prefixFileVar) - cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) - set (${_prefixFileVar} "" PARENT_SCOPE) - if (_prefixFileName) - if (NOT _language) - set (_language "C") - endif() - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel|MSVC") - cotire_get_intermediate_dir(_baseDir) - set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE) - endif() - endif() -endfunction() - -function (cotire_make_pch_file_path _language _target _pchFileVar) - cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) - set (${_pchFileVar} "" PARENT_SCOPE) - if (_prefixFileBaseName AND _prefixFileName) - cotire_check_precompiled_header_support("${_language}" "${_target}" _msg) - if (NOT _msg) - if (XCODE) - # For Xcode, we completely hand off the compilation of the prefix header to the IDE - return() - endif() - cotire_get_intermediate_dir(_baseDir) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") - # MSVC uses the extension .pch added to the prefix header base name - set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") - # Clang looks for a precompiled header corresponding to the prefix header with the extension .pch appended - set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.pch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") - # GCC looks for a precompiled header corresponding to the prefix header with the extension .gch appended - set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") - # Intel uses the extension .pchi added to the prefix header base name - set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE) - endif() - endif() - endif() -endfunction() - -function (cotire_select_unity_source_files _unityFile _sourcesVar) - set (_sourceFiles ${ARGN}) - if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)") - set (_startIndex ${CMAKE_MATCH_1}) - set (_endIndex ${CMAKE_MATCH_2}) - list (LENGTH _sourceFiles _numberOfSources) - if (NOT _startIndex LESS _numberOfSources) - math (EXPR _startIndex "${_numberOfSources} - 1") - endif() - if (NOT _endIndex LESS _numberOfSources) - math (EXPR _endIndex "${_numberOfSources} - 1") - endif() - set (_files "") - foreach (_index RANGE ${_startIndex} ${_endIndex}) - list (GET _sourceFiles ${_index} _file) - list (APPEND _files "${_file}") - endforeach() - else() - set (_files ${_sourceFiles}) - endif() - set (${_sourcesVar} ${_files} PARENT_SCOPE) -endfunction() - -function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar) - set (_dependencySources "") - # depend on target's generated source files - get_target_property(_targetSourceFiles ${_target} SOURCES) - cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles}) - if (_generatedSources) - # but omit all generated source files that have the COTIRE_EXCLUDED property set to true - cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources}) - if (_excludedGeneratedSources) - list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources}) - endif() - # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly - cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources}) - if (_excludedNonDependencySources) - list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources}) - endif() - if (_generatedSources) - list (APPEND _dependencySources ${_generatedSources}) - endif() - endif() - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_language} ${_target} unity source dependencies: ${_dependencySources}") - endif() - set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) -endfunction() - -function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar) - set (_dependencySources "") - # depend on target source files marked with custom COTIRE_DEPENDENCY property - get_target_property(_targetSourceFiles ${_target} SOURCES) - cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${_targetSourceFiles}) - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_language} ${_target} prefix header dependencies: ${_dependencySources}") - endif() - set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) -endfunction() - -function (cotire_generate_target_script _language _configurations _target _targetScriptVar _targetConfigScriptVar) - set (_targetSources ${ARGN}) - cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${_targetSources}) - cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${_targetSources}) - # set up variables to be configured - set (COTIRE_TARGET_LANGUAGE "${_language}") - get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH) - cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH) - get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH) - cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH) - get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS) - get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS) - get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) - get_target_property(COTIRE_TARGET_INCLUDE_PRIORITY_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH) - cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${_targetSources}) - cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${_targetSources}) - set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}") - foreach (_config ${_configurations}) - string (TOUPPER "${_config}" _upperConfig) - cotire_get_target_include_directories( - "${_config}" "${_language}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig} COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}) - cotire_get_target_compile_definitions( - "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}) - cotire_get_target_compiler_flags( - "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}) - cotire_get_source_files_compile_definitions( - "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${_targetSources}) - endforeach() - get_target_property(COTIRE_TARGET_${_language}_COMPILER_LAUNCHER ${_target} ${_language}_COMPILER_LAUNCHER) - # set up COTIRE_TARGET_SOURCES - set (COTIRE_TARGET_SOURCES "") - foreach (_sourceFile ${_targetSources}) - get_source_file_property(_generated "${_sourceFile}" GENERATED) - if (_generated) - # use absolute paths for generated files only, retrieving the LOCATION property is an expensive operation - get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION) - list (APPEND COTIRE_TARGET_SOURCES "${_sourceLocation}") - else() - list (APPEND COTIRE_TARGET_SOURCES "${_sourceFile}") - endif() - endforeach() - # copy variable definitions to cotire target script - get_cmake_property(_vars VARIABLES) - string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}") - # omit COTIRE_*_INIT variables - string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+_INIT" _initVars "${_matchVars}") - if (_initVars) - list (REMOVE_ITEM _matchVars ${_initVars}) - endif() - # omit COTIRE_VERBOSE which is passed as a CMake define on command line - list (REMOVE_ITEM _matchVars COTIRE_VERBOSE) - set (_contents "") - set (_contentsHasGeneratorExpressions FALSE) - foreach (_var IN LISTS _matchVars ITEMS - XCODE MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES - CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER_VERSION - CMAKE_${_language}_COMPILER_LAUNCHER CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1 - CMAKE_INCLUDE_FLAG_${_language} CMAKE_INCLUDE_FLAG_${_language}_SEP - CMAKE_INCLUDE_SYSTEM_FLAG_${_language} - CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG - CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG - CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) - if (DEFINED ${_var}) - string (REPLACE "\"" "\\\"" _value "${${_var}}") - set (_contents "${_contents}set (${_var} \"${_value}\")\n") - if (NOT _contentsHasGeneratorExpressions) - if ("${_value}" MATCHES "\\$<.*>") - set (_contentsHasGeneratorExpressions TRUE) - endif() - endif() - endif() - endforeach() - # generate target script file - get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) - set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}") - cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE) - if (_contentsHasGeneratorExpressions) - # use file(GENERATE ...) to expand generator expressions in the target script at CMake generate-time - set (_configNameOrNoneGeneratorExpression "$<$:None>$<$>:$>") - set (_targetCotireConfigScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_configNameOrNoneGeneratorExpression}_${_moduleName}") - file (GENERATE OUTPUT "${_targetCotireConfigScript}" INPUT "${_targetCotireScript}") - else() - set (_targetCotireConfigScript "${_targetCotireScript}") - endif() - set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE) - set (${_targetConfigScriptVar} "${_targetCotireConfigScript}" PARENT_SCOPE) -endfunction() - -function (cotire_setup_pch_file_compilation _language _target _targetScript _prefixFile _pchFile _hostFile) - set (_sourceFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # for Visual Studio and Intel, we attach the precompiled header compilation to the host file - # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion - if (_sourceFiles) - set (_flags "") - cotire_add_pch_compilation_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags) - set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}") - # make object file generated from host file depend on prefix header - set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") - # mark host file as cotired to prevent it from being used in another cotired target - set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}") - endif() - elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - # for makefile based generator, we add a custom command to precompile the prefix header - if (_targetScript) - cotire_set_cmd_to_prologue(_cmds) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}") - if (MSVC_IDE) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileLogPath) - else() - file (RELATIVE_PATH _pchFileLogPath "${CMAKE_BINARY_DIR}" "${_pchFile}") - endif() - # make precompiled header compilation depend on the actual compiler executable used to force - # re-compilation when the compiler executable is updated. This prevents "created by a different GCC executable" - # warnings when the precompiled header is included. - get_filename_component(_realCompilerExe "${CMAKE_${_language}_COMPILER}" ABSOLUTE) - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} ${_realCompilerExe} IMPLICIT_DEPENDS ${_language} ${_prefixFile}") - endif() - set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE) - add_custom_command( - OUTPUT "${_pchFile}" - COMMAND ${_cmds} - DEPENDS "${_prefixFile}" "${_realCompilerExe}" - IMPLICIT_DEPENDS ${_language} "${_prefixFile}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMENT "Building ${_language} precompiled header ${_pchFileLogPath}" - VERBATIM) - endif() - endif() -endfunction() - -function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile _hostFile) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # for Visual Studio and Intel, we include the precompiled header in all but the host file - # the host file does the precompiled header compilation, see cotire_setup_pch_file_compilation - set (_sourceFiles ${ARGN}) - list (LENGTH _sourceFiles _numberOfSourceFiles) - if (_numberOfSourceFiles GREATER 0) - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - set (_flags "") - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # make object files generated from source files depend on precompiled header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") - endif() - elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - set (_sourceFiles ${_hostFile} ${ARGN}) - if (NOT _wholeTarget) - # for makefile based generator, we force the inclusion of the prefix header for a subset - # of the source files, if this is a multi-language target or has excluded files - set (_flags "") - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - endif() - # make object files generated from source files depend on precompiled header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") - endif() -endfunction() - -function (cotire_setup_prefix_file_inclusion _language _target _prefixFile) - set (_sourceFiles ${ARGN}) - # force the inclusion of the prefix header for the given source files - set (_flags "") - set (_pchFile "") - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - # make object files generated from source files depend on prefix header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") -endfunction() - -function (cotire_get_first_set_property_value _propertyValueVar _type _object) - set (_properties ${ARGN}) - foreach (_property ${_properties}) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (_propertyValue) - set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE) - return() - endif() - endforeach() - set (${_propertyValueVar} "" PARENT_SCOPE) -endfunction() - -function (cotire_setup_combine_command _language _targetScript _joinedFile _cmdsVar) - set (_files ${ARGN}) - set (_filesPaths "") - foreach (_file ${_files}) - get_filename_component(_filePath "${_file}" ABSOLUTE) - list (APPEND _filesPaths "${_filePath}") - endforeach() - cotire_set_cmd_to_prologue(_prefixCmd) - list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine") - if (_targetScript) - list (APPEND _prefixCmd "${_targetScript}") - endif() - list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths}) - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}") - endif() - set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE) - if (MSVC_IDE) - file (TO_NATIVE_PATH "${_joinedFile}" _joinedFileLogPath) - else() - file (RELATIVE_PATH _joinedFileLogPath "${CMAKE_BINARY_DIR}" "${_joinedFile}") - endif() - get_filename_component(_joinedFileBaseName "${_joinedFile}" NAME_WE) - get_filename_component(_joinedFileExt "${_joinedFile}" EXT) - if (_language AND _joinedFileBaseName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$") - set (_comment "Generating ${_language} unity source ${_joinedFileLogPath}") - elseif (_language AND _joinedFileBaseName MATCHES "${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}$") - if (_joinedFileExt MATCHES "^\\.c") - set (_comment "Generating ${_language} prefix source ${_joinedFileLogPath}") - else() - set (_comment "Generating ${_language} prefix header ${_joinedFileLogPath}") - endif() - else() - set (_comment "Generating ${_joinedFileLogPath}") - endif() - add_custom_command( - OUTPUT "${_joinedFile}" - COMMAND ${_prefixCmd} - DEPENDS ${_files} - COMMENT "${_comment}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_target_pch_usage _languages _target _wholeTarget) - if (XCODE) - # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers - set (_prefixFiles "") - foreach (_language ${_languages}) - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - if (_prefixFile) - list (APPEND _prefixFiles "${_prefixFile}") - endif() - endforeach() - set (_cmds ${ARGN}) - list (LENGTH _prefixFiles _numberOfPrefixFiles) - if (_numberOfPrefixFiles GREATER 1) - # we also generate a generic, single prefix header which includes all language specific prefix headers - set (_language "") - set (_targetScript "") - cotire_make_prefix_file_path("${_language}" ${_target} _prefixHeader) - cotire_setup_combine_command("${_language}" "${_targetScript}" "${_prefixHeader}" _cmds ${_prefixFiles}) - else() - set (_prefixHeader "${_prefixFiles}") - endif() - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}") - endif() - # because CMake PRE_BUILD command does not support dependencies, - # we check dependencies explicity in cotire script mode when the pre-build action is run - add_custom_command( - TARGET "${_target}" - PRE_BUILD ${_cmds} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMENT "Updating target ${_target} prefix headers" - VERBATIM) - # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++ - set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") - set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}") - elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - # for makefile based generator, we force inclusion of the prefix header for all target source files - # if this is a single-language target without any excluded files - if (_wholeTarget) - set (_language "${_languages}") - # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level - # see cotire_setup_pch_file_inclusion - if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - if (_prefixFile) - get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER) - set (_options COMPILE_OPTIONS) - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _options) - set_property(TARGET ${_target} APPEND PROPERTY ${_options}) - endif() - endif() - endif() - endif() -endfunction() - -function (cotire_setup_unity_generation_commands _language _target _targetScript _targetConfigScript _unityFiles _cmdsVar) - set (_dependencySources "") - cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN}) - foreach (_unityFile ${_unityFiles}) - set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE) - # set up compiled unity source dependencies via OBJECT_DEPENDS - # this ensures that missing source files are generated before the unity file is compiled - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}") - endif() - if (_dependencySources) - # the OBJECT_DEPENDS property requires a list of full paths - set (_objectDependsPaths "") - foreach (_sourceFile ${_dependencySources}) - get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION) - list (APPEND _objectDependsPaths "${_sourceLocation}") - endforeach() - set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_objectDependsPaths}) - endif() - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel - set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj") - endif() - cotire_set_cmd_to_prologue(_unityCmd) - list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetConfigScript}" "${_unityFile}") - if (CMAKE_VERSION VERSION_LESS "3.1.0") - set (_unityCmdDepends "${_targetScript}") - else() - # CMake 3.1.0 supports generator expressions in arguments to DEPENDS - set (_unityCmdDepends "${_targetConfigScript}") - endif() - if (MSVC_IDE) - file (TO_NATIVE_PATH "${_unityFile}" _unityFileLogPath) - else() - file (RELATIVE_PATH _unityFileLogPath "${CMAKE_BINARY_DIR}" "${_unityFile}") - endif() - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_unityCmdDepends}") - endif() - add_custom_command( - OUTPUT "${_unityFile}" - COMMAND ${_unityCmd} - DEPENDS ${_unityCmdDepends} - COMMENT "Generating ${_language} unity source ${_unityFileLogPath}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_unityCmd}) - endforeach() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar) - set (_sourceFiles ${ARGN}) - set (_dependencySources "") - cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles}) - cotire_set_cmd_to_prologue(_prefixCmd) - list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" ${_unityFiles}) - set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE) - # make prefix header generation depend on the actual compiler executable used to force - # re-generation when the compiler executable is updated. This prevents "file not found" - # errors for compiler version specific system header files. - get_filename_component(_realCompilerExe "${CMAKE_${_language}_COMPILER}" ABSOLUTE) - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_unityFile} ${_dependencySources} ${_realCompilerExe}") - endif() - if (MSVC_IDE) - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileLogPath) - else() - file (RELATIVE_PATH _prefixFileLogPath "${CMAKE_BINARY_DIR}" "${_prefixFile}") - endif() - get_filename_component(_prefixFileExt "${_prefixFile}" EXT) - if (_prefixFileExt MATCHES "^\\.c") - set (_comment "Generating ${_language} prefix source ${_prefixFileLogPath}") - else() - set (_comment "Generating ${_language} prefix header ${_prefixFileLogPath}") - endif() - # prevent pre-processing errors upon generating the prefix header when a target's generated include file does not yet exist - # we do not add a file-level dependency for the target's generated files though, because we only want to depend on their existence - # thus we make the prefix header generation depend on a custom helper target which triggers the generation of the files - set (_preTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}_pre") - if (TARGET ${_preTargetName}) - # custom helper target has already been generated while processing a different language - list (APPEND _dependencySources ${_preTargetName}) - else() - get_target_property(_targetSourceFiles ${_target} SOURCES) - cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles}) - if (_generatedSources) - add_custom_target("${_preTargetName}" DEPENDS ${_generatedSources}) - cotire_init_target("${_preTargetName}") - list (APPEND _dependencySources ${_preTargetName}) - endif() - endif() - add_custom_command( - OUTPUT "${_prefixFile}" "${_prefixFile}.log" - COMMAND ${_prefixCmd} - DEPENDS ${_unityFiles} ${_dependencySources} "${_realCompilerExe}" - COMMENT "${_comment}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_from_unity_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar) - set (_sourceFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma - cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) - else() - set (_prefixSourceFile "${_prefixFile}") - endif() - cotire_setup_prefix_generation_command( - ${_language} ${_target} "${_targetScript}" - "${_prefixSourceFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # set up generation of a prefix source file which includes the prefix header - cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) - endif() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_from_provided_command _language _target _targetScript _prefixFile _cmdsVar) - set (_prefixHeaderFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma - cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) - else() - set (_prefixSourceFile "${_prefixFile}") - endif() - cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixSourceFile}" _cmds ${_prefixHeaderFiles}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # set up generation of a prefix source file which includes the prefix header - cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) - endif() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_init_cotire_target_properties _target) - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}") - cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}") - if (NOT _isRelative) - set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}") - endif() - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT "COPY_UNITY") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET) - if (NOT _isSet) - if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}") - else() - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "") - endif() - endif() -endfunction() - -function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar) - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - string (REPLACE ";" " " _languagesStr "${_languages}") - math (EXPR _numberOfExcludedFiles "${ARGC} - 4") - if (_numberOfExcludedFiles EQUAL 0) - set (_excludedStr "") - elseif (COTIRE_VERBOSE OR _numberOfExcludedFiles LESS 4) - string (REPLACE ";" ", " _excludedStr "excluding ${ARGN}") - else() - set (_excludedStr "excluding ${_numberOfExcludedFiles} files") - endif() - set (_targetMsg "") - if (NOT _languages) - set (_targetMsg "Target ${_target} cannot be cotired.") - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetUsePCH AND NOT _targetAddSCU) - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.") - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetUsePCH) - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.") - endif() - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetAddSCU) - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.") - endif() - else() - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired.") - endif() - endif() - set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE) -endfunction() - -function (cotire_choose_target_languages _target _targetLanguagesVar _wholeTargetVar) - set (_languages ${ARGN}) - set (_allSourceFiles "") - set (_allExcludedSourceFiles "") - set (_allCotiredSourceFiles "") - set (_targetLanguages "") - set (_pchEligibleTargetLanguages "") - get_target_property(_targetType ${_target} TYPE) - get_target_property(_targetSourceFiles ${_target} SOURCES) - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - set (_disableMsg "") - foreach (_language ${_languages}) - get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER) - get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE) - if (_prefixHeader OR _unityBuildFile) - message (STATUS "cotire: target ${_target} has already been cotired.") - set (${_targetLanguagesVar} "" PARENT_SCOPE) - return() - endif() - if (_targetUsePCH AND "${_language}" MATCHES "^C|CXX$" AND DEFINED CMAKE_${_language}_COMPILER_ID) - if (CMAKE_${_language}_COMPILER_ID) - cotire_check_precompiled_header_support("${_language}" "${_target}" _disableMsg) - if (_disableMsg) - set (_targetUsePCH FALSE) - endif() - endif() - endif() - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (_sourceFiles OR _excludedSources OR _cotiredSources) - list (APPEND _targetLanguages ${_language}) - endif() - if (_sourceFiles) - list (APPEND _allSourceFiles ${_sourceFiles}) - endif() - list (LENGTH _sourceFiles _numberOfSources) - if (NOT _numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) - list (APPEND _pchEligibleTargetLanguages ${_language}) - endif() - if (_excludedSources) - list (APPEND _allExcludedSourceFiles ${_excludedSources}) - endif() - if (_cotiredSources) - list (APPEND _allCotiredSourceFiles ${_cotiredSources}) - endif() - endforeach() - set (_targetMsgLevel STATUS) - if (NOT _targetLanguages) - string (REPLACE ";" " or " _languagesStr "${_languages}") - set (_disableMsg "No ${_languagesStr} source files.") - set (_targetUsePCH FALSE) - set (_targetAddSCU FALSE) - endif() - if (_targetUsePCH) - if (_allCotiredSourceFiles) - cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles}) - list (REMOVE_DUPLICATES _cotireTargets) - string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}") - set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.") - set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},") - set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.") - set (_targetMsgLevel SEND_ERROR) - set (_targetUsePCH FALSE) - elseif (NOT _pchEligibleTargetLanguages) - set (_disableMsg "Too few applicable sources.") - set (_targetUsePCH FALSE) - elseif (XCODE AND _allExcludedSourceFiles) - # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target - set (_disableMsg "Exclusion of source files not supported for generator Xcode.") - set (_targetUsePCH FALSE) - elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY") - # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target - set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.") - set (_targetUsePCH FALSE) - endif() - endif() - set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH}) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU}) - cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles}) - if (_targetMsg) - if (NOT DEFINED COTIREMSG_${_target}) - set (COTIREMSG_${_target} "") - endif() - if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR - NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}") - # cache message to avoid redundant messages on re-configure - set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.") - message (${_targetMsgLevel} "${_targetMsg}") - endif() - endif() - list (LENGTH _targetLanguages _numberOfLanguages) - if (_numberOfLanguages GREATER 1 OR _allExcludedSourceFiles) - set (${_wholeTargetVar} FALSE PARENT_SCOPE) - else() - set (${_wholeTargetVar} TRUE PARENT_SCOPE) - endif() - set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE) -endfunction() - -function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar) - set (_sourceFiles ${ARGN}) - get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) - if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)") - set (_numberOfThreads "${CMAKE_MATCH_2}") - if (NOT _numberOfThreads) - # use all available cores - ProcessorCount(_numberOfThreads) - endif() - list (LENGTH _sourceFiles _numberOfSources) - math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}") - elseif (NOT _maxIncludes MATCHES "[0-9]+") - set (_maxIncludes 0) - endif() - if (COTIRE_DEBUG) - message (STATUS "${_target} unity source max includes: ${_maxIncludes}") - endif() - set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE) -endfunction() - -function (cotire_process_target_language _language _configurations _target _wholeTarget _cmdsVar) - set (${_cmdsVar} "" PARENT_SCOPE) - get_target_property(_targetSourceFiles ${_target} SOURCES) - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (NOT _sourceFiles AND NOT _cotiredSources) - return() - endif() - set (_cmds "") - # check for user provided unity source file list - get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT) - if (NOT _unitySourceFiles) - set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources}) - endif() - cotire_generate_target_script( - ${_language} "${_configurations}" ${_target} _targetScript _targetConfigScript ${_unitySourceFiles}) - # set up unity files for parallel compilation - cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles}) - cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles}) - list (LENGTH _unityFiles _numberOfUnityFiles) - if (_numberOfUnityFiles EQUAL 0) - return() - elseif (_numberOfUnityFiles GREATER 1) - cotire_setup_unity_generation_commands( - ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFiles}" _cmds ${_unitySourceFiles}) - endif() - # set up single unity file for prefix header generation - cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) - cotire_setup_unity_generation_commands( - ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFile}" _cmds ${_unitySourceFiles}) - cotire_make_prefix_file_path(${_language} ${_target} _prefixFile) - # set up prefix header - if (_prefixFile) - # check for user provided prefix header files - get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) - if (_prefixHeaderFiles) - cotire_setup_prefix_generation_from_provided_command( - ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles}) - else() - cotire_setup_prefix_generation_from_unity_command( - ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_unityFile}" _cmds ${_unitySourceFiles}) - endif() - # check if selected language has enough sources at all - list (LENGTH _sourceFiles _numberOfSources) - if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) - set (_targetUsePCH FALSE) - else() - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - endif() - if (_targetUsePCH) - cotire_make_pch_file_path(${_language} ${_target} _pchFile) - if (_pchFile) - # first file in _sourceFiles is passed as the host file - cotire_setup_pch_file_compilation( - ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) - cotire_setup_pch_file_inclusion( - ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) - endif() - elseif (_prefixHeaderFiles) - # user provided prefix header must be included unconditionally - cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_sourceFiles}) - endif() - endif() - # mark target as cotired for language - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}") - if (_prefixFile) - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}") - if (_targetUsePCH AND _pchFile) - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}") - endif() - endif() - set (${_cmdsVar} ${_cmds} PARENT_SCOPE) -endfunction() - -function (cotire_setup_clean_target _target) - set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}") - if (NOT TARGET "${_cleanTargetName}") - cotire_set_cmd_to_prologue(_cmds) - get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}") - add_custom_target(${_cleanTargetName} - COMMAND ${_cmds} - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - COMMENT "Cleaning up target ${_target} cotire generated files" - VERBATIM) - cotire_init_target("${_cleanTargetName}") - endif() -endfunction() - -function (cotire_setup_pch_target _languages _configurations _target) - if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - # for makefile based generators, we add a custom target to trigger the generation of the cotire related files - set (_dependsFiles "") - foreach (_language ${_languages}) - set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE) - if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # Visual Studio and Intel only create precompiled header as a side effect - list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER) - endif() - cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props}) - if (_dependsFile) - list (APPEND _dependsFiles "${_dependsFile}") - endif() - endforeach() - if (_dependsFiles) - set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}") - add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles}) - cotire_init_target("${_pchTargetName}") - cotire_add_to_pch_all_target(${_pchTargetName}) - endif() - else() - # for other generators, we add the "clean all" target to clean up the precompiled header - cotire_setup_clean_all_target() - endif() -endfunction() - -function (cotire_filter_object_libraries _target _objectLibrariesVar) - set (_objectLibraries "") - foreach (_source ${ARGN}) - if (_source MATCHES "^\\$$") - list (APPEND _objectLibraries "${_source}") - endif() - endforeach() - set (${_objectLibrariesVar} ${_objectLibraries} PARENT_SCOPE) -endfunction() - -function (cotire_collect_unity_target_sources _target _languages _unityTargetSourcesVar) - get_target_property(_targetSourceFiles ${_target} SOURCES) - set (_unityTargetSources ${_targetSourceFiles}) - foreach (_language ${_languages}) - get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) - if (_unityFiles) - # remove source files that are included in the unity source - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (_sourceFiles OR _cotiredSources) - list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources}) - endif() - # add unity source files instead - list (APPEND _unityTargetSources ${_unityFiles}) - endif() - endforeach() - get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT) - if ("${_linkLibrariesStrategy}" MATCHES "^COPY_UNITY$") - cotire_filter_object_libraries(${_target} _objectLibraries ${_targetSourceFiles}) - if (_objectLibraries) - cotire_map_libraries("${_linkLibrariesStrategy}" _unityObjectLibraries ${_objectLibraries}) - list (REMOVE_ITEM _unityTargetSources ${_objectLibraries}) - list (APPEND _unityTargetSources ${_unityObjectLibraries}) - endif() - endif() - set (${_unityTargetSourcesVar} ${_unityTargetSources} PARENT_SCOPE) -endfunction() - -function (cotire_setup_unity_target_pch_usage _languages _target) - foreach (_language ${_languages}) - get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) - if (_unityFiles) - get_property(_userPrefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - if (_userPrefixFile AND _prefixFile) - # user provided prefix header must be included unconditionally by unity sources - cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_unityFiles}) - endif() - endif() - endforeach() -endfunction() - -function (cotire_setup_unity_build_target _languages _configurations _target) - get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) - if (NOT _unityTargetName) - set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}") - endif() - # determine unity target sub type - get_target_property(_targetType ${_target} TYPE) - if ("${_targetType}" STREQUAL "EXECUTABLE") - set (_unityTargetSubType "") - elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") - set (_unityTargetSubType "${CMAKE_MATCH_1}") - else() - message (WARNING "cotire: target ${_target} has unknown target type ${_targetType}.") - return() - endif() - # determine unity target sources - set (_unityTargetSources "") - cotire_collect_unity_target_sources(${_target} "${_languages}" _unityTargetSources) - # handle automatic Qt processing - get_target_property(_targetAutoMoc ${_target} AUTOMOC) - get_target_property(_targetAutoUic ${_target} AUTOUIC) - get_target_property(_targetAutoRcc ${_target} AUTORCC) - if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc) - # if the original target sources are subject to CMake's automatic Qt processing, - # also include implicitly generated _automoc.cpp file - list (APPEND _unityTargetSources "${_target}_automoc.cpp") - set_property (SOURCE "${_target}_automoc.cpp" PROPERTY GENERATED TRUE) - endif() - # prevent AUTOMOC, AUTOUIC and AUTORCC properties from being set when the unity target is created - set (CMAKE_AUTOMOC OFF) - set (CMAKE_AUTOUIC OFF) - set (CMAKE_AUTORCC OFF) - if (COTIRE_DEBUG) - message (STATUS "add target ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}") - endif() - # generate unity target - if ("${_targetType}" STREQUAL "EXECUTABLE") - add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) - else() - add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) - endif() - if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio") - # depend on original target's automoc target, if it exists - if (TARGET ${_target}_automoc) - add_dependencies(${_unityTargetName} ${_target}_automoc) - endif() - else() - if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc) - # depend on the original target's implicity generated _automoc target - add_dependencies(${_unityTargetName} ${_target}_automoc) - endif() - endif() - # copy output location properties - set (_outputDirProperties - ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_ - LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_ - RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_) - if (COTIRE_UNITY_OUTPUT_DIRECTORY) - set (_setDefaultOutputDir TRUE) - if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}") - set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}") - else() - # append relative COTIRE_UNITY_OUTPUT_DIRECTORY to target's actual output directory - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties}) - cotire_resolve_config_properites("${_configurations}" _properties ${_outputDirProperties}) - foreach (_property ${_properties}) - get_property(_outputDir TARGET ${_target} PROPERTY ${_property}) - if (_outputDir) - get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) - set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}") - set (_setDefaultOutputDir FALSE) - endif() - endforeach() - if (_setDefaultOutputDir) - get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) - endif() - endif() - if (_setDefaultOutputDir) - set_target_properties(${_unityTargetName} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}" - LIBRARY_OUTPUT_DIRECTORY "${_outputDir}" - RUNTIME_OUTPUT_DIRECTORY "${_outputDir}") - endif() - else() - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - ${_outputDirProperties}) - endif() - # copy output name - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_ - LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_ - OUTPUT_NAME OUTPUT_NAME_ - RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_ - PREFIX _POSTFIX SUFFIX - IMPORT_PREFIX IMPORT_SUFFIX) - # copy compile stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - COMPILE_DEFINITIONS COMPILE_DEFINITIONS_ - COMPILE_FLAGS COMPILE_OPTIONS - Fortran_FORMAT Fortran_MODULE_DIRECTORY - INCLUDE_DIRECTORIES - INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_ - POSITION_INDEPENDENT_CODE - C_COMPILER_LAUNCHER CXX_COMPILER_LAUNCHER - C_INCLUDE_WHAT_YOU_USE CXX_INCLUDE_WHAT_YOU_USE - C_VISIBILITY_PRESET CXX_VISIBILITY_PRESET VISIBILITY_INLINES_HIDDEN - C_CLANG_TIDY CXX_CLANG_TIDY) - # copy compile features - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - C_EXTENSIONS C_STANDARD C_STANDARD_REQUIRED - CXX_EXTENSIONS CXX_STANDARD CXX_STANDARD_REQUIRED - COMPILE_FEATURES) - # copy interface stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN - COMPATIBLE_INTERFACE_STRING - INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS - INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SOURCES - INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SYSTEM_INCLUDE_DIRECTORIES - INTERFACE_AUTOUIC_OPTIONS NO_SYSTEM_FROM_IMPORTED) - # copy link stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - BUILD_WITH_INSTALL_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH - LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED - LINK_FLAGS LINK_FLAGS_ - LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_ - LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_ - LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC - STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_ - NO_SONAME SOVERSION VERSION - LINK_WHAT_YOU_USE) - # copy cmake stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK) - # copy Apple platform specific stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - BUNDLE BUNDLE_EXTENSION FRAMEWORK FRAMEWORK_VERSION INSTALL_NAME_DIR - MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST MACOSX_RPATH - OSX_ARCHITECTURES OSX_ARCHITECTURES_ PRIVATE_HEADER PUBLIC_HEADER RESOURCE XCTEST - IOS_INSTALL_COMBINED) - # copy Windows platform specific stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - GNUtoMS - COMPILE_PDB_NAME COMPILE_PDB_NAME_ - COMPILE_PDB_OUTPUT_DIRECTORY COMPILE_PDB_OUTPUT_DIRECTORY_ - PDB_NAME PDB_NAME_ PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_ - VS_DESKTOP_EXTENSIONS_VERSION VS_DOTNET_REFERENCES VS_DOTNET_TARGET_FRAMEWORK_VERSION - VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE - VS_IOT_EXTENSIONS_VERSION VS_IOT_STARTUP_TASK - VS_KEYWORD VS_MOBILE_EXTENSIONS_VERSION - VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER - VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION - VS_WINRT_COMPONENT VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES - WIN32_EXECUTABLE WINDOWS_EXPORT_ALL_SYMBOLS - DEPLOYMENT_REMOTE_DIRECTORY VS_CONFIGURATION_TYPE - VS_SDK_REFERENCES) - # copy Android platform specific stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - ANDROID_API ANDROID_API_MIN ANDROID_GUI - ANDROID_ANT_ADDITIONAL_OPTIONS ANDROID_ARCH ANDROID_ASSETS_DIRECTORIES - ANDROID_JAR_DEPENDENCIES ANDROID_JAR_DIRECTORIES ANDROID_JAVA_SOURCE_DIR - ANDROID_NATIVE_LIB_DEPENDENCIES ANDROID_NATIVE_LIB_DIRECTORIES - ANDROID_PROCESS_MAX ANDROID_PROGUARD ANDROID_PROGUARD_CONFIG_PATH - ANDROID_SECURE_PROPS_PATH ANDROID_SKIP_ANT_STEP ANDROID_STL_TYPE) - # use output name from original target - get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME) - if (NOT _targetOutputName) - set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}") - endif() - # use export symbol from original target - cotire_get_target_export_symbol("${_target}" _defineSymbol) - if (_defineSymbol) - set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}") - if ("${_targetType}" STREQUAL "EXECUTABLE") - set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE) - endif() - endif() - cotire_init_target(${_unityTargetName}) - cotire_add_to_unity_all_target(${_unityTargetName}) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}") -endfunction(cotire_setup_unity_build_target) - -function (cotire_target _target) - set(_options "") - set(_oneValueArgs "") - set(_multiValueArgs LANGUAGES CONFIGURATIONS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (NOT _option_LANGUAGES) - get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) - endif() - if (NOT _option_CONFIGURATIONS) - cotire_get_configuration_types(_option_CONFIGURATIONS) - endif() - # check if cotire can be applied to target at all - cotire_is_target_supported(${_target} _isSupported) - if (NOT _isSupported) - get_target_property(_imported ${_target} IMPORTED) - get_target_property(_targetType ${_target} TYPE) - if (_imported) - message (WARNING "cotire: imported ${_targetType} target ${_target} cannot be cotired.") - else() - message (STATUS "cotire: ${_targetType} target ${_target} cannot be cotired.") - endif() - return() - endif() - # resolve alias - get_target_property(_aliasName ${_target} ALIASED_TARGET) - if (_aliasName) - if (COTIRE_DEBUG) - message (STATUS "${_target} is an alias. Applying cotire to aliased target ${_aliasName} instead.") - endif() - set (_target ${_aliasName}) - endif() - # check if target needs to be cotired for build type - # when using configuration types, the test is performed at build time - cotire_init_cotire_target_properties(${_target}) - if (NOT CMAKE_CONFIGURATION_TYPES) - if (CMAKE_BUILD_TYPE) - list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index) - else() - list (FIND _option_CONFIGURATIONS "None" _index) - endif() - if (_index EQUAL -1) - if (COTIRE_DEBUG) - message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})") - endif() - return() - endif() - endif() - # when not using configuration types, immediately create cotire intermediate dir - if (NOT CMAKE_CONFIGURATION_TYPES) - cotire_get_intermediate_dir(_baseDir) - file (MAKE_DIRECTORY "${_baseDir}") - endif() - # choose languages that apply to the target - cotire_choose_target_languages("${_target}" _targetLanguages _wholeTarget ${_option_LANGUAGES}) - if (NOT _targetLanguages) - return() - endif() - set (_cmds "") - foreach (_language ${_targetLanguages}) - cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}" ${_target} ${_wholeTarget} _cmd) - if (_cmd) - list (APPEND _cmds ${_cmd}) - endif() - endforeach() - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - if (_targetAddSCU) - cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) - endif() - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - if (_targetUsePCH) - cotire_setup_target_pch_usage("${_targetLanguages}" ${_target} ${_wholeTarget} ${_cmds}) - cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) - if (_targetAddSCU) - cotire_setup_unity_target_pch_usage("${_targetLanguages}" ${_target}) - endif() - endif() - get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN) - if (_targetAddCleanTarget) - cotire_setup_clean_target(${_target}) - endif() -endfunction(cotire_target) - -function (cotire_map_libraries _strategy _mappedLibrariesVar) - set (_mappedLibraries "") - foreach (_library ${ARGN}) - if (_library MATCHES "^\\$$") - set (_libraryName "${CMAKE_MATCH_1}") - set (_linkOnly TRUE) - set (_objectLibrary FALSE) - elseif (_library MATCHES "^\\$$") - set (_libraryName "${CMAKE_MATCH_1}") - set (_linkOnly FALSE) - set (_objectLibrary TRUE) - else() - set (_libraryName "${_library}") - set (_linkOnly FALSE) - set (_objectLibrary FALSE) - endif() - if ("${_strategy}" MATCHES "COPY_UNITY") - cotire_is_target_supported(${_libraryName} _isSupported) - if (_isSupported) - # use target's corresponding unity target, if available - get_target_property(_libraryUnityTargetName ${_libraryName} COTIRE_UNITY_TARGET_NAME) - if (TARGET "${_libraryUnityTargetName}") - if (_linkOnly) - list (APPEND _mappedLibraries "$") - elseif (_objectLibrary) - list (APPEND _mappedLibraries "$") - else() - list (APPEND _mappedLibraries "${_libraryUnityTargetName}") - endif() - else() - list (APPEND _mappedLibraries "${_library}") - endif() - else() - list (APPEND _mappedLibraries "${_library}") - endif() - else() - list (APPEND _mappedLibraries "${_library}") - endif() - endforeach() - list (REMOVE_DUPLICATES _mappedLibraries) - set (${_mappedLibrariesVar} ${_mappedLibraries} PARENT_SCOPE) -endfunction() - -function (cotire_target_link_libraries _target) - cotire_is_target_supported(${_target} _isSupported) - if (NOT _isSupported) - return() - endif() - get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) - if (TARGET "${_unityTargetName}") - get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT) - if (COTIRE_DEBUG) - message (STATUS "unity target ${_unityTargetName} link strategy: ${_linkLibrariesStrategy}") - endif() - if ("${_linkLibrariesStrategy}" MATCHES "^(COPY|COPY_UNITY)$") - get_target_property(_linkLibraries ${_target} LINK_LIBRARIES) - if (_linkLibraries) - cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkLibraries ${_linkLibraries}) - set_target_properties(${_unityTargetName} PROPERTIES LINK_LIBRARIES "${_unityLinkLibraries}") - if (COTIRE_DEBUG) - message (STATUS "unity target ${_unityTargetName} link libraries: ${_unityLinkLibraries}") - endif() - endif() - get_target_property(_interfaceLinkLibraries ${_target} INTERFACE_LINK_LIBRARIES) - if (_interfaceLinkLibraries) - cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkInterfaceLibraries ${_interfaceLinkLibraries}) - set_target_properties(${_unityTargetName} PROPERTIES INTERFACE_LINK_LIBRARIES "${_unityLinkInterfaceLibraries}") - if (COTIRE_DEBUG) - message (STATUS "unity target ${_unityTargetName} interface link libraries: ${_unityLinkInterfaceLibraries}") - endif() - endif() - endif() - endif() -endfunction(cotire_target_link_libraries) - -function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName) - if (_targetName) - file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*") - else() - file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*") - endif() - # filter files in intermediate directory - set (_filesToRemove "") - foreach (_file ${_cotireFiles}) - get_filename_component(_dir "${_file}" DIRECTORY) - get_filename_component(_dirName "${_dir}" NAME) - if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}") - list (APPEND _filesToRemove "${_file}") - endif() - endforeach() - if (_filesToRemove) - if (COTIRE_VERBOSE) - message (STATUS "cleaning up ${_filesToRemove}") - endif() - file (REMOVE ${_filesToRemove}) - endif() -endfunction() - -function (cotire_init_target _targetName) - if (COTIRE_TARGETS_FOLDER) - set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}") - endif() - set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_ALL TRUE) - if (MSVC_IDE) - set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE) - endif() -endfunction() - -function (cotire_add_to_pch_all_target _pchTargetName) - set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - add_custom_target("${_targetName}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - VERBATIM) - cotire_init_target("${_targetName}") - endif() - cotire_setup_clean_all_target() - add_dependencies(${_targetName} ${_pchTargetName}) -endfunction() - -function (cotire_add_to_unity_all_target _unityTargetName) - set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - add_custom_target("${_targetName}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - VERBATIM) - cotire_init_target("${_targetName}") - endif() - cotire_setup_clean_all_target() - add_dependencies(${_targetName} ${_unityTargetName}) -endfunction() - -function (cotire_setup_clean_all_target) - set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - cotire_set_cmd_to_prologue(_cmds) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}") - add_custom_target(${_targetName} - COMMAND ${_cmds} - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - COMMENT "Cleaning up all cotire generated files" - VERBATIM) - cotire_init_target("${_targetName}") - endif() -endfunction() - -function (cotire) - set(_options "") - set(_oneValueArgs "") - set(_multiValueArgs LANGUAGES CONFIGURATIONS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - set (_targets ${_option_UNPARSED_ARGUMENTS}) - foreach (_target ${_targets}) - if (TARGET ${_target}) - cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS}) - else() - message (WARNING "cotire: ${_target} is not a target.") - endif() - endforeach() - foreach (_target ${_targets}) - if (TARGET ${_target}) - cotire_target_link_libraries(${_target}) - endif() - endforeach() -endfunction() - -if (CMAKE_SCRIPT_MODE_FILE) - - # cotire is being run in script mode - # locate -P on command args - set (COTIRE_ARGC -1) - foreach (_index RANGE ${CMAKE_ARGC}) - if (COTIRE_ARGC GREATER -1) - set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}") - math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1") - elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P") - set (COTIRE_ARGC 0) - endif() - endforeach() - - # include target script if available - if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$") - # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES) - include("${COTIRE_ARGV2}") - endif() - - if (COTIRE_DEBUG) - message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}") - endif() - - if (NOT COTIRE_BUILD_TYPE) - set (COTIRE_BUILD_TYPE "None") - endif() - string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig) - set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}}) - set (_systemIncludeDirs ${COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}}) - set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}}) - set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}}) - # check if target has been cotired for actual build type COTIRE_BUILD_TYPE - list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index) - if (_index GREATER -1) - set (_sources ${COTIRE_TARGET_SOURCES}) - set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}}) - else() - if (COTIRE_DEBUG) - message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})") - endif() - set (_sources "") - set (_sourcesDefinitions "") - endif() - set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS}) - set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS}) - set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS}) - set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS}) - - if ("${COTIRE_ARGV1}" STREQUAL "unity") - - if (XCODE) - # executing pre-build action under Xcode, check dependency on target script - set (_dependsOption DEPENDS "${COTIRE_ARGV2}") - else() - # executing custom command, no need to re-check for dependencies - set (_dependsOption "") - endif() - - cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources}) - - cotire_generate_unity_source( - "${COTIRE_ARGV3}" ${_sources} - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions} - PRE_UNDEFS ${_targetPreUndefs} - POST_UNDEFS ${_targetPostUndefs} - SOURCES_PRE_UNDEFS ${_sourcesPreUndefs} - SOURCES_POST_UNDEFS ${_sourcesPostUndefs} - ${_dependsOption}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "prefix") - - if (XCODE) - # executing pre-build action under Xcode, check dependency on unity file and prefix dependencies - set (_dependsOption DEPENDS "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS}) - else() - # executing custom command, no need to re-check for dependencies - set (_dependsOption "") - endif() - - set (_files "") - foreach (_index RANGE 4 ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - - cotire_generate_prefix_header( - "${COTIRE_ARGV3}" ${_files} - COMPILER_LAUNCHER "${COTIRE_TARGET_${COTIRE_TARGET_LANGUAGE}_COMPILER_LAUNCHER}" - COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" - COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} - COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" - COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}" - INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH} - IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}" - INCLUDE_PRIORITY_PATH ${COTIRE_TARGET_INCLUDE_PRIORITY_PATH} - INCLUDE_DIRECTORIES ${_includeDirs} - SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} - COMPILE_DEFINITIONS ${_compileDefinitions} - COMPILE_FLAGS ${_compileFlags} - ${_dependsOption}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "precompile") - - set (_files "") - foreach (_index RANGE 5 ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - - cotire_precompile_prefix_header( - "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}" - COMPILER_LAUNCHER "${COTIRE_TARGET_${COTIRE_TARGET_LANGUAGE}_COMPILER_LAUNCHER}" - COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" - COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} - COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" - COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - INCLUDE_DIRECTORIES ${_includeDirs} - SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} - COMPILE_DEFINITIONS ${_compileDefinitions} - COMPILE_FLAGS ${_compileFlags}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "combine") - - if (COTIRE_TARGET_LANGUAGE) - set (_combinedFile "${COTIRE_ARGV3}") - set (_startIndex 4) - else() - set (_combinedFile "${COTIRE_ARGV2}") - set (_startIndex 3) - endif() - set (_files "") - foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - - if (XCODE) - # executing pre-build action under Xcode, check dependency on files to be combined - set (_dependsOption DEPENDS ${_files}) - else() - # executing custom command, no need to re-check for dependencies - set (_dependsOption "") - endif() - - if (COTIRE_TARGET_LANGUAGE) - cotire_generate_unity_source( - "${_combinedFile}" ${_files} - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - ${_dependsOption}) - else() - cotire_generate_unity_source("${_combinedFile}" ${_files} ${_dependsOption}) - endif() - - elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup") - - cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}") - - else() - message (FATAL_ERROR "cotire: unknown command \"${COTIRE_ARGV1}\".") - endif() - -else() - - # cotire is being run in include mode - # set up all variable and property definitions - - if (NOT DEFINED COTIRE_DEBUG_INIT) - if (DEFINED COTIRE_DEBUG) - set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG}) - else() - set (COTIRE_DEBUG_INIT FALSE) - endif() - endif() - option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT}) - - if (NOT DEFINED COTIRE_VERBOSE_INIT) - if (DEFINED COTIRE_VERBOSE) - set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE}) - else() - set (COTIRE_VERBOSE_INIT FALSE) - endif() - endif() - option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT}) - - set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING - "Ignore headers with the listed file extensions from the generated prefix header.") - - set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING - "Ignore headers from these directories when generating the prefix header.") - - set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING - "Ignore sources with the listed file extensions from the generated unity source.") - - set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING - "Minimum number of sources in target required to enable use of precompiled header.") - - if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT) - if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}) - elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio") - # enable parallelization for generators that run multiple jobs by default - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j") - else() - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0") - endif() - endif() - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING - "Maximum number of source files to include in a single unity source file.") - - if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX) - set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix") - endif() - if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX) - set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity") - endif() - if (NOT COTIRE_INTDIR) - set (COTIRE_INTDIR "cotire") - endif() - if (NOT COTIRE_PCH_ALL_TARGET_NAME) - set (COTIRE_PCH_ALL_TARGET_NAME "all_pch") - endif() - if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME) - set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity") - endif() - if (NOT COTIRE_CLEAN_ALL_TARGET_NAME) - set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire") - endif() - if (NOT COTIRE_CLEAN_TARGET_SUFFIX) - set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire") - endif() - if (NOT COTIRE_PCH_TARGET_SUFFIX) - set (COTIRE_PCH_TARGET_SUFFIX "_pch") - endif() - if (MSVC) - # MSVC default PCH memory scaling factor of 100 percent (75 MB) is too small for template heavy C++ code - # use a bigger default factor of 170 percent (128 MB) - if (NOT DEFINED COTIRE_PCH_MEMORY_SCALING_FACTOR) - set (COTIRE_PCH_MEMORY_SCALING_FACTOR "170") - endif() - endif() - if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX) - set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity") - endif() - if (NOT DEFINED COTIRE_TARGETS_FOLDER) - set (COTIRE_TARGETS_FOLDER "cotire") - endif() - if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY) - if ("${CMAKE_GENERATOR}" MATCHES "Ninja") - # generated Ninja build files do not work if the unity target produces the same output file as the cotired target - set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity") - else() - set (COTIRE_UNITY_OUTPUT_DIRECTORY "") - endif() - endif() - - # define cotire cache variables - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH" - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "The variable can be set to a semicolon separated list of include directories." - "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." - "If not defined, defaults to empty list." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS" - BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header." - FULL_DOCS - "The variable can be set to a semicolon separated list of file extensions." - "If a header file extension matches one in the list, it will be excluded from the generated prefix header." - "Includes with an extension in CMAKE__SOURCE_FILE_EXTENSIONS are always ignored." - "If not defined, defaults to inc;inl;ipp." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS" - BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source." - FULL_DOCS - "The variable can be set to a semicolon separated list of file extensions." - "If a source file extension matches one in the list, it will be excluded from the generated unity source file." - "Source files with an extension in CMAKE__IGNORE_EXTENSIONS are always excluded." - "If not defined, defaults to m;mm." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES" - BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header." - FULL_DOCS - "The variable can be set to an integer > 0." - "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target." - "If not defined, defaults to 3." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES" - BRIEF_DOCS "Maximum number of source files to include in a single unity source file." - FULL_DOCS - "This may be set to an integer >= 0." - "If 0, cotire will only create a single unity source file." - "If a target contains more than that number of source files, cotire will create multiple unity source files for it." - "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores." - "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs." - "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." - "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise." - ) - - # define cotire directory properties - - define_property( - DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" - BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header." - FULL_DOCS - "See target property COTIRE_ENABLE_PRECOMPILED_HEADER." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD" - BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory." - FULL_DOCS - "See target property COTIRE_ADD_UNITY_BUILD." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_ADD_CLEAN" - BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory." - FULL_DOCS - "See target property COTIRE_ADD_CLEAN." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" - BRIEF_DOCS "Honor headers from these directories when generating the prefix header." - FULL_DOCS - "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" - BRIEF_DOCS "Header paths matching one of these directories are put at the top of the prefix header." - FULL_DOCS - "See target property COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" - BRIEF_DOCS "Maximum number of source files to include in a single unity source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" - BRIEF_DOCS "Define strategy for setting up the unity target's link libraries." - FULL_DOCS - "See target property COTIRE_UNITY_LINK_LIBRARIES_INIT." - ) - - # define cotire target properties - - define_property( - TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED - BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header." - FULL_DOCS - "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header." - "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target." - "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header." - "The target name will be set to this target's name with the suffix _pch appended." - "Inherited from directory." - "Defaults to TRUE." - ) - - define_property( - TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED - BRIEF_DOCS "Add a new target that performs a unity build for this target." - FULL_DOCS - "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources." - "Most of the relevant target properties will be copied from this target to the new unity build target." - "Target dependencies and linked libraries have to be manually set up for the new unity build target." - "The unity target name will be set to this target's name with the suffix _unity appended." - "Inherited from directory." - "Defaults to TRUE." - ) - - define_property( - TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED - BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target." - FULL_DOCS - "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)." - "The clean target name will be set to this target's name with the suffix _clean_cotire appended." - "Inherited from directory." - "Defaults to FALSE." - ) - - define_property( - TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "The property can be set to a list of directories." - "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." - "Inherited from directory." - "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}." - ) - - define_property( - TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED - BRIEF_DOCS "Honor headers from these directories when generating the prefix header." - FULL_DOCS - "The property can be set to a list of directories." - "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header." - "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH," - "the option which yields the closer relative path match wins." - "Inherited from directory." - "If not set, this property is initialized to the empty list." - ) - - define_property( - TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" INHERITED - BRIEF_DOCS "Header paths matching one of these directories are put at the top of prefix header." - FULL_DOCS - "The property can be set to a list of directories." - "Header file paths matching one of these directories will be inserted at the beginning of the generated prefix header." - "Header files are sorted according to the order of the directories in the property." - "If not set, this property is initialized to the empty list." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file before each target source file." - "Inherited from directory." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file after each target source file." - "Inherited from directory." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED - BRIEF_DOCS "Maximum number of source files to include in a single unity source file." - FULL_DOCS - "This may be set to an integer > 0." - "If a target contains more than that number of source files, cotire will create multiple unity build files for it." - "If not set, cotire will only create a single unity source file." - "Inherited from directory." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__UNITY_SOURCE_INIT" - BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one." - FULL_DOCS - "If set, cotire will only add the given file(s) to the generated unity source file." - "If not set, cotire will add all the target source files to the generated unity source file." - "The property can be set to a user provided unity source file." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__PREFIX_HEADER_INIT" - BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one." - FULL_DOCS - "If set, cotire will add the given header file(s) to the generated prefix header file." - "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file." - "The property can be set to a user provided prefix header file (e.g., stdafx.h)." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" INHERITED - BRIEF_DOCS "Define strategy for setting up unity target's link libraries." - FULL_DOCS - "If this property is empty or set to NONE, the generated unity target's link libraries have to be set up manually." - "If this property is set to COPY, the unity target's link libraries will be copied from this target." - "If this property is set to COPY_UNITY, the unity target's link libraries will be copied from this target with considering existing unity targets." - "Inherited from directory." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__UNITY_SOURCE" - BRIEF_DOCS "Read-only property. The generated unity source file(s)." - FULL_DOCS - "cotire sets this property to the path of the generated single computation unit source file for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE__PREFIX_HEADER" - BRIEF_DOCS "Read-only property. The generated prefix header file." - FULL_DOCS - "cotire sets this property to the full path of the generated language prefix header for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE__PRECOMPILED_HEADER" - BRIEF_DOCS "Read-only property. The generated precompiled header file." - FULL_DOCS - "cotire sets this property to the full path of the generated language precompiled header binary for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME" - BRIEF_DOCS "The name of the generated unity build target corresponding to this target." - FULL_DOCS - "This property can be set to the desired name of the unity target that will be created by cotire." - "If not set, the unity target name will be set to this target's name with the suffix _unity appended." - "After this target has been processed by cotire, the property is set to the actual name of the generated unity target." - "Defaults to empty string." - ) - - # define cotire source properties - - define_property( - SOURCE PROPERTY "COTIRE_EXCLUDED" - BRIEF_DOCS "Do not modify source file's build command." - FULL_DOCS - "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header." - "The source file will also be excluded from the generated unity source file." - "Source files that have their COMPILE_FLAGS property set will be excluded by default." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_DEPENDENCY" - BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file." - FULL_DOCS - "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file." - "If the file is modified, cotire will re-generate the prefix header source upon build." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file before this file is included." - "Defaults to empty string." - ) - - define_property( - SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file after this file is included." - "Defaults to empty string." - ) - - define_property( - SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE" - BRIEF_DOCS "Start a new unity source file which includes this source file as the first one." - FULL_DOCS - "If this property is set to TRUE, cotire will complete the current unity file and start a new one." - "The new unity source file will include this source file as the first one." - "This property essentially works as a separator for unity source files." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_TARGET" - BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target." - FULL_DOCS - "cotire sets this property to the name of target, that the source file's build command has been altered for." - "Defaults to empty string." - ) - - message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.") - -endif() diff --git a/CMakeModules/wasm.cmake b/CMakeModules/wasm.cmake deleted file mode 100644 index a8475728e49..00000000000 --- a/CMakeModules/wasm.cmake +++ /dev/null @@ -1,212 +0,0 @@ -find_package(Wasm) - -if(WASM_FOUND) - message(STATUS "Using WASM clang => " ${WASM_CLANG}) - message(STATUS "Using WASM llc => " ${WASM_LLC}) - message(STATUS "Using WASM llvm-link => " ${WASM_LLVM_LINK}) -else() - message( FATAL_ERROR "No WASM compiler cound be found (make sure WASM_ROOT is set)" ) - return() -endif() -macro(compile_wast) - #read arguments include ones that we don't since arguments get forwared "as is" and we don't want to threat unknown argument names as values - cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS;LIBRARIES" ${ARGN}) - set(target ${ARG_TARGET}) - - # NOTE: Setting SOURCE_FILE and looping over it to avoid cmake issue with compilation ${target}.bc's rule colliding with - # linking ${target}.bc's rule - if ("${ARG_SOURCE_FILES}" STREQUAL "") - set(SOURCE_FILES ${target}.cpp) - else() - set(SOURCE_FILES ${ARG_SOURCE_FILES}) - endif() - set(outfiles "") - foreach(srcfile ${SOURCE_FILES}) - - get_filename_component(outfile ${srcfile} NAME) - get_filename_component(extension ${srcfile} EXT) - get_filename_component(infile ${srcfile} ABSOLUTE) - - # -ffreestanding - # Assert that compilation targets a freestanding environment. - # This implies -fno-builtin. A freestanding environment is one in which the standard library may not exist, and program startup may not necessarily be at main. - # The most obvious example is an OS kernel. - - # -nostdlib - # Do not use the standard system startup files or libraries when linking. - # No startup files and only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, are ignored. - # The compiler may generate calls to memcmp, memset, memcpy and memmove. - # These entries are usually resolved by entries in libc. These entry points should be supplied through some other mechanism when this option is specified. - - # -fno-threadsafe-statics - # Do not emit the extra code to use the routines specified in the C++ ABI for thread-safe initialization of local statics. - # You can use this option to reduce code size slightly in code that doesn’t need to be thread-safe. - - # -fno-rtti - # Disable generation of information about every class with virtual functions for use by the C++ run-time type identification features (dynamic_cast and typeid). - - # -fno-exceptions - # Disable the generation of extra code needed to propagate exceptions - if ("${extension}" STREQUAL ".c") - set(STDFLAG -D_XOPEN_SOURCE=700) - else() - set(STDFLAG "--std=c++14") - endif() - - set(WASM_COMMAND ${WASM_CLANG} -emit-llvm -O3 ${STDFLAG} --target=wasm32 -ffreestanding - -nostdlib -nostdlibinc -DBOOST_DISABLE_ASSERTS -DBOOST_EXCEPTION_DISABLE -fno-threadsafe-statics -fno-rtti -fno-exceptions - -c ${infile} -o ${outfile}.bc - ) - if (${ARG_NOWARNINGS}) - list(APPEND WASM_COMMAND -Wno-everything) - else() - list(APPEND WASM_COMMAND -Weverything -Wno-c++98-compat -Wno-old-style-cast -Wno-vla -Wno-vla-extension -Wno-c++98-compat-pedantic - -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-packed -Wno-padded -Wno-c99-extensions -Wno-documentation-unknown-command) - endif() - - foreach(folder ${ARG_INCLUDE_FOLDERS}) - list(APPEND WASM_COMMAND -I ${folder}) - endforeach() - - if ("${ARG_SYSTEM_INCLUDE_FOLDERS}" STREQUAL "") - set (ARG_SYSTEM_INCLUDE_FOLDERS ${DEFAULT_SYSTEM_INCLUDE_FOLDERS}) - endif() - foreach(folder ${ARG_SYSTEM_INCLUDE_FOLDERS}) - list(APPEND WASM_COMMAND -isystem ${folder}) - endforeach() - - add_custom_command(OUTPUT ${outfile}.bc - DEPENDS ${infile} - COMMAND ${WASM_COMMAND} - IMPLICIT_DEPENDS CXX ${infile} - COMMENT "Building LLVM bitcode ${outfile}.bc" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - ) - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${outfile}.bc) - list(APPEND outfiles ${outfile}.bc) - - endforeach(srcfile) - - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.bc) - -endmacro(compile_wast) - -macro(add_wast_library) - cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS" ${ARGN}) - set(target ${ARG_TARGET}) - compile_wast(${ARGV}) - - get_filename_component("${ARG_TARGET}_BC_FILENAME" "${ARG_DESTINATION_FOLDER}/${ARG_TARGET}.bc" ABSOLUTE CACHE) - add_custom_target(${target} ALL DEPENDS ${${ARG_TARGET}_BC_FILENAME}) - - add_custom_command(OUTPUT ${${ARG_TARGET}_BC_FILENAME} - DEPENDS ${outfiles} - COMMAND ${WASM_LLVM_LINK} -o ${${ARG_TARGET}_BC_FILENAME} ${outfiles} - COMMENT "Linking LLVM bitcode library ${target}.bc" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - ) - -endmacro(add_wast_library) - -macro(add_wast_executable) - cmake_parse_arguments(ARG "NOWARNINGS" "TARGET;DESTINATION_FOLDER;MAX_MEMORY" "SOURCE_FILES;INCLUDE_FOLDERS;SYSTEM_INCLUDE_FOLDERS;LIBRARIES" ${ARGN}) - set(target ${ARG_TARGET}) - set(DESTINATION_FOLDER ${ARG_DESTINATION_FOLDER}) - - compile_wast(${ARGV}) - - foreach(lib ${ARG_LIBRARIES}) - list(APPEND LIBRARIES ${${lib}_BC_FILENAME}) - endforeach() - add_custom_command(OUTPUT ${target}.bc - DEPENDS ${outfiles} ${ARG_LIBRARIES} ${LIBRARIES} - COMMAND ${WASM_LLVM_LINK} -only-needed -o ${target}.bc ${outfiles} ${LIBRARIES} - COMMENT "Linking LLVM bitcode executable ${target}.bc" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - ) - - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.bc) - - add_custom_command(OUTPUT ${target}.s - DEPENDS ${target}.bc - COMMAND ${WASM_LLC} -thread-model=single -asm-verbose=false -o ${target}.s ${target}.bc - COMMENT "Generating textual assembly ${target}.s" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - ) - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.s) - - if(ARG_MAX_MEMORY) - set(MAX_MEMORY_PARAM "-m" ${ARG_MAX_MEMORY}) - endif() - - add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wast - DEPENDS ${target}.s - COMMAND $ -o ${DESTINATION_FOLDER}/${target}.wast -s 10240 ${MAX_MEMORY_PARAM} ${target}.s - COMMENT "Generating WAST ${target}.wast" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - ) - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.wast) - - add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wasm - DEPENDS ${target}.wast - COMMAND $ ${DESTINATION_FOLDER}/${target}.wast ${DESTINATION_FOLDER}/${target}.wasm -n - COMMENT "Generating WASM ${target}.wasm" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - ) - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.wasm) - - STRING (REPLACE "." "_" TARGET_VARIABLE "${target}") - - add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.wast.hpp - DEPENDS ${DESTINATION_FOLDER}/${target}.wast - COMMAND echo "const char* const ${TARGET_VARIABLE}_wast = R\"=====(" > ${DESTINATION_FOLDER}/${target}.wast.hpp - COMMAND cat ${DESTINATION_FOLDER}/${target}.wast >> ${DESTINATION_FOLDER}/${target}.wast.hpp - COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.wast.hpp - COMMENT "Generating ${target}.wast.hpp" - VERBATIM - ) - - if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${target}.abi ) - add_custom_command(OUTPUT ${DESTINATION_FOLDER}/${target}.abi.hpp - DEPENDS ${DESTINATION_FOLDER}/${target}.abi - COMMAND echo "const char* const ${TARGET_VARIABLE}_abi = R\"=====(" > ${DESTINATION_FOLDER}/${target}.abi.hpp - COMMAND cat ${DESTINATION_FOLDER}/${target}.abi >> ${DESTINATION_FOLDER}/${target}.abi.hpp - COMMAND echo ")=====\";" >> ${DESTINATION_FOLDER}/${target}.abi.hpp - COMMENT "Generating ${target}.abi.hpp" - VERBATIM - ) - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${target}.abi.hpp) - set(extra_target_dependency ${DESTINATION_FOLDER}/${target}.abi.hpp) - else() - endif() - - add_custom_target(${target} ALL DEPENDS ${DESTINATION_FOLDER}/${target}.wast.hpp ${extra_target_dependency} ${DESTINATION_FOLDER}/${target}.wasm) - - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${DESTINATION_FOLDER}/${target}.wast.hpp) - - set_property(TARGET ${target} PROPERTY INCLUDE_DIRECTORIES ${ARG_INCLUDE_FOLDERS}) - - set(extra_target_dependency) - - # For CLion code insight - foreach(folder ${ARG_INCLUDE_FOLDERS}) - include_directories(${folder}) - endforeach() - include_directories(${Boost_INCLUDE_DIR}) - - if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${target}.hpp) - set(HEADER_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${target}.hpp) - endif() - file(GLOB HEADER_FILES ${ARG_INCLUDE_FOLDERS}/*.hpp ${SYSTEM_INCLUDE_FOLDERS}/*.hpp) - add_executable(${target}.tmp EXCLUDE_FROM_ALL ${SOURCE_FILES} ${HEADER_FILE} ${HEADER_FILES}) - - add_test(NAME "validate_${target}_abi" - COMMAND ${CMAKE_BINARY_DIR}/scripts/abi_is_json.py ${ABI_FILES}) - -endmacro(add_wast_executable) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index ea21477cc51..6cce1a12bf4 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -14,7 +14,6 @@ FROM ubuntu:18.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/lib/* /usr/local/lib/ COPY --from=builder /tmp/build/bin /opt/eosio/bin -COPY --from=builder /tmp/build/contracts /contracts COPY --from=builder /eos/Docker/config.ini / COPY --from=builder /etc/eosio-version /etc COPY --from=builder /eos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh diff --git a/LICENSE b/LICENSE index 55e80764e3a..1516b96cbdf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018, Respective Authors all rights reserved. +Copyright (c) 2019 Respective Authors all rights reserved. The MIT License diff --git a/README.md b/README.md index 52bb6b3706a..454d3ed56d7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Some of the groundbreaking features of EOSIO include: 1. Low Latency Block confirmation (0.5 seconds) 1. Low-overhead Byzantine Fault Tolerant Finality 1. Designed for optional high-overhead, low-latency BFT finality -1. Smart contract platform powered by Web Assembly +1. Smart contract platform powered by WebAssembly 1. Designed for Sparse Header Light Client Validation 1. Scheduled Recurring Transactions 1. Time Delay Security @@ -92,4 +92,4 @@ EOSIO currently supports the following operating systems: ## Getting Started -Instructions detailing the process of getting the software, building it, running a simple test network that produces blocks, account creation and uploading a sample contract to the blockchain can be found in [Getting Started](https://developers.eos.io/eosio-nodeos/docs/overview-1) on the [EOSIO Developer Portal](https://developers.eos.io). +Instructions detailing the process of getting the software, building it, running a simple test network that produces blocks, account creation and uploading a sample contract to the blockchain can be found in [Getting Started](https://developers.eos.io/eosio-home/docs) on the [EOSIO Developer Portal](https://developers.eos.io). diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt deleted file mode 100644 index 443330c886a..00000000000 --- a/contracts/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -# will be implictly used for any compilation unit if not overrided by SYSTEM_INCLUDE_FOLDERS parameter -# these directories go as -isystem to avoid warnings from code of third-party libraries -set(DEFAULT_SYSTEM_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts/libc++/upstream/include ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include ${Boost_INCLUDE_DIR}) - -set(STANDARD_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts ${CMAKE_BINARY_DIR}/contracts ${CMAKE_SOURCE_DIR}/externals/magic_get/include) - -add_subdirectory(eosiolib) -add_subdirectory(musl) -add_subdirectory(libc++) -add_subdirectory(eosio.token) -add_subdirectory(eosio.msig) -add_subdirectory(eosio.sudo) -add_subdirectory(multi_index_test) -add_subdirectory(snapshot_test) -add_subdirectory(eosio.system) -add_subdirectory(identity) -add_subdirectory(stltest) -add_subdirectory(test.inline) - -add_subdirectory(hello) -add_subdirectory(asserter) -add_subdirectory(proxy) -add_subdirectory(test_api) -add_subdirectory(test_api_mem) -add_subdirectory(test_api_db) -add_subdirectory(test_api_multi_index) -add_subdirectory(test_ram_limit) -add_subdirectory(eosio.bios) -add_subdirectory(noop) -add_subdirectory(tic_tac_toe) -add_subdirectory(payloadless) -add_subdirectory(integration_test) - - -file(GLOB SKELETONS RELATIVE ${CMAKE_SOURCE_DIR}/contracts "skeleton/*") - -# Documented multiple output support is broken, so properly setting up the multiple -# dependencies in the custom target is not possible. (CMake 3.5) -add_custom_command(OUTPUT share/eosio/skeleton/skeleton.cpp - COMMAND ${CMAKE_COMMAND} -E make_directory ../share/eosio/skeleton - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/skeleton ../share/eosio/skeleton - DEPENDS ${SKELETONS} - COMMENT Copying skeleton contract... - VERBATIM) -add_custom_target(copy_skeleton_contract ALL DEPENDS share/eosio/skeleton/skeleton.cpp) diff --git a/contracts/asserter/CMakeLists.txt b/contracts/asserter/CMakeLists.txt deleted file mode 100644 index e73595af1de..00000000000 --- a/contracts/asserter/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET asserter - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc libc++ eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/asserter/asserter.cpp b/contracts/asserter/asserter.cpp deleted file mode 100644 index c89db1fc709..00000000000 --- a/contracts/asserter/asserter.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ - -#include /// defines assert_def struct (abi) - -using namespace asserter; - -static int global_variable = 45; - -extern "C" { - /// The apply method implements the dispatch of events to this contract - void apply( uint64_t /* receiver */, uint64_t code, uint64_t action ) { - require_auth(code); - if( code == N(asserter) ) { - if( action == N(procassert) ) { - assertdef def = eosio::unpack_action_data(); - - // maybe assert? - eosio_assert((uint32_t)def.condition, def.message.c_str()); - } else if( action == N(provereset) ) { - eosio_assert(global_variable == 45, "Global Variable Initialized poorly"); - global_variable = 100; - } - } - } -} diff --git a/contracts/eosio.bios/CMakeLists.txt b/contracts/eosio.bios/CMakeLists.txt deleted file mode 100644 index ae5ea158406..00000000000 --- a/contracts/eosio.bios/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET eosio.bios - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/eosio.bios/eosio.bios.abi b/contracts/eosio.bios/eosio.bios.abi deleted file mode 100644 index 2dd3310fc67..00000000000 --- a/contracts/eosio.bios/eosio.bios.abi +++ /dev/null @@ -1,263 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - },{ - "new_type_name": "permission_name", - "type": "name" - },{ - "new_type_name": "action_name", - "type": "name" - },{ - "new_type_name": "transaction_id_type", - "type": "checksum256" - },{ - "new_type_name": "weight_type", - "type": "uint16" - }], - "structs": [{ - "name": "permission_level", - "base": "", - "fields": [ - {"name":"actor", "type":"account_name"}, - {"name":"permission", "type":"permission_name"} - ] - },{ - "name": "key_weight", - "base": "", - "fields": [ - {"name":"key", "type":"public_key"}, - {"name":"weight", "type":"weight_type"} - ] - },{ - "name": "permission_level_weight", - "base": "", - "fields": [ - {"name":"permission", "type":"permission_level"}, - {"name":"weight", "type":"weight_type"} - ] - },{ - "name": "wait_weight", - "base": "", - "fields": [ - {"name":"wait_sec", "type":"uint32"}, - {"name":"weight", "type":"weight_type"} - ] - },{ - "name": "authority", - "base": "", - "fields": [ - {"name":"threshold", "type":"uint32"}, - {"name":"keys", "type":"key_weight[]"}, - {"name":"accounts", "type":"permission_level_weight[]"}, - {"name":"waits", "type":"wait_weight[]"} - ] - },{ - "name": "blockchain_parameters", - "base": "", - "fields": [ - {"name":"max_block_net_usage", "type":"uint64"}, - {"name":"target_block_net_usage_pct", "type":"uint32"}, - {"name":"max_transaction_net_usage", "type":"uint32"}, - {"name":"base_per_transaction_net_usage", "type":"uint32"}, - {"name":"net_usage_leeway", "type":"uint32"}, - {"name":"context_free_discount_net_usage_num", "type":"uint32"}, - {"name":"context_free_discount_net_usage_den", "type":"uint32"}, - {"name":"max_block_cpu_usage", "type":"uint32"}, - {"name":"target_block_cpu_usage_pct", "type":"uint32"}, - {"name":"max_transaction_cpu_usage", "type":"uint32"}, - {"name":"min_transaction_cpu_usage", "type":"uint32"}, - {"name":"max_transaction_lifetime", "type":"uint32"}, - {"name":"deferred_trx_expiration_window", "type":"uint32"}, - {"name":"max_transaction_delay", "type":"uint32"}, - {"name":"max_inline_action_size", "type":"uint32"}, - {"name":"max_inline_action_depth", "type":"uint16"}, - {"name":"max_authority_depth", "type":"uint16"} - ] - },{ - "name": "newaccount", - "base": "", - "fields": [ - {"name":"creator", "type":"account_name"}, - {"name":"name", "type":"account_name"}, - {"name":"owner", "type":"authority"}, - {"name":"active", "type":"authority"} - ] - },{ - "name": "setcode", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"vmtype", "type":"uint8"}, - {"name":"vmversion", "type":"uint8"}, - {"name":"code", "type":"bytes"} - ] - },{ - "name": "setabi", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"abi", "type":"bytes"} - ] - },{ - "name": "updateauth", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"permission", "type":"permission_name"}, - {"name":"parent", "type":"permission_name"}, - {"name":"auth", "type":"authority"} - ] - },{ - "name": "deleteauth", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"permission", "type":"permission_name"} - ] - },{ - "name": "linkauth", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"code", "type":"account_name"}, - {"name":"type", "type":"action_name"}, - {"name":"requirement", "type":"permission_name"} - ] - },{ - "name": "unlinkauth", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"code", "type":"account_name"}, - {"name":"type", "type":"action_name"} - ] - },{ - "name": "canceldelay", - "base": "", - "fields": [ - {"name":"canceling_auth", "type":"permission_level"}, - {"name":"trx_id", "type":"transaction_id_type"} - ] - },{ - "name": "onerror", - "base": "", - "fields": [ - {"name":"sender_id", "type":"uint128"}, - {"name":"sent_trx", "type":"bytes"} - ] - },{ - "name": "set_account_limits", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"ram_bytes", "type":"int64"}, - {"name":"net_weight", "type":"int64"}, - {"name":"cpu_weight", "type":"int64"} - ] - },{ - "name": "setpriv", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"is_priv", "type":"int8"} - ] - },{ - "name": "set_global_limits", - "base": "", - "fields": [ - {"name":"cpu_usec_per_period", "type":"int64"} - ] - },{ - "name": "producer_key", - "base": "", - "fields": [ - {"name":"producer_name", "type":"account_name"}, - {"name":"block_signing_key", "type":"public_key"} - ] - },{ - "name": "set_producers", - "base": "", - "fields": [ - {"name":"schedule", "type":"producer_key[]"} - ] - },{ - "name": "setparams", - "base": "", - "fields": [ - {"name":"params", "type":"blockchain_parameters"} - ] - },{ - "name": "require_auth", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"} - ] - }], - "actions": [{ - "name": "newaccount", - "type": "newaccount", - "ricardian_contract": "" - },{ - "name": "setcode", - "type": "setcode", - "ricardian_contract": "" - },{ - "name": "setabi", - "type": "setabi", - "ricardian_contract": "" - },{ - "name": "updateauth", - "type": "updateauth", - "ricardian_contract": "" - },{ - "name": "deleteauth", - "type": "deleteauth", - "ricardian_contract": "" - },{ - "name": "linkauth", - "type": "linkauth", - "ricardian_contract": "" - },{ - "name": "unlinkauth", - "type": "unlinkauth", - "ricardian_contract": "" - },{ - "name": "canceldelay", - "type": "canceldelay", - "ricardian_contract": "" - },{ - "name": "onerror", - "type": "onerror", - "ricardian_contract": "" - },{ - "name": "setalimits", - "type": "set_account_limits", - "ricardian_contract": "" - },{ - "name": "setglimits", - "type": "set_global_limits", - "ricardian_contract": "" - },{ - "name": "setpriv", - "type": "setpriv", - "ricardian_contract": "" - },{ - "name": "setprods", - "type": "set_producers", - "ricardian_contract": "" - },{ - "name": "setparams", - "type": "setparams", - "ricardian_contract": "" - },{ - "name": "reqauth", - "type": "require_auth", - "ricardian_contract": "" - } - ], - "tables": [], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/eosio.bios/eosio.bios.cpp b/contracts/eosio.bios/eosio.bios.cpp deleted file mode 100644 index 66d70f0c47e..00000000000 --- a/contracts/eosio.bios/eosio.bios.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -EOSIO_ABI( eosio::bios, (setpriv)(setalimits)(setglimits)(setprods)(setparams)(reqauth) ) diff --git a/contracts/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/eosio.bios.hpp deleted file mode 100644 index 0abca64c90e..00000000000 --- a/contracts/eosio.bios/eosio.bios.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include -#include - -namespace eosio { - - class bios : public contract { - public: - bios( action_name self ):contract(self){} - - void setpriv( account_name account, uint8_t ispriv ) { - require_auth( _self ); - set_privileged( account, ispriv ); - } - - void setalimits( account_name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ) { - require_auth( _self ); - set_resource_limits( account, ram_bytes, net_weight, cpu_weight ); - } - - void setglimits( uint64_t ram, uint64_t net, uint64_t cpu ) { - (void)ram; (void)net; (void)cpu; - require_auth( _self ); - } - - void setprods( std::vector schedule ) { - (void)schedule; // schedule argument just forces the deserialization of the action data into vector (necessary check) - require_auth( _self ); - - constexpr size_t max_stack_buffer_size = 512; - size_t size = action_data_size(); - char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); - read_action_data( buffer, size ); - set_proposed_producers(buffer, size); - } - - void setparams( const eosio::blockchain_parameters& params ) { - require_auth( _self ); - set_blockchain_parameters( params ); - } - - void reqauth( action_name from ) { - require_auth( from ); - } - - private: - }; - -} /// namespace eosio diff --git a/contracts/eosio.msig/CMakeLists.txt b/contracts/eosio.msig/CMakeLists.txt deleted file mode 100644 index afcf7038f1a..00000000000 --- a/contracts/eosio.msig/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ - -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET eosio.msig - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/eosio.msig/README.md b/contracts/eosio.msig/README.md deleted file mode 100644 index 6857660782e..00000000000 --- a/contracts/eosio.msig/README.md +++ /dev/null @@ -1,113 +0,0 @@ -eosio.msig --------- - -Actions: -The naming convention is codeaccount::actionname followed by a list of paramters. - -Create a proposal -## eosio.msig::propose proposer proposal_name requested trx - - **proposer** account proposing a transaction - - **proposal_name** name of the proposal (should be unique for proposer) - - **requested** permission levels expected to approve the proposal - - **trx** proposed transaction - - Storage changes are billed to 'proposer' - -Approve a proposal -## eosio.msig::approve proposer proposal_name level - - **proposer** account proposing a transaction - - **proposal_name** name of the proposal - - **level** permission level approving the transaction - - Storage changes are billed to 'proposer' - -Revoke an approval of transaction -## eosio.msig::unapprove proposer proposal_name level - - **proposer** account proposing a transaction - - **proposal_name** name of the proposal - - **level** permission level revoking approval from the transaction - - Storage changes are billed to 'proposer' - -Cancel a proposal -## eosio.msig::cancel proposer proposal_name canceler - - **proposer** account proposing a transaction - - **proposal_name** name of the proposal - - **canceler** account canceling the transaction (only proposer can cancel not expired transaction) - -Execute a proposal -## eosio.msig::exec proposer proposal_name executer - - **proposer** account proposing a transaction - - **proposal_name** name of the proposal - - **executer** account executing the transaction - - -Cleos usage example. - -Prerequisites: - - eosio.token contract installed to eosio.token account, eosio.msig contract installed on eosio.msig account which is a privileged account. - - account 'treasury' is the issuer of EOS token. - - account 'tester' exists. - - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked. - -One user creates a proposal: -```` -$ cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token issue '{"to": "tester", "quantity": "1000.0000 EOS", "memo": ""}' -p tester -executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb183d61 336 bytes 107520 cycles -# eosio.msig <= eosio.msig::propose {"proposer":"tester","proposal_name":"test","requested":[{"actor":"treasury","permission":"active"}]... -```` - -Another user reviews the transaction: -```` -$ cleos multisig review tester test -p treasury -{ - "proposal_name": "test", - "requested_approvals": [{ - "actor": "treasury", - "permission": "active" - } - ], - "provided_approvals": [], - "packed_transaction": "00aee75a0000000000000000000000000100a6823403ea30550000000000a5317601000000fe6a6cd4cd00000000a8ed323219000000005c95b1ca809698000000000004454f530000000000", - "transaction": { - "expiration": "2018-05-01T00:00:00", - "region": 0, - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_kcpu_usage": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio.token", - "name": "issue", - "authorization": [{ - "actor": "treasury", - "permission": "active" - } - ], - "data": { - "to": "tester", - "quantity": "1000.0000 EOS", - "memo": "" - }, - "hex_data": "000000005c95b1ca809698000000000004454f530000000000" - } - ] - } -} -```` - -And then approves it: -```` -$ cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury -executed transaction: 475970a4b0016368d0503d1ce01577376f91f5a5ba63dd4353683bd95101b88d 256 bytes 108544 cycles -# eosio.msig <= eosio.msig::approve {"proposer":"tester","proposal_name":"test","level":{"actor":"treasury","permission":"active"}} -```` - -First user initiates execution: -```` -$ cleos multisig exec tester test -p tester -executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e56d6c2 248 bytes 109568 cycles -# eosio.msig <= eosio.msig::exec {"proposer":"tester","proposal_name":"test","executer":"tester"} -```` diff --git a/contracts/eosio.msig/eosio.msig.abi b/contracts/eosio.msig/eosio.msig.abi deleted file mode 100644 index 9fcf8a957cc..00000000000 --- a/contracts/eosio.msig/eosio.msig.abi +++ /dev/null @@ -1,152 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - },{ - "new_type_name": "permission_name", - "type": "name" - },{ - "new_type_name": "action_name", - "type": "name" - }], - "structs": [{ - "name": "permission_level", - "base": "", - "fields": [ - {"name": "actor", "type": "account_name"}, - {"name": "permission", "type": "permission_name"} - ] - },{ - "name": "action", - "base": "", - "fields": [ - {"name": "account", "type": "account_name"}, - {"name": "name", "type": "action_name"}, - {"name": "authorization", "type": "permission_level[]"}, - {"name": "data", "type": "bytes"} - ] - },{ - "name": "transaction_header", - "base": "", - "fields": [ - {"name": "expiration", "type": "time_point_sec"}, - {"name": "ref_block_num", "type": "uint16"}, - {"name": "ref_block_prefix", "type": "uint32"}, - {"name": "max_net_usage_words", "type": "varuint32"}, - {"name": "max_cpu_usage_ms", "type": "uint8"}, - {"name": "delay_sec", "type": "varuint32"} - ] - },{ - "name": "extension", - "base": "", - "fields": [ - {"name": "type", "type" : "uint16" }, - {"name": "data", "type": "bytes"} - ] - },{ - "name": "transaction", - "base": "transaction_header", - "fields": [ - {"name": "context_free_actions", "type": "action[]"}, - {"name": "actions", "type": "action[]"}, - {"name": "transaction_extensions", "type": "extension[]"} - ] - },{ - "name": "propose", - "base": "", - "fields": [ - {"name":"proposer", "type":"account_name"}, - {"name":"proposal_name", "type":"name"}, - {"name":"requested", "type":"permission_level[]"}, - {"name":"trx", "type":"transaction"} - ] - },{ - "name": "approve", - "base": "", - "fields": [ - {"name":"proposer", "type":"account_name"}, - {"name":"proposal_name", "type":"name"}, - {"name":"level", "type":"permission_level"} - ] - },{ - "name": "unapprove", - "base": "", - "fields": [ - {"name":"proposer", "type":"account_name"}, - {"name":"proposal_name", "type":"name"}, - {"name":"level", "type":"permission_level"} - ] - },{ - "name": "cancel", - "base": "", - "fields": [ - {"name":"proposer", "type":"account_name"}, - {"name":"proposal_name", "type":"name"}, - {"name":"canceler", "type":"account_name"} - ] - },{ - "name": "exec", - "base": "", - "fields": [ - {"name":"proposer", "type":"account_name"}, - {"name":"proposal_name", "type":"name"}, - {"name":"executer", "type":"account_name"} - ] - },{ - "name": "proposal", - "base": "", - "fields": [ - {"name": "proposal_name", "type": "name"}, - {"name": "packed_transaction", "type": "bytes"} - ] - },{ - "name": "approvals_info", - "base": "", - "fields": [ - {"name": "proposal_name", "type": "name"}, - {"name": "requested_approvals", "type": "permission_level[]"}, - {"name": "provided_approvals", "type": "permission_level[]"} - ] - } - ], - "actions": [{ - "name": "propose", - "type": "propose", - "ricardian_contract": "" - },{ - "name": "approve", - "type": "approve", - "ricardian_contract": "" - },{ - "name": "unapprove", - "type": "unapprove", - "ricardian_contract": "" - }, { - "name": "cancel", - "type": "cancel", - "ricardian_contract": "" - }, { - "name": "exec", - "type": "exec", - "ricardian_contract": "" - } - - ], - "tables": [{ - "name": "proposal", - "type": "proposal", - "index_type": "i64", - "key_names" : ["proposal_name"], - "key_types" : ["name"] - },{ - "name": "approvals", - "type": "approvals_info", - "index_type": "i64", - "key_names" : ["proposal_name"], - "key_types" : ["name"] - } - ], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/eosio.msig/eosio.msig.cpp b/contracts/eosio.msig/eosio.msig.cpp deleted file mode 100644 index 9d04a1a9813..00000000000 --- a/contracts/eosio.msig/eosio.msig.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include -#include -#include - -namespace eosio { - -/* -propose function manually parses input data (instead of taking parsed arguments from dispatcher) -because parsing data in the dispatcher uses too much CPU in case if proposed transaction is big - -If we use dispatcher the function signature should be: - -void multisig::propose( account_name proposer, - name proposal_name, - vector requested, - transaction trx) -*/ - -void multisig::propose() { - constexpr size_t max_stack_buffer_size = 512; - size_t size = action_data_size(); - char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); - read_action_data( buffer, size ); - - account_name proposer; - name proposal_name; - vector requested; - transaction_header trx_header; - - datastream ds( buffer, size ); - ds >> proposer >> proposal_name >> requested; - - size_t trx_pos = ds.tellp(); - ds >> trx_header; - - require_auth( proposer ); - eosio_assert( trx_header.expiration >= eosio::time_point_sec(now()), "transaction expired" ); - //eosio_assert( trx_header.actions.size() > 0, "transaction must have at least one action" ); - - proposals proptable( _self, proposer ); - eosio_assert( proptable.find( proposal_name ) == proptable.end(), "proposal with the same name exists" ); - - bytes packed_requested = pack(requested); - auto res = ::check_transaction_authorization( buffer+trx_pos, size-trx_pos, - (const char*)0, 0, - packed_requested.data(), packed_requested.size() - ); - eosio_assert( res > 0, "transaction authorization failed" ); - - proptable.emplace( proposer, [&]( auto& prop ) { - prop.proposal_name = proposal_name; - prop.packed_transaction = bytes( buffer+trx_pos, buffer+size ); - }); - - approvals apptable( _self, proposer ); - apptable.emplace( proposer, [&]( auto& a ) { - a.proposal_name = proposal_name; - a.requested_approvals = std::move(requested); - }); -} - -void multisig::approve( account_name proposer, name proposal_name, permission_level level ) { - require_auth( level ); - - approvals apptable( _self, proposer ); - auto& apps = apptable.get( proposal_name, "proposal not found" ); - - auto itr = std::find( apps.requested_approvals.begin(), apps.requested_approvals.end(), level ); - eosio_assert( itr != apps.requested_approvals.end(), "approval is not on the list of requested approvals" ); - - apptable.modify( apps, proposer, [&]( auto& a ) { - a.provided_approvals.push_back( level ); - a.requested_approvals.erase( itr ); - }); -} - -void multisig::unapprove( account_name proposer, name proposal_name, permission_level level ) { - require_auth( level ); - - approvals apptable( _self, proposer ); - auto& apps = apptable.get( proposal_name, "proposal not found" ); - auto itr = std::find( apps.provided_approvals.begin(), apps.provided_approvals.end(), level ); - eosio_assert( itr != apps.provided_approvals.end(), "no approval previously granted" ); - - apptable.modify( apps, proposer, [&]( auto& a ) { - a.requested_approvals.push_back(level); - a.provided_approvals.erase(itr); - }); -} - -void multisig::cancel( account_name proposer, name proposal_name, account_name canceler ) { - require_auth( canceler ); - - proposals proptable( _self, proposer ); - auto& prop = proptable.get( proposal_name, "proposal not found" ); - - if( canceler != proposer ) { - eosio_assert( unpack( prop.packed_transaction ).expiration < eosio::time_point_sec(now()), "cannot cancel until expiration" ); - } - - approvals apptable( _self, proposer ); - auto& apps = apptable.get( proposal_name, "proposal not found" ); - - proptable.erase(prop); - apptable.erase(apps); -} - -void multisig::exec( account_name proposer, name proposal_name, account_name executer ) { - require_auth( executer ); - - proposals proptable( _self, proposer ); - auto& prop = proptable.get( proposal_name, "proposal not found" ); - - approvals apptable( _self, proposer ); - auto& apps = apptable.get( proposal_name, "proposal not found" ); - - transaction_header trx_header; - datastream ds( prop.packed_transaction.data(), prop.packed_transaction.size() ); - ds >> trx_header; - eosio_assert( trx_header.expiration >= eosio::time_point_sec(now()), "transaction expired" ); - - bytes packed_provided_approvals = pack(apps.provided_approvals); - auto res = ::check_transaction_authorization( prop.packed_transaction.data(), prop.packed_transaction.size(), - (const char*)0, 0, - packed_provided_approvals.data(), packed_provided_approvals.size() - ); - eosio_assert( res > 0, "transaction authorization failed" ); - - send_deferred( (uint128_t(proposer) << 64) | proposal_name, executer, prop.packed_transaction.data(), prop.packed_transaction.size() ); - - proptable.erase(prop); - apptable.erase(apps); -} - -} /// namespace eosio - -EOSIO_ABI( eosio::multisig, (propose)(approve)(unapprove)(cancel)(exec) ) diff --git a/contracts/eosio.msig/eosio.msig.hpp b/contracts/eosio.msig/eosio.msig.hpp deleted file mode 100644 index 48ce2e3dca8..00000000000 --- a/contracts/eosio.msig/eosio.msig.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -#include - -namespace eosio { - - class multisig : public contract { - public: - multisig( account_name self ):contract(self){} - - void propose(); - void approve( account_name proposer, name proposal_name, permission_level level ); - void unapprove( account_name proposer, name proposal_name, permission_level level ); - void cancel( account_name proposer, name proposal_name, account_name canceler ); - void exec( account_name proposer, name proposal_name, account_name executer ); - - private: - struct proposal { - name proposal_name; - vector packed_transaction; - - auto primary_key()const { return proposal_name.value; } - }; - typedef eosio::multi_index proposals; - - struct approvals_info { - name proposal_name; - vector requested_approvals; - vector provided_approvals; - - auto primary_key()const { return proposal_name.value; } - }; - typedef eosio::multi_index approvals; - }; - -} /// namespace eosio diff --git a/contracts/eosio.sudo/CMakeLists.txt b/contracts/eosio.sudo/CMakeLists.txt deleted file mode 100644 index 3760b6e82e2..00000000000 --- a/contracts/eosio.sudo/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ - -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET eosio.sudo - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/eosio.sudo/README.md b/contracts/eosio.sudo/README.md deleted file mode 100644 index af1031e0126..00000000000 --- a/contracts/eosio.sudo/README.md +++ /dev/null @@ -1,886 +0,0 @@ -# eosio.sudo - -## 1. Actions: -The naming convention is codeaccount::actionname followed by a list of parameters. - -Execute a transaction while bypassing regular authorization checks (requires authorization of eosio.sudo which needs to be a privileged account). - -### eosio.sudo::exec executer trx - - **executer** account executing the transaction - - **trx** transaction to execute - - Deferred transaction RAM usage is billed to 'executer' - - -## 2. Installing the eosio.sudo contract - -The eosio.sudo contract needs to be installed on a privileged account to function. It is recommended to use the account `eosio.sudo`. - -First, the account `eosio.sudo` needs to be created. Since it has the restricted `eosio.` prefix, only a privileged account can create this account. So this guide will use the `eosio` account to create the `eosio.sudo` account. On typical live blockchain configurations, the `eosio` account can only be controlled by a supermajority of the current active block producers. So, this guide will use the `eosio.msig` contract to help coordinate the approvals of the proposed transaction that creates the `eosio.sudo` account. - -The `eosio.sudo` account also needs to have sufficient RAM to host the contract and sufficient CPU and network bandwidth to deploy the contract. This means that the creator of the account (`eosio`) needs to gift sufficient RAM to the new account and delegate (preferably with transfer) sufficient bandwidth to the new account. To pull this off the `eosio` account needs to have enough of the core system token (the `SYS` token will be used within this guide) in its liquid balance. So prior to continuing with the next steps of this guide, the active block producers of the chain who are coordinating this process need to ensure that a sufficient amount of core system tokens that they are authorized to spend is placed in the liquid balance of the `eosio` account. - -This guide will be using cleos to carry out the process. - -### 2.1 Create the eosio.sudo account - -#### 2.1.1 Generate the transaction to create the eosio.sudo account - -The transaction to create the `eosio.sudo` account will need to be proposed to get the necessary approvals from active block producers before executing it. This transaction needs to first be generated and stored as JSON into a file so that it can be used in the cleos command to propose the transaction to the eosio.msig contract. - -A simple way to generate a transaction to create a new account is to use the `cleos system newaccount`. However, that sub-command currently only accepts a single public key as the owner and active authority of the new account. However, the owner and active authorities of the new account should only be satisfied by the `active` permission of `eosio`. One option is to create the new account with the some newly generated key, and then later update the authorities of the new account using `cleos set account permission`. This guide will take an alternative approach which atomically creates the new account in its proper configuration. - -Three unsigned transactions will be generated using cleos and then the actions within those transactions will be appropriately stitched together into a single transaction which will later be proposed using the eosio.msig contract. - -First, generate a transaction to capture the necessary actions involved in creating a new account: -``` -$ cleos system newaccount -s -j -d --transfer --stake-net "1.000 SYS" --stake-cpu "1.000 SYS" --buy-ram-kbytes 50 eosio eosio.sudo EOS8MMUW11TAdTDxqdSwSqJodefSoZbFhcprndomgLi9MeR2o8MT4 > generated_account_creation_trx.json -726964ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea305500c80000"} arg: {"code":"eosio","action":"buyrambytes","args":{"payer":"eosio","receiver":"eosio.sudo","bytes":51200}} -726967ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001"} arg: {"code":"eosio","action":"delegatebw","args":{"from":"eosio","receiver":"eosio.sudo","stake_net_quantity":"1.0000 SYS","stake_cpu_quantity":"1.0000 SYS","transfer":true}} -$ cat generated_account_creation_trx.json -{ - "expiration": "2018-06-29T17:11:36", - "ref_block_num": 16349, - "ref_block_prefix": 3248946195, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "newaccount", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "0000000000ea305500004d1a03ea305501000000010003c8162ea04fed738bfd5470527fd1ae7454c2e9ad1acbadec9f9e35bab2f33c660100000001000000010003c8162ea04fed738bfd5470527fd1ae7454c2e9ad1acbadec9f9e35bab2f33c6601000000" - },{ - "account": "eosio", - "name": "buyrambytes", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "0000000000ea305500004d1a03ea305500c80000" - },{ - "account": "eosio", - "name": "delegatebw", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` -Adjust the amount of delegated tokens and the amount of RAM bytes to gift as necessary. -The actual public key used is not important since that data is only encoded into the `eosio::newaccount` action which will be replaced soon anyway. - -Second, create a file (e.g. newaccount_payload.json) with the JSON payload for the real `eosio::newaccount` action. It should look like: -``` -$ cat newaccount_payload.json -{ - "creator": "eosio", - "name": "eosio.sudo", - "owner": { - "threshold": 1, - "keys": [], - "accounts": [{ - "permission": {"actor": "eosio", "permission": "active"}, - "weight": 1 - }], - "waits": [] - }, - "active": { - "threshold": 1, - "keys": [], - "accounts": [{ - "permission": {"actor": "eosio", "permission": "active"}, - "weight": 1 - }], - "waits": [] - } -} -``` - -Third, generate a transaction containing the actual `eosio::newaccount` action that will be used in the final transaction: -``` -$ cleos push action -s -j -d eosio newaccount newaccount_payload.json -p eosio > generated_newaccount_trx.json -$ cat generated_newaccount_trx.json -{ - "expiration": "2018-06-29T17:11:36", - "ref_block_num": 16349, - "ref_block_prefix": 3248946195, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "newaccount", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "0000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed3232010000" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` - -Fourth, generate a transaction containing the `eosio::setpriv` action which will make the `eosio.sudo` account privileged: -``` -$ cleos push action -s -j -d eosio setpriv '{"account": "eosio.sudo", "is_priv": 1}' -p eosio > generated_setpriv_trx.json -$ cat generated_setpriv_trx.json -{ - "expiration": "2018-06-29T17:11:36", - "ref_block_num": 16349, - "ref_block_prefix": 3248946195, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "setpriv", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "00004d1a03ea305501" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` - -Next, the action JSONs of the previously generated transactions will be used to construct a unified transaction which will eventually be proposed with the eosio.msig contract. A good way to get started is to make a copy of the generated_newaccount_trx.json file (call the copied file create_sudo_account_trx.json) and edit the first three fields so it looks something like the following: -``` -$ cat create_sudo_account_trx.json -{ - "expiration": "2018-07-06T12:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "newaccount", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "0000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed3232010000" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` - -The `ref_block_num` and `ref_block_prefix` values were set to 0. The proposed transaction does not need to have a valid TaPoS reference block because it will be reset anyway when scheduled as a deferred transaction during the `eosio.msig::exec` action. The `expiration` field, which was the only other field that was changed, will also be reset when the proposed transaction is scheduled as a deferred transaction during `eosio.msig::exec`. However, this field actually does matter during the propose-approve-exec lifecycle of the proposed transaction. If the present time passes the time in the `expiration` field of the proposed transaction, it will not be possible to execute the proposed transaction even if all necessary approvals are gathered. Therefore, it is important to set the expiration time to some point well enough in the future to give all necessary approvers enough time to review and approve the proposed transaction, but it is otherwise arbitrary. Generally, for reviewing/validation purposes it is important that all potential approvers of the transaction (i.e. the block producers) choose the exact same `expiration` time so that there is not any discrepancy in bytes of the serialized transaction if it was to later be included in payload data of some other action. - -Then, all but the first action JSON object of generated_account_creation_trx.json should be appended to the `actions` array of create_sudo_account_trx.json, and then the single action JSON object of generated_setpriv_trx.json should be appended to the `actions` array of create_sudo_account_trx.json. The final result is a create_sudo_account_trx.json file that looks like the following: -``` -$ cat create_sudo_account_trx.json -{ - "expiration": "2018-07-06T12:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "newaccount", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "0000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed3232010000" - },{ - "account": "eosio", - "name": "buyrambytes", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "0000000000ea305500004d1a03ea305500c80000" - },{ - "account": "eosio", - "name": "delegatebw", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001" - },{ - "account": "eosio", - "name": "setpriv", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": "00004d1a03ea305501" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` - -The transaction in create_sudo_account_trx.json is now ready to be proposed. - -It will be useful to have a JSON of the active permissions of each of the active block producers for later when proposing transactions using the eosio.msig contract. - -This guide will assume that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. - -In that case, create a file producer_permissions.json with the content shown in the command below: -``` -$ cat producer_permissions.json -[ - {"actor": "blkproducera", "permission": "active"}, - {"actor": "blkproducerb", "permission": "active"}, - {"actor": "blkproducerc", "permission": "active"}, - {"actor": "blkproducerd", "permission": "active"}, - {"actor": "blkproducere", "permission": "active"}, - {"actor": "blkproducerf", "permission": "active"}, - {"actor": "blkproducerg", "permission": "active"}, - {"actor": "blkproducerh", "permission": "active"}, - {"actor": "blkproduceri", "permission": "active"}, - {"actor": "blkproducerj", "permission": "active"}, - {"actor": "blkproducerk", "permission": "active"}, - {"actor": "blkproducerl", "permission": "active"}, - {"actor": "blkproducerm", "permission": "active"}, - {"actor": "blkproducern", "permission": "active"}, - {"actor": "blkproducero", "permission": "active"}, - {"actor": "blkproducerp", "permission": "active"}, - {"actor": "blkproducerq", "permission": "active"}, - {"actor": "blkproducerr", "permission": "active"}, - {"actor": "blkproducers", "permission": "active"}, - {"actor": "blkproducert", "permission": "active"}, - {"actor": "blkproduceru", "permission": "active"} -] -``` - -#### 2.1.2 Propose the transaction to create the eosio.sudo account - -Only one of the potential approvers will need to propose the transaction that was created in the previous sub-section. All the other approvers should still follow the steps in the previous sub-section to generate the same create_sudo_account_trx.json file as all the other approvers. They will need this to compare to the actual proposed transaction prior to approving. - -The approvers are typically going to be the active block producers of the chain, so it makes sense that one of the block producers is elected as the leader to propose the actual transaction. Note that this lead block producer will need to incur the temporary RAM cost of proposing the transaction, but they will get the RAM back when the proposal has executed or has been canceled (which only the proposer can do prior to expiration). - -The guide will assume that `blkproducera` was chosen as the lead block producer to propose the transaction. - -The lead block producer (`blkproducera`) should propose the transaction stored in create_sudo_account_trx.json: -``` -$ cleos multisig propose_trx createsudo producer_permissions.json create_sudo_account_trx.json blkproducera -executed transaction: bf6aaa06b40e2a35491525cb11431efd2b5ac94e4a7a9c693c5bf0cfed942393 744 bytes 772 us -# eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"createsudo","requested":[{"actor":"blkproducera","permis... -warning: transaction executed locally, but may not be confirmed by the network yet -``` - -#### 2.1.3 Review and approve the transaction to create the eosio.sudo account - -Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. - -The proposed transaction can be reviewed using the `cleos multisig review` command: -``` -$ cleos multisig review blkproducera createsudo > create_sudo_account_trx_to_review.json -$ head -n 30 create_sudo_account_trx_to_review.json -{ - "proposal_name": "createsudo", - "packed_transaction": "c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100", - "transaction": { - "expiration": "2018-07-06T12:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "newaccount", - "authorization": [{ - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "creator": "eosio", - "name": "eosio.sudo", - "owner": { - "threshold": 1, - "keys": [], - "accounts": [{ - "permission": { - "actor": "eosio", - "permission": "active" - }, -``` - -The approvers should go through the full human-readable transaction output and make sure everything looks fine. But they can also use tools to automatically compare the proposed transaction to the one they generated to make sure there are absolutely no differences: -``` -$ cleos multisig propose_trx -j -s -d createsudo '[]' create_sudo_account_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_create_sudo_trx_serialized.hex -$ cat expected_create_sudo_trx_serialized.hex -c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100 -$ cat create_sudo_account_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_create_sudo_trx_serialized.hex -$ cat proposed_create_sudo_trx_serialized.hex -c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100 -$ diff expected_create_sudo_trx_serialized.hex proposed_create_sudo_trx_serialized.hex -``` - -When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: -``` -$ cleos multisig approve blkproducera createsudo '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb -executed transaction: 03a907e2a3192aac0cd040c73db8273c9da7696dc7960de22b1a479ae5ee9f23 128 bytes 472 us -# eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"createsudo","level":{"actor":"blkproducerb","permission"... -warning: transaction executed locally, but may not be confirmed by the network yet -``` - -#### 2.1.4 Execute the transaction to create the eosio.sudo account - -When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). - -``` -$ cleos multisig exec blkproducera createsudo blkproducera -executed transaction: 7ecc183b99915cc411f96dde7c35c3fe0df6e732507f272af3a039b706482e5a 160 bytes 850 us -# eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"createsudo","executer":"blkproducera"} -warning: transaction executed locally, but may not be confirmed by the network yet -``` - -Anyone can now verify that the `eosio.sudo` was created: -``` -$ cleos get account eosio.sudo -privileged: true -permissions: - owner 1: 1 eosio@active, - active 1: 1 eosio@active, -memory: - quota: 49.74 KiB used: 3.33 KiB - -net bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) - used: 0 bytes - available: 2.304 MiB - limit: 2.304 MiB - -cpu bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) - used: 0 us - available: 460.8 ms - limit: 460.8 ms - -producers: - -``` - -### 2.2 Deploy the eosio.sudo contract - -#### 2.2.1 Generate the transaction to deploy the eosio.sudo contract - -The transaction to deploy the contract to the `eosio.sudo` account will need to be proposed to get the necessary approvals from active block producers before executing it. This transaction needs to first be generated and stored as JSON into a file so that it can be used in the cleos command to propose the transaction to the eosio.msig contract. - -The easy way to generate this transaction is using cleos: -``` -$ cleos set contract -s -j -d eosio.sudo contracts/eosio.sudo/ > deploy_sudo_contract_trx.json -Reading WAST/WASM from contracts/eosio.sudo/eosio.sudo.wasm... -Using already assembled WASM... -Publishing contract... -$ cat deploy_sudo_contract_trx.json -{ - "expiration": "2018-06-29T19:55:26", - "ref_block_num": 18544, - "ref_block_prefix": 562790588, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "setcode", - "authorization": [{ - "actor": "eosio.sudo", - "permission": "active" - } - ], - "data": "00004d1a03ea30550000c8180061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f636174656400" - },{ - "account": "eosio", - "name": "setabi", - "authorization": [{ - "actor": "eosio.sudo", - "permission": "active" - } - ], - "data": "00004d1a03ea3055df040e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e01000000000080545704657865630000000000" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` - -Once again, as described in sub-section 2.1.1, edit the values of the `ref_block_num` and `ref_block_prefix` fields to be 0 and edit the time of the `expiration` field to some point in the future that provides enough time to approve and execute the proposed transaction. After editing deploy_sudo_contract_trx.json the first few lines of it may look something like the following: -``` -$ head -n 9 deploy_sudo_contract_trx.json -{ - "expiration": "2018-07-06T12:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ -``` - -This guide will assume that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. The end of sub-section 2.1.1 displayed what the JSON of the active permissions of each of the active block producers would look like given the assumptions about the active block producer set. That JSON was stored in the file producer_permissions.json; if the approvers (i.e. block producers) have not created that file already, they should create that file now as shown at the end of sub-section 2.1.1. - -#### 2.2.2 Propose the transaction to deploy the eosio.sudo contract - -Only one of the potential approvers will need to propose the transaction that was created in the previous sub-section. All the other approvers should still follow the steps in the previous sub-section to generate the same deploy_sudo_contract_trx.json file as all the other approvers. They will need this to compare to the actual proposed transaction prior to approving. - -The approvers are typically going to be the active block producers of the chain, so it makes sense that one of the block producers is elected as the leader to propose the actual transaction. Note that this lead block producer will need to incur the temporary RAM cost of proposing the transaction, but they will get the RAM back when the proposal has executed or has been canceled (which only the proposer can do prior to expiration). - -This guide will assume that `blkproducera` was chosen as the lead block producer to propose the transaction. - -The lead block producer (`blkproducera`) should propose the transaction stored in deploy_sudo_contract_trx.json: -``` -$ cleos multisig propose_trx deploysudo producer_permissions.json deploy_sudo_contract_trx.json blkproducera -executed transaction: 9e50dd40eba25583a657ee8114986a921d413b917002c8fb2d02e2d670f720a8 4312 bytes 871 us -# eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"deploysudo","requested":[{"actor":"blkproducera","permis... -warning: transaction executed locally, but may not be confirmed by the network yet -``` - -#### 2.2.3 Review and approve the transaction to deploy the eosio.sudo contract - -Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. - -The proposed transaction can be reviewed using the `cleos multisig review` command: -``` -$ cleos multisig review blkproducera deploysudo > deploy_sudo_contract_trx_to_review.json -$ cat deploy_sudo_contract_trx_to_review.json -{ - "proposal_name": "deploysudo", - "packed_transaction": "c0593f5b00000000000000000000020000000000ea305500000040258ab2c20100004d1a03ea305500000000a8ed3232d41800004d1a03ea30550000c8180061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f6361746564000000000000ea305500000000b863b2c20100004d1a03ea305500000000a8ed3232e90400004d1a03ea3055df040e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e0100000000008054570465786563000000000000", - "transaction": { - "expiration": "2018-07-06T12:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "setcode", - "authorization": [{ - "actor": "eosio.sudo", - "permission": "active" - } - ], - "data": { - "account": "eosio.sudo", - "vmtype": 0, - "vmversion": 0, - "code": "0061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f636174656400" - }, - "hex_data": "00004d1a03ea30550000c8180061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f636174656400" - },{ - "account": "eosio", - "name": "setabi", - "authorization": [{ - "actor": "eosio.sudo", - "permission": "active" - } - ], - "data": { - "account": "eosio.sudo", - "abi": "0e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e01000000000080545704657865630000000000" - }, - "hex_data": "00004d1a03ea3055df040e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e01000000000080545704657865630000000000" - } - ], - "transaction_extensions": [] - } -} -``` - -Each approver should be able to see that the proposed transaction is setting the code and ABI of the `eosio.sudo` contract. But the data is just hex data and therefore not very meaningful to the approver. And considering that `eosio.sudo` at this point should be a privileged contract, it would be very dangerous for block producers to just allow a contract to be deployed to a privileged account without knowing exactly which WebAssembly code they are deploying and also auditing the source code that generated that WebAssembly code to ensure it is safe to deploy. - -This guide assumes that each approver has already audited the source code of the contract to be deployed and has already compiled that code to generate the WebAssembly code that should be byte-for-byte identical to the code that every other approver following the same process should have generated. The guide also assumes that this generated code and its associated ABI were provided in the steps in sub-section 2.2.1 that generated the transaction in the deploy_sudo_contract_trx.json file. It then becomes quite simple to verify that the proposed transaction is identical to the one the potential approver could have proposed with the code and ABI that they already audited: -``` -$ cleos multisig propose_trx -j -s -d deploysudo '[]' deploy_sudo_contract_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_deploy_sudo_trx_serialized.hex -$ cat expected_deploy_sudo_trx_serialized.hex | cut -c -50 -c0593f5b00000000000000000000020000000000ea30550000 -$ cat deploy_sudo_account_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_deploy_sudo_trx_serialized.hex -$ cat proposed_deploy_sudo_trx_serialized.hex | cut -c -50 -c0593f5b00000000000000000000020000000000ea30550000 -$ diff expected_deploy_sudo_trx_serialized.hex proposed_deploy_sudo_trx_serialized.hex -``` - -When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: -``` -$ cleos multisig approve blkproducera deploysudo '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb -executed transaction: d1e424e05ee4d96eb079fcd5190dd0bf35eca8c27dd7231b59df8e464881abfd 128 bytes 483 us -# eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"deploysudo","level":{"actor":"blkproducerb","permission"... -warning: transaction executed locally, but may not be confirmed by the network yet -``` - -#### 2.2.4 Execute the transaction to create the eosio.sudo account - -When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). - -``` -$ cleos multisig exec blkproducera deploysudo blkproducera -executed transaction: e8da14c6f1fdc3255b5413adccfd0d89b18f832a4cc18c4324ea2beec6abd483 160 bytes 1877 us -# eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"deploysudo","executer":"blkproducera"} -``` - -Anyone can now verify that the `eosio.sudo` contract was deployed correctly. - -``` -$ cleos get code -a retrieved-eosio.sudo.abi eosio.sudo -code hash: 1b3456a5eca28bcaca7a2a3360fbb2a72b9772a416c8e11a303bcb26bfe3263c -saving abi to retrieved-eosio.sudo.abi -$ sha256sum contracts/eosio.sudo/eosio.sudo.wasm -1b3456a5eca28bcaca7a2a3360fbb2a72b9772a416c8e11a303bcb26bfe3263c contracts/eosio.sudo/eosio.sudo.wasm -``` - -If the two hashes match then the local WebAssembly code is the one deployed on the blockchain. The retrieved ABI, which was stored in the file retrieved-eosio.sudo.abi, can then be compared to the original ABI of the contract (contracts/eosio.sudo/eosio.sudo.abi) to ensure they are semantically the same. - -## 3. Using the eosio.sudo contract - -### 3.1 Example: Updating owner authority of an arbitrary account - -This example will demonstrate how to use the deployed eosio.sudo contract together with the eosio.msig contract to allow a greater than two-thirds supermajority of block producers of an EOSIO blockchain to change the owner authority of an arbitrary account. The example will use cleos: in particular, the `cleos multisig` command, the `cleos set account permission` sub-command, and the `cleos sudo exec` sub-command. However, the guide also demonstrates what to do if the `cleos sudo exec` sub-command is not available. - -This guide assumes that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. Block producer `blkproducera` will act as the lead block producer handling the proposal of the transaction. - -The producer permissions will later come in handy when proposing a transaction that must be approved by a supermajority of the producers. So a file producer_permissions.json containing those permission (see contents below) should be created to be used later in this guide: -``` -$ cat producer_permissions.json -[ - {"actor": "blkproducera", "permission": "active"}, - {"actor": "blkproducerb", "permission": "active"}, - {"actor": "blkproducerc", "permission": "active"}, - {"actor": "blkproducerd", "permission": "active"}, - {"actor": "blkproducere", "permission": "active"}, - {"actor": "blkproducerf", "permission": "active"}, - {"actor": "blkproducerg", "permission": "active"}, - {"actor": "blkproducerh", "permission": "active"}, - {"actor": "blkproduceri", "permission": "active"}, - {"actor": "blkproducerj", "permission": "active"}, - {"actor": "blkproducerk", "permission": "active"}, - {"actor": "blkproducerl", "permission": "active"}, - {"actor": "blkproducerm", "permission": "active"}, - {"actor": "blkproducern", "permission": "active"}, - {"actor": "blkproducero", "permission": "active"}, - {"actor": "blkproducerp", "permission": "active"}, - {"actor": "blkproducerq", "permission": "active"}, - {"actor": "blkproducerr", "permission": "active"}, - {"actor": "blkproducers", "permission": "active"}, - {"actor": "blkproducert", "permission": "active"}, - {"actor": "blkproduceru", "permission": "active"} -] -``` - -#### 3.1.1 Generate the transaction to change the owner permission of an account - -The goal of this example is for the block producers to change the owner permission of the account `alice`. - -The initial status of the `alice` account might be: -``` -permissions: - owner 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV - active 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV -memory: - quota: 49.74 KiB used: 3.365 KiB - -net bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) - used: 0 bytes - available: 2.304 MiB - limit: 2.304 MiB - -cpu bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) - used: 0 us - available: 460.8 ms - limit: 460.8 ms - -producers: -``` - -Assume that none of the block producers know the private key corresponding to the public key `EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV` which, as can be seen above, is initially securing access to the `alice` account. - -The first step is to generate the transaction changing the owner permission of the `alice` account as if `alice` is authorizing the change: -``` -$ cleos set account permission -s -j -d alice owner '{"threshold": 1, "accounts": [{"permission": {"actor": "eosio", "permission": "active"}, "weight": 1}]}' > update_alice_owner_trx.json -``` - -Then modify update_alice_owner_trx.json so that the values for the `ref_block_num` and `ref_block_prefix` fields are both 0 and the value of the `expiration` field is `"1970-01-01T00:00:00"`: -``` -$ cat update_alice_owner_trx.json -{ - "expiration": "1970-01-01T00:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "updateauth", - "authorization": [{ - "actor": "alice", - "permission": "active" - } - ], - "data": "0000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed3232010000" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` - -The next step is to generate the transaction containing the `eosio.sudo::exec` action. This action will contain the transaction in update_alice_owner_trx.json as part of its action payload data. - -``` -$ cleos sudo exec -s -j -d blkproducera update_alice_owner_trx.json > sudo_update_alice_owner_trx.json -``` - -Once again modify sudo_update_alice_owner_trx.json so that the value for the `ref_block_num` and `ref_block_prefix` fields are both 0. However, instead of changing the value of the expiration field to `"1970-01-01T00:00:00"`, it should be changed to a time that is far enough in the future to allow enough time for the proposed transaction to be approved and executed. -``` -$ cat sudo_update_alice_owner_trx.json -{ - "expiration": "2018-07-06T12:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio.sudo", - "name": "exec", - "authorization": [{ - "actor": "blkproducera", - "permission": "active" - },{ - "actor": "eosio.sudo", - "permission": "active" - } - ], - "data": "60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed323201000000" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` - -If the `cleos sudo` command is not available, there is an alternative way to generate the above transaction. There is no need to continue reading the remaining of sub-section 3.1.1 if the sudo_update_alice_owner_trx.json file was already generated with content similar to the above using the `cleos sudo exec` sub-command method. - -First the hex encoding of the binary serialization of the transaction in update_alice_owner_trx.json must be obtained. One way of obtaining this data is through the following command: -``` -$ cleos multisig propose_trx -s -j -d nothing '[]' update_alice_owner_trx.json nothing | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > update_alice_owner_trx_serialized.hex -$ cat update_alice_owner_trx_serialized.hex -0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed323201000000 -``` - -Then generate the template for the transaction containing the `eosio.sudo::exec` action: -``` -$ cleos push action -s -j -d eosio.sudo exec '{"executer": "blkproducera", "trx": ""}' > sudo_update_alice_owner_trx.json -$ cat sudo_update_alice_owner_trx.json -{ - "expiration": "2018-06-29T23:34:01", - "ref_block_num": 23708, - "ref_block_prefix": 3605208482, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio.sudo", - "name": "exec", - "authorization": [], - "data": "60ae423ad15b613c" - } - ], - "transaction_extensions": [], - "signatures": [], - "context_free_data": [] -} -``` - -Then modify the transaction in sudo_update_alice_owner_trx.json as follows: - * replace the values of the `ref_block_num` and `ref_block_prefix` fields to 0; - * replace the time of the `expiration` field to the desired expiration time as described above (e.g. `"2018-07-06T12:00:00"`); - * append the hex data from update_alice_owner_trx_serialized.hex to the end of the existing hex data in the `data` field in sudo_update_alice_owner_trx.json. - - -#### 3.1.2 Propose the transaction to change the owner permission of an account - -The lead block producer (`blkproducera`) should propose the transaction stored in sudo_update_alice_owner_trx.json: -``` -$ cleos multisig propose_trx updatealice producer_permissions.json sudo_update_alice_owner_trx.json blkproducera -executed transaction: 10474f52c9e3fc8e729469a577cd2fc9e4330e25b3fd402fc738ddde26605c13 624 bytes 782 us -# eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"updatealice","requested":[{"actor":"blkproducera","permi... -warning: transaction executed locally, but may not be confirmed by the network yet -``` - -#### 3.1.3 Review and approve the transaction to change the owner permission of an account - -Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. -``` -$ cleos multisig review blkproducera updatealice > sudo_update_alice_owner_trx_to_review.json -$ cat sudo_update_alice_owner_trx_to_review.json -{ - "proposal_name": "updatealice", - "packed_transaction": "c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000", - "transaction": { - "expiration": "2018-07-06T12:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio.sudo", - "name": "exec", - "authorization": [{ - "actor": "blkproducera", - "permission": "active" - },{ - "actor": "eosio.sudo", - "permission": "active" - } - ], - "data": { - "executer": "blkproducera", - "trx": { - "expiration": "1970-01-01T00:00:00", - "ref_block_num": 0, - "ref_block_prefix": 0, - "max_net_usage_words": 0, - "max_cpu_usage_ms": 0, - "delay_sec": 0, - "context_free_actions": [], - "actions": [{ - "account": "eosio", - "name": "updateauth", - "authorization": [{ - "actor": "alice", - "permission": "active" - } - ], - "data": "0000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed3232010000" - } - ], - "transaction_extensions": [] - } - }, - "hex_data": "60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed323201000000" - } - ], - "transaction_extensions": [] - } -} -``` - -The approvers should go through the human-readable transaction output and make sure everything looks fine. However, due to a current limitation of nodeos/cleos, the JSONification of action payload data does not occur recursively. So while both the `hex_data` and the human-readable JSON `data` of the payload of the `eosio.sudo::exec` action is available in the output of the `cleos multisig review` command, only the hex data is available of the payload of the inner `eosio::updateauth` action. So it is not clear what the `updateauth` will actually do. - -Furthermore, even if this usability issue was fixed in nodeos/cleos, there will still be cases where there is no sensible human-readable version of an action data payload within a transaction. An example of this is the proposed transaction in sub-section 2.2.3 which used the `eosio::setcode` action to set the contract code of the `eosio.sudo` account. The best thing to do in such situations is for the reviewer to compare the proposed transaction to one generated by them through a process they trust. - -Since each block producer generated a transaction in sub-section 3.1.1 (stored in the file sudo_update_alice_owner_trx.json) which should be identical to the transaction proposed by the lead block producer, they can each simply check to see if the two transactions are identical: -``` -$ cleos multisig propose_trx -j -s -d updatealice '[]' sudo_update_alice_owner_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_sudo_update_alice_owner_trx_serialized.hex -$ cat expected_sudo_update_alice_owner_trx_serialized.hex -c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000 -$ cat sudo_update_alice_owner_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_sudo_update_alice_owner_trx_serialized.hex -$ cat proposed_sudo_update_alice_owner_trx_serialized.hex -c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000 -$ diff expected_sudo_update_alice_owner_trx_serialized.hex proposed_sudo_update_alice_owner_trx_serialized.hex -``` - -When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: -``` -$ cleos multisig approve blkproducera updatealice '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb -executed transaction: 2bddc7747e0660ba26babf95035225895b134bfb2ede32ba0a2bb6091c7dab56 128 bytes 543 us -# eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"updatealice","level":{"actor":"blkproducerb","permission... -warning: transaction executed locally, but may not be confirmed by the network yet -``` - -#### 3.1.4 Execute the transaction to change the owner permission of an account - -When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). - -``` -$ cleos multisig exec blkproducera updatealice blkproducera -executed transaction: 7127a66ae307fbef6415bf60c3e91a88b79bcb46030da983c683deb2a1a8e0d0 160 bytes 820 us -# eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"updatealice","executer":"blkproducera"} -warning: transaction executed locally, but may not be confirmed by the network yet -``` - -Anyone can now verify that the owner authority of `alice` was successfully changed: -``` -$ cleos get account alice -permissions: - owner 1: 1 eosio@active, - active 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV -memory: - quota: 49.74 KiB used: 3.348 KiB - -net bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) - used: 0 bytes - available: 2.304 MiB - limit: 2.304 MiB - -cpu bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) - used: 413 us - available: 460.4 ms - limit: 460.8 ms - -producers: - -``` diff --git a/contracts/eosio.sudo/eosio.sudo.abi b/contracts/eosio.sudo/eosio.sudo.abi deleted file mode 100644 index 6f74921bc2a..00000000000 --- a/contracts/eosio.sudo/eosio.sudo.abi +++ /dev/null @@ -1,73 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - },{ - "new_type_name": "permission_name", - "type": "name" - },{ - "new_type_name": "action_name", - "type": "name" - }], - "structs": [{ - "name": "permission_level", - "base": "", - "fields": [ - {"name": "actor", "type": "account_name"}, - {"name": "permission", "type": "permission_name"} - ] - },{ - "name": "action", - "base": "", - "fields": [ - {"name": "account", "type": "account_name"}, - {"name": "name", "type": "action_name"}, - {"name": "authorization", "type": "permission_level[]"}, - {"name": "data", "type": "bytes"} - ] - },{ - "name": "transaction_header", - "base": "", - "fields": [ - {"name": "expiration", "type": "time_point_sec"}, - {"name": "ref_block_num", "type": "uint16"}, - {"name": "ref_block_prefix", "type": "uint32"}, - {"name": "max_net_usage_words", "type": "varuint32"}, - {"name": "max_cpu_usage_ms", "type": "uint8"}, - {"name": "delay_sec", "type": "varuint32"} - ] - },{ - "name": "extension", - "base": "", - "fields": [ - {"name": "type", "type" : "uint16" }, - {"name": "data", "type": "bytes"} - ] - },{ - "name": "transaction", - "base": "transaction_header", - "fields": [ - {"name": "context_free_actions", "type": "action[]"}, - {"name": "actions", "type": "action[]"}, - {"name": "transaction_extensions", "type": "extension[]"} - ] - },{ - "name": "exec", - "base": "", - "fields": [ - {"name":"executer", "type":"account_name"}, - {"name":"trx", "type":"transaction"} - ] - } - ], - "actions": [{ - "name": "exec", - "type": "exec", - "ricardian_contract": "" - } - ], - "tables": [], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/eosio.sudo/eosio.sudo.cpp b/contracts/eosio.sudo/eosio.sudo.cpp deleted file mode 100644 index c64ffa756aa..00000000000 --- a/contracts/eosio.sudo/eosio.sudo.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -namespace eosio { - -/* -exec function manually parses input data (instead of taking parsed arguments from dispatcher) -because parsing data in the dispatcher uses too much CPU if the included transaction is very big - -If we use dispatcher the function signature should be: - -void sudo::exec( account_name executer, - transaction trx ) -*/ - -void sudo::exec() { - require_auth( _self ); - - constexpr size_t max_stack_buffer_size = 512; - size_t size = action_data_size(); - char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); - read_action_data( buffer, size ); - - account_name executer; - - datastream ds( buffer, size ); - ds >> executer; - - require_auth( executer ); - - size_t trx_pos = ds.tellp(); - send_deferred( (uint128_t(executer) << 64) | current_time(), executer, buffer+trx_pos, size-trx_pos ); -} - -} /// namespace eosio - -EOSIO_ABI( eosio::sudo, (exec) ) diff --git a/contracts/eosio.sudo/eosio.sudo.hpp b/contracts/eosio.sudo/eosio.sudo.hpp deleted file mode 100644 index a96562121dc..00000000000 --- a/contracts/eosio.sudo/eosio.sudo.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -namespace eosio { - - class sudo : public contract { - public: - sudo( account_name self ):contract(self){} - - void exec(); - - }; - -} /// namespace eosio diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt deleted file mode 100644 index eb4ff749f77..00000000000 --- a/contracts/eosio.system/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET eosio.system - INCLUDE_FOLDERS ${STANDARD_INCLUDE_FOLDERS} - LIBRARIES libc++ libc eosiolib eosio.token - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/eosio.system/README.md b/contracts/eosio.system/README.md deleted file mode 100644 index 9e5c3160069..00000000000 --- a/contracts/eosio.system/README.md +++ /dev/null @@ -1,84 +0,0 @@ -eosio.system ----------- - -This contract enables users to stake tokens, and then configure and vote on producers and worker proposals. - -Users can also proxy their voting influence to other users. - -The state of this contract is read to determine the 21 active block producers. - -Actions: -The naming convention is codeaccount::actionname followed by a list of paramters. - -Indicates that a particular account wishes to become a producer -## eosio.system::cfgproducer account config - - **account** the producer account to update - - updates the configuration settings for a particular producer, these - - Storage changes are billed to 'account' - -## eosio.system::okproducer account producer vote - - **account** the account which is doing the voting - - **producer** the producer which is being voted for (or unvoted for) - - **vote** true if the producer should be voted for, false if not - - Each account has a maximum number of votes it can maintain. Storage changes will be billed to 'account' - -## eosio.system::setproxy account proxy - - **account** the account which is updating it's proxy - - **proxy** the account which will have the power to vote account's stake - - All current votes are removed and a new proxy link is created. The votes for every producer the proxy - has voted for are updated immediately. - - Storage changes will be billed to 'account' - -## eosio.system::unstake account quantity - - **account** - the account which is requesting their balance be unstaked - - **quantity** - the quantity which will be unstaked, unstaked tokens lose voting influence immediately - - - in order to unstake tokens, an account must request them. The user will receive them over - time via weekly withdraws. The length of time will be configured by the median time as set by - the active producers. - - - If this is called while in the process of unstaking, the currently pending unstake is canceled as if - quantity were 0, then it is applied as if a new unstake request was made. - - - all producers this 'from' has voted for will have their votes updated immediately. - - - bandwidth and storage for the deferred transaction will be billed to 'from' - -## eosio.system::withdraw account - - this action can only be triggered by eosio.system via a deferred transaction generated by unstake - - this will generate an inline eosio.token::transfer call from=eosio.system to=account and amount equal to the next withdraw increment - - this will generate another deferred withdraw to continue the process if there are still withdraws to be made - - -## eosio.system::transfer from to amount memo - - decrements balance of from if amount <= balance - - increments balance of to by amount - - memo is ignored - -## eosio.system::stakevote account amount - - the primary currency of eosio is controlled by the token contract which enables users to transfer - balances from one user to another. The receiver is notified on incoming balances and the vote contract - will stake the tokens on receipt. - - - all producers this 'from' has voted for will have their votes updated immediately. - - -## eosio.system::onblock account blocktime blocknum - - this special action is triggered when a block is applied by the given producer and cannot be generated from - any other source. It is used to pay producers and calculate missed blocks of other producers. - - - producer pay is deposited into the producer's stake balance and can be withdrawn over time. - - - if blocknum is the start of a new round this may update the active producer config from the producer votes. - -## eosio.system::freeze producer accounts true|false - - requires permission of the @producers account - - if an account is frozen, all authorizations of that account are rejected and the code for that account will not be run - -## eosio.system::paystandby producer - - every block some amount of tokens is paid - - at most once per day a producer may claim a percentage of the standby pay equal to their totalvotes / allvotes diff --git a/contracts/eosio.system/delegate_bandwidth.cpp b/contracts/eosio.system/delegate_bandwidth.cpp deleted file mode 100644 index d37ee0554ea..00000000000 --- a/contracts/eosio.system/delegate_bandwidth.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include "eosio.system.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include - - -#include -#include - -namespace eosiosystem { - using eosio::asset; - using eosio::indexed_by; - using eosio::const_mem_fun; - using eosio::bytes; - using eosio::print; - using eosio::permission_level; - using std::map; - using std::pair; - - static constexpr time refund_delay = 3*24*3600; - static constexpr time refund_expiration_time = 3600; - - struct user_resources { - account_name owner; - asset net_weight; - asset cpu_weight; - int64_t ram_bytes = 0; - - uint64_t primary_key()const { return owner; } - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( user_resources, (owner)(net_weight)(cpu_weight)(ram_bytes) ) - }; - - - /** - * Every user 'from' has a scope/table that uses every receipient 'to' as the primary key. - */ - struct delegated_bandwidth { - account_name from; - account_name to; - asset net_weight; - asset cpu_weight; - - uint64_t primary_key()const { return to; } - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( delegated_bandwidth, (from)(to)(net_weight)(cpu_weight) ) - - }; - - struct refund_request { - account_name owner; - time request_time; - eosio::asset net_amount; - eosio::asset cpu_amount; - - uint64_t primary_key()const { return owner; } - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( refund_request, (owner)(request_time)(net_amount)(cpu_amount) ) - }; - - /** - * These tables are designed to be constructed in the scope of the relevant user, this - * facilitates simpler API for per-user queries - */ - typedef eosio::multi_index< N(userres), user_resources> user_resources_table; - typedef eosio::multi_index< N(delband), delegated_bandwidth> del_bandwidth_table; - typedef eosio::multi_index< N(refunds), refund_request> refunds_table; - - - - /** - * This action will buy an exact amount of ram and bill the payer the current market price. - */ - void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) { - auto itr = _rammarket.find(S(4,RAMCORE)); - auto tmp = *itr; - auto eosout = tmp.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL ); - - buyram( payer, receiver, eosout ); - } - - - /** - * When buying ram the payer irreversiblly transfers quant to system contract and only - * the receiver may reclaim the tokens via the sellram action. The receiver pays for the - * storage of all database records associated with this action. - * - * RAM is a scarce resource whose supply is defined by global properties max_ram_size. RAM is - * priced using the bancor algorithm such that price-per-byte with a constant reserve ratio of 100:1. - */ - void system_contract::buyram( account_name payer, account_name receiver, asset quant ) - { - require_auth( payer ); - eosio_assert( quant.amount > 0, "must purchase a positive amount" ); - - auto fee = quant; - fee.amount = ( fee.amount + 199 ) / 200; /// .5% fee (round up) - // fee.amount cannot be 0 since that is only possible if quant.amount is 0 which is not allowed by the assert above. - // If quant.amount == 1, then fee.amount == 1, - // otherwise if quant.amount > 1, then 0 < fee.amount < quant.amount. - auto quant_after_fee = quant; - quant_after_fee.amount -= fee.amount; - // quant_after_fee.amount should be > 0 if quant.amount > 1. - // If quant.amount == 1, then quant_after_fee.amount == 0 and the next inline transfer will fail causing the buyram action to fail. - - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {payer,N(active)}, - { payer, N(eosio.ram), quant_after_fee, std::string("buy ram") } ); - - if( fee.amount > 0 ) { - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {payer,N(active)}, - { payer, N(eosio.ramfee), fee, std::string("ram fee") } ); - } - - int64_t bytes_out; - - const auto& market = _rammarket.get(S(4,RAMCORE), "ram market does not exist"); - _rammarket.modify( market, 0, [&]( auto& es ) { - bytes_out = es.convert( quant_after_fee, S(0,RAM) ).amount; - }); - - eosio_assert( bytes_out > 0, "must reserve a positive amount" ); - - _gstate.total_ram_bytes_reserved += uint64_t(bytes_out); - _gstate.total_ram_stake += quant_after_fee.amount; - - user_resources_table userres( _self, receiver ); - auto res_itr = userres.find( receiver ); - if( res_itr == userres.end() ) { - res_itr = userres.emplace( receiver, [&]( auto& res ) { - res.owner = receiver; - res.ram_bytes = bytes_out; - }); - } else { - userres.modify( res_itr, receiver, [&]( auto& res ) { - res.ram_bytes += bytes_out; - }); - } - set_resource_limits( res_itr->owner, res_itr->ram_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount ); - } - - - /** - * The system contract now buys and sells RAM allocations at prevailing market prices. - * This may result in traders buying RAM today in anticipation of potential shortages - * tomorrow. Overall this will result in the market balancing the supply and demand - * for RAM over time. - */ - void system_contract::sellram( account_name account, int64_t bytes ) { - require_auth( account ); - eosio_assert( bytes > 0, "cannot sell negative byte" ); - - user_resources_table userres( _self, account ); - auto res_itr = userres.find( account ); - eosio_assert( res_itr != userres.end(), "no resource row" ); - eosio_assert( res_itr->ram_bytes >= bytes, "insufficient quota" ); - - asset tokens_out; - auto itr = _rammarket.find(S(4,RAMCORE)); - _rammarket.modify( itr, 0, [&]( auto& es ) { - /// the cast to int64_t of bytes is safe because we certify bytes is <= quota which is limited by prior purchases - tokens_out = es.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL); - }); - - eosio_assert( tokens_out.amount > 1, "token amount received from selling ram is too low" ); - - _gstate.total_ram_bytes_reserved -= static_cast(bytes); // bytes > 0 is asserted above - _gstate.total_ram_stake -= tokens_out.amount; - - //// this shouldn't happen, but just in case it does we should prevent it - eosio_assert( _gstate.total_ram_stake >= 0, "error, attempt to unstake more tokens than previously staked" ); - - userres.modify( res_itr, account, [&]( auto& res ) { - res.ram_bytes -= bytes; - }); - set_resource_limits( res_itr->owner, res_itr->ram_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount ); - - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.ram),N(active)}, - { N(eosio.ram), account, asset(tokens_out), std::string("sell ram") } ); - - auto fee = ( tokens_out.amount + 199 ) / 200; /// .5% fee (round up) - // since tokens_out.amount was asserted to be at least 2 earlier, fee.amount < tokens_out.amount - - if( fee > 0 ) { - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {account,N(active)}, - { account, N(eosio.ramfee), asset(fee), std::string("sell ram fee") } ); - } - } - - void validate_b1_vesting( int64_t stake ) { - const int64_t base_time = 1527811200; /// 2018-06-01 - const int64_t max_claimable = 100'000'000'0000ll; - const int64_t claimable = int64_t(max_claimable * double(now()-base_time) / (10*seconds_per_year) ); - - eosio_assert( max_claimable - claimable <= stake, "b1 can only claim their tokens over 10 years" ); - } - - void system_contract::changebw( account_name from, account_name receiver, - const asset stake_net_delta, const asset stake_cpu_delta, bool transfer ) - { - require_auth( from ); - eosio_assert( stake_net_delta != asset(0) || stake_cpu_delta != asset(0), "should stake non-zero amount" ); - eosio_assert( std::abs( (stake_net_delta + stake_cpu_delta).amount ) - >= std::max( std::abs( stake_net_delta.amount ), std::abs( stake_cpu_delta.amount ) ), - "net and cpu deltas cannot be opposite signs" ); - - account_name source_stake_from = from; - if ( transfer ) { - from = receiver; - } - - // update stake delegated from "from" to "receiver" - { - del_bandwidth_table del_tbl( _self, from); - auto itr = del_tbl.find( receiver ); - if( itr == del_tbl.end() ) { - itr = del_tbl.emplace( from, [&]( auto& dbo ){ - dbo.from = from; - dbo.to = receiver; - dbo.net_weight = stake_net_delta; - dbo.cpu_weight = stake_cpu_delta; - }); - } - else { - del_tbl.modify( itr, 0, [&]( auto& dbo ){ - dbo.net_weight += stake_net_delta; - dbo.cpu_weight += stake_cpu_delta; - }); - } - eosio_assert( asset(0) <= itr->net_weight, "insufficient staked net bandwidth" ); - eosio_assert( asset(0) <= itr->cpu_weight, "insufficient staked cpu bandwidth" ); - if ( itr->net_weight == asset(0) && itr->cpu_weight == asset(0) ) { - del_tbl.erase( itr ); - } - } // itr can be invalid, should go out of scope - - // update totals of "receiver" - { - user_resources_table totals_tbl( _self, receiver ); - auto tot_itr = totals_tbl.find( receiver ); - if( tot_itr == totals_tbl.end() ) { - tot_itr = totals_tbl.emplace( from, [&]( auto& tot ) { - tot.owner = receiver; - tot.net_weight = stake_net_delta; - tot.cpu_weight = stake_cpu_delta; - }); - } else { - totals_tbl.modify( tot_itr, from == receiver ? from : 0, [&]( auto& tot ) { - tot.net_weight += stake_net_delta; - tot.cpu_weight += stake_cpu_delta; - }); - } - eosio_assert( asset(0) <= tot_itr->net_weight, "insufficient staked total net bandwidth" ); - eosio_assert( asset(0) <= tot_itr->cpu_weight, "insufficient staked total cpu bandwidth" ); - - set_resource_limits( receiver, tot_itr->ram_bytes, tot_itr->net_weight.amount, tot_itr->cpu_weight.amount ); - - if ( tot_itr->net_weight == asset(0) && tot_itr->cpu_weight == asset(0) && tot_itr->ram_bytes == 0 ) { - totals_tbl.erase( tot_itr ); - } - } // tot_itr can be invalid, should go out of scope - - // create refund or update from existing refund - if ( N(eosio.stake) != source_stake_from ) { //for eosio both transfer and refund make no sense - refunds_table refunds_tbl( _self, from ); - auto req = refunds_tbl.find( from ); - - //create/update/delete refund - auto net_balance = stake_net_delta; - auto cpu_balance = stake_cpu_delta; - bool need_deferred_trx = false; - - - // net and cpu are same sign by assertions in delegatebw and undelegatebw - // redundant assertion also at start of changebw to protect against misuse of changebw - bool is_undelegating = (net_balance.amount + cpu_balance.amount ) < 0; - bool is_delegating_to_self = (!transfer && from == receiver); - - if( is_delegating_to_self || is_undelegating ) { - if ( req != refunds_tbl.end() ) { //need to update refund - refunds_tbl.modify( req, 0, [&]( refund_request& r ) { - if ( net_balance < asset(0) || cpu_balance < asset(0) ) { - r.request_time = now(); - } - r.net_amount -= net_balance; - if ( r.net_amount < asset(0) ) { - net_balance = -r.net_amount; - r.net_amount = asset(0); - } else { - net_balance = asset(0); - } - r.cpu_amount -= cpu_balance; - if ( r.cpu_amount < asset(0) ){ - cpu_balance = -r.cpu_amount; - r.cpu_amount = asset(0); - } else { - cpu_balance = asset(0); - } - }); - - eosio_assert( asset(0) <= req->net_amount, "negative net refund amount" ); //should never happen - eosio_assert( asset(0) <= req->cpu_amount, "negative cpu refund amount" ); //should never happen - - if ( req->net_amount == asset(0) && req->cpu_amount == asset(0) ) { - refunds_tbl.erase( req ); - need_deferred_trx = false; - } else { - need_deferred_trx = true; - } - - } else if ( net_balance < asset(0) || cpu_balance < asset(0) ) { //need to create refund - refunds_tbl.emplace( from, [&]( refund_request& r ) { - r.owner = from; - if ( net_balance < asset(0) ) { - r.net_amount = -net_balance; - net_balance = asset(0); - } // else r.net_amount = 0 by default constructor - if ( cpu_balance < asset(0) ) { - r.cpu_amount = -cpu_balance; - cpu_balance = asset(0); - } // else r.cpu_amount = 0 by default constructor - r.request_time = now(); - }); - need_deferred_trx = true; - } // else stake increase requested with no existing row in refunds_tbl -> nothing to do with refunds_tbl - } /// end if is_delegating_to_self || is_undelegating - - if ( need_deferred_trx ) { - eosio::transaction out; - out.actions.emplace_back( permission_level{ from, N(active) }, _self, N(refund), from ); - out.delay_sec = refund_delay; - cancel_deferred( from ); // TODO: Remove this line when replacing deferred trxs is fixed - out.send( from, from, true ); - } else { - cancel_deferred( from ); - } - - auto transfer_amount = net_balance + cpu_balance; - if ( asset(0) < transfer_amount ) { - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {source_stake_from, N(active)}, - { source_stake_from, N(eosio.stake), asset(transfer_amount), std::string("stake bandwidth") } ); - } - } - - // update voting power - { - asset total_update = stake_net_delta + stake_cpu_delta; - auto from_voter = _voters.find(from); - if( from_voter == _voters.end() ) { - from_voter = _voters.emplace( from, [&]( auto& v ) { - v.owner = from; - v.staked = total_update.amount; - }); - } else { - _voters.modify( from_voter, 0, [&]( auto& v ) { - v.staked += total_update.amount; - }); - } - eosio_assert( 0 <= from_voter->staked, "stake for voting cannot be negative"); - if( from == N(b1) ) { - validate_b1_vesting( from_voter->staked ); - } - - if( from_voter->producers.size() || from_voter->proxy ) { - update_votes( from, from_voter->proxy, from_voter->producers, false ); - } - } - } - - void system_contract::delegatebw( account_name from, account_name receiver, - asset stake_net_quantity, - asset stake_cpu_quantity, bool transfer ) - { - eosio_assert( stake_cpu_quantity >= asset(0), "must stake a positive amount" ); - eosio_assert( stake_net_quantity >= asset(0), "must stake a positive amount" ); - eosio_assert( stake_net_quantity + stake_cpu_quantity > asset(0), "must stake a positive amount" ); - eosio_assert( !transfer || from != receiver, "cannot use transfer flag if delegating to self" ); - - changebw( from, receiver, stake_net_quantity, stake_cpu_quantity, transfer); - } // delegatebw - - void system_contract::undelegatebw( account_name from, account_name receiver, - asset unstake_net_quantity, asset unstake_cpu_quantity ) - { - eosio_assert( asset() <= unstake_cpu_quantity, "must unstake a positive amount" ); - eosio_assert( asset() <= unstake_net_quantity, "must unstake a positive amount" ); - eosio_assert( asset() < unstake_cpu_quantity + unstake_net_quantity, "must unstake a positive amount" ); - eosio_assert( _gstate.total_activated_stake >= min_activated_stake, - "cannot undelegate bandwidth until the chain is activated (at least 15% of all tokens participate in voting)" ); - - changebw( from, receiver, -unstake_net_quantity, -unstake_cpu_quantity, false); - } // undelegatebw - - - void system_contract::refund( const account_name owner ) { - require_auth( owner ); - - refunds_table refunds_tbl( _self, owner ); - auto req = refunds_tbl.find( owner ); - eosio_assert( req != refunds_tbl.end(), "refund request not found" ); - eosio_assert( req->request_time + refund_delay <= now(), "refund is not available yet" ); - // Until now() becomes NOW, the fact that now() is the timestamp of the previous block could in theory - // allow people to get their tokens earlier than the 3 day delay if the unstake happened immediately after many - // consecutive missed blocks. - - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.stake),N(active)}, - { N(eosio.stake), req->owner, req->net_amount + req->cpu_amount, std::string("unstake") } ); - - refunds_tbl.erase( req ); - } - - -} //namespace eosiosystem diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi deleted file mode 100644 index 87937c787f9..00000000000 --- a/contracts/eosio.system/eosio.system.abi +++ /dev/null @@ -1,578 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - },{ - "new_type_name": "permission_name", - "type": "name" - },{ - "new_type_name": "action_name", - "type": "name" - },{ - "new_type_name": "transaction_id_type", - "type": "checksum256" - },{ - "new_type_name": "weight_type", - "type": "uint16" - }], - "____comment": "eosio.bios structs: set_account_limits, setpriv, set_global_limits, producer_key, set_producers, require_auth are provided so abi available for deserialization in future.", - "structs": [{ - "name": "permission_level", - "base": "", - "fields": [ - {"name":"actor", "type":"account_name"}, - {"name":"permission", "type":"permission_name"} - ] - },{ - "name": "key_weight", - "base": "", - "fields": [ - {"name":"key", "type":"public_key"}, - {"name":"weight", "type":"weight_type"} - ] - },{ - "name": "bidname", - "base": "", - "fields": [ - {"name":"bidder", "type":"account_name"}, - {"name":"newname", "type":"account_name"}, - {"name":"bid", "type":"asset"} - ] - },{ - "name": "permission_level_weight", - "base": "", - "fields": [ - {"name":"permission", "type":"permission_level"}, - {"name":"weight", "type":"weight_type"} - ] - },{ - "name": "wait_weight", - "base": "", - "fields": [ - {"name":"wait_sec", "type":"uint32"}, - {"name":"weight", "type":"weight_type"} - ] - },{ - "name": "authority", - "base": "", - "fields": [ - {"name":"threshold", "type":"uint32"}, - {"name":"keys", "type":"key_weight[]"}, - {"name":"accounts", "type":"permission_level_weight[]"}, - {"name":"waits", "type":"wait_weight[]"} - ] - },{ - "name": "newaccount", - "base": "", - "fields": [ - {"name":"creator", "type":"account_name"}, - {"name":"name", "type":"account_name"}, - {"name":"owner", "type":"authority"}, - {"name":"active", "type":"authority"} - ] - },{ - "name": "setcode", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"vmtype", "type":"uint8"}, - {"name":"vmversion", "type":"uint8"}, - {"name":"code", "type":"bytes"} - ] - },{ - "name": "setabi", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"abi", "type":"bytes"} - ] - },{ - "name": "updateauth", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"permission", "type":"permission_name"}, - {"name":"parent", "type":"permission_name"}, - {"name":"auth", "type":"authority"} - ] - },{ - "name": "deleteauth", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"permission", "type":"permission_name"} - ] - },{ - "name": "linkauth", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"code", "type":"account_name"}, - {"name":"type", "type":"action_name"}, - {"name":"requirement", "type":"permission_name"} - ] - },{ - "name": "unlinkauth", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"code", "type":"account_name"}, - {"name":"type", "type":"action_name"} - ] - },{ - "name": "canceldelay", - "base": "", - "fields": [ - {"name":"canceling_auth", "type":"permission_level"}, - {"name":"trx_id", "type":"transaction_id_type"} - ] - },{ - "name": "onerror", - "base": "", - "fields": [ - {"name":"sender_id", "type":"uint128"}, - {"name":"sent_trx", "type":"bytes"} - ] - },{ - "name": "buyrambytes", - "base": "", - "fields": [ - {"name":"payer", "type":"account_name"}, - {"name":"receiver", "type":"account_name"}, - {"name":"bytes", "type":"uint32"} - ] - },{ - "name": "sellram", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"bytes", "type":"uint64"} - ] - },{ - "name": "buyram", - "base": "", - "fields": [ - {"name":"payer", "type":"account_name"}, - {"name":"receiver", "type":"account_name"}, - {"name":"quant", "type":"asset"} - ] - },{ - "name": "delegatebw", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"receiver", "type":"account_name"}, - {"name":"stake_net_quantity", "type":"asset"}, - {"name":"stake_cpu_quantity", "type":"asset"}, - {"name":"transfer", "type":"bool"} - ] - },{ - "name": "undelegatebw", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"receiver", "type":"account_name"}, - {"name":"unstake_net_quantity", "type":"asset"}, - {"name":"unstake_cpu_quantity", "type":"asset"} - ] - },{ - "name": "refund", - "base": "", - "fields": [ - {"name":"owner", "type":"account_name"} - ] - },{ - "name": "delegated_bandwidth", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"to", "type":"account_name"}, - {"name":"net_weight", "type":"asset"}, - {"name":"cpu_weight", "type":"asset"} - ] - },{ - "name": "user_resources", - "base": "", - "fields": [ - {"name":"owner", "type":"account_name"}, - {"name":"net_weight", "type":"asset"}, - {"name":"cpu_weight", "type":"asset"}, - {"name":"ram_bytes", "type":"uint64"} - ] - },{ - "name": "total_resources", - "base": "", - "fields": [ - {"name":"owner", "type":"account_name"}, - {"name":"net_weight", "type":"asset"}, - {"name":"cpu_weight", "type":"asset"}, - {"name":"ram_bytes", "type":"uint64"} - ] - },{ - "name": "refund_request", - "base": "", - "fields": [ - {"name":"owner", "type":"account_name"}, - {"name":"request_time", "type":"time_point_sec"}, - {"name":"net_amount", "type":"asset"}, - {"name":"cpu_amount", "type":"asset"} - ] - },{ - "name": "blockchain_parameters", - "base": "", - "fields": [ - - {"name":"max_block_net_usage", "type":"uint64"}, - {"name":"target_block_net_usage_pct", "type":"uint32"}, - {"name":"max_transaction_net_usage", "type":"uint32"}, - {"name":"base_per_transaction_net_usage", "type":"uint32"}, - {"name":"net_usage_leeway", "type":"uint32"}, - {"name":"context_free_discount_net_usage_num", "type":"uint32"}, - {"name":"context_free_discount_net_usage_den", "type":"uint32"}, - {"name":"max_block_cpu_usage", "type":"uint32"}, - {"name":"target_block_cpu_usage_pct", "type":"uint32"}, - {"name":"max_transaction_cpu_usage", "type":"uint32"}, - {"name":"min_transaction_cpu_usage", "type":"uint32"}, - {"name":"max_transaction_lifetime", "type":"uint32"}, - {"name":"deferred_trx_expiration_window", "type":"uint32"}, - {"name":"max_transaction_delay", "type":"uint32"}, - {"name":"max_inline_action_size", "type":"uint32"}, - {"name":"max_inline_action_depth", "type":"uint16"}, - {"name":"max_authority_depth", "type":"uint16"} - - ] - },{ - "name": "eosio_global_state", - "base": "blockchain_parameters", - "fields": [ - {"name":"max_ram_size", "type":"uint64"}, - {"name":"total_ram_bytes_reserved", "type":"uint64"}, - {"name":"total_ram_stake", "type":"int64"}, - {"name":"last_producer_schedule_update", "type":"block_timestamp_type"}, - {"name":"last_pervote_bucket_fill", "type":"uint64"}, - {"name":"pervote_bucket", "type":"int64"}, - {"name":"perblock_bucket", "type":"int64"}, - {"name":"total_unpaid_blocks", "type":"uint32"}, - {"name":"total_activated_stake", "type":"int64"}, - {"name":"thresh_activated_stake_time", "type":"uint64"}, - {"name":"last_producer_schedule_size", "type":"uint16"}, - {"name":"total_producer_vote_weight", "type":"float64"}, - {"name":"last_name_close", "type":"block_timestamp_type"} - ] - },{ - "name": "producer_info", - "base": "", - "fields": [ - {"name":"owner", "type":"account_name"}, - {"name":"total_votes", "type":"float64"}, - {"name":"producer_key", "type":"public_key"}, - {"name":"is_active", "type":"bool"}, - {"name":"url", "type":"string"}, - {"name":"unpaid_blocks", "type":"uint32"}, - {"name":"last_claim_time", "type":"uint64"}, - {"name":"location", "type":"uint16"} - ] - },{ - "name": "regproducer", - "base": "", - "fields": [ - {"name":"producer", "type":"account_name"}, - {"name":"producer_key", "type":"public_key"}, - {"name":"url", "type":"string"}, - {"name":"location", "type":"uint16"} - ] - },{ - "name": "unregprod", - "base": "", - "fields": [ - {"name":"producer", "type":"account_name"} - ] - },{ - "name": "setram", - "base": "", - "fields": [ - {"name":"max_ram_size", "type":"uint64"} - ] - },{ - "name": "regproxy", - "base": "", - "fields": [ - {"name":"proxy", "type":"account_name"}, - {"name":"isproxy", "type":"bool"} - ] - },{ - "name": "voteproducer", - "base": "", - "fields": [ - {"name":"voter", "type":"account_name"}, - {"name":"proxy", "type":"account_name"}, - {"name":"producers", "type":"account_name[]"} - ] - },{ - "name": "voter_info", - "base": "", - "fields": [ - {"name":"owner", "type":"account_name"}, - {"name":"proxy", "type":"account_name"}, - {"name":"producers", "type":"account_name[]"}, - {"name":"staked", "type":"int64"}, - {"name":"last_vote_weight", "type":"float64"}, - {"name":"proxied_vote_weight", "type":"float64"}, - {"name":"is_proxy", "type":"bool"} - ] - },{ - "name": "claimrewards", - "base": "", - "fields": [ - {"name":"owner", "type":"account_name"} - ] - },{ - "name": "setpriv", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"is_priv", "type":"int8"} - ] - },{ - "name": "rmvproducer", - "base": "", - "fields": [ - {"name":"producer", "type":"account_name"} - ] - },{ - "name": "set_account_limits", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"}, - {"name":"ram_bytes", "type":"int64"}, - {"name":"net_weight", "type":"int64"}, - {"name":"cpu_weight", "type":"int64"} - ] - },{ - "name": "set_global_limits", - "base": "", - "fields": [ - {"name":"cpu_usec_per_period", "type":"int64"} - ] - },{ - "name": "producer_key", - "base": "", - "fields": [ - {"name":"producer_name", "type":"account_name"}, - {"name":"block_signing_key", "type":"public_key"} - ] - },{ - "name": "set_producers", - "base": "", - "fields": [ - {"name":"schedule", "type":"producer_key[]"} - ] - },{ - "name": "require_auth", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"} - ] - },{ - "name": "setparams", - "base": "", - "fields": [ - {"name":"params", "type":"blockchain_parameters"} - ] - },{ - "name": "connector", - "base": "", - "fields": [ - {"name":"balance", "type":"asset"}, - {"name":"weight", "type":"float64"} - ] - },{ - "name": "exchange_state", - "base": "", - "fields": [ - {"name":"supply", "type":"asset"}, - {"name":"base", "type":"connector"}, - {"name":"quote", "type":"connector"} - ] - }, { - "name": "namebid_info", - "base": "", - "fields": [ - {"name":"newname", "type":"account_name"}, - {"name":"high_bidder", "type":"account_name"}, - {"name":"high_bid", "type":"int64"}, - {"name":"last_bid_time", "type":"uint64"} - ] - } - ], - "actions": [{ - "name": "newaccount", - "type": "newaccount", - "ricardian_contract": "" - },{ - "name": "setcode", - "type": "setcode", - "ricardian_contract": "" - },{ - "name": "setabi", - "type": "setabi", - "ricardian_contract": "" - },{ - "name": "updateauth", - "type": "updateauth", - "ricardian_contract": "" - },{ - "name": "deleteauth", - "type": "deleteauth", - "ricardian_contract": "" - },{ - "name": "linkauth", - "type": "linkauth", - "ricardian_contract": "" - },{ - "name": "unlinkauth", - "type": "unlinkauth", - "ricardian_contract": "" - },{ - "name": "canceldelay", - "type": "canceldelay", - "ricardian_contract": "" - },{ - "name": "onerror", - "type": "onerror", - "ricardian_contract": "" - },{ - "name": "buyrambytes", - "type": "buyrambytes", - "ricardian_contract": "" - },{ - "name": "buyram", - "type": "buyram", - "ricardian_contract": "" - },{ - "name": "sellram", - "type": "sellram", - "ricardian_contract": "" - },{ - "name": "delegatebw", - "type": "delegatebw", - "ricardian_contract": "" - },{ - "name": "undelegatebw", - "type": "undelegatebw", - "ricardian_contract": "" - },{ - "name": "refund", - "type": "refund", - "ricardian_contract": "" - },{ - "name": "regproducer", - "type": "regproducer", - "ricardian_contract": "" - },{ - "name": "setram", - "type": "setram", - "ricardian_contract": "" - },{ - "name": "bidname", - "type": "bidname", - "ricardian_contract": "" - },{ - "name": "unregprod", - "type": "unregprod", - "ricardian_contract": "" - },{ - "name": "regproxy", - "type": "regproxy", - "ricardian_contract": "" - },{ - "name": "voteproducer", - "type": "voteproducer", - "ricardian_contract": "" - },{ - "name": "claimrewards", - "type": "claimrewards", - "ricardian_contract": "" - },{ - "name": "setpriv", - "type": "setpriv", - "ricardian_contract": "" - },{ - "name": "rmvproducer", - "type": "rmvproducer", - "ricardian_contract": "" - },{ - "name": "setalimits", - "type": "set_account_limits", - "ricardian_contract": "" - },{ - "name": "setglimits", - "type": "set_global_limits", - "ricardian_contract": "" - },{ - "name": "setprods", - "type": "set_producers", - "ricardian_contract": "" - },{ - "name": "reqauth", - "type": "require_auth", - "ricardian_contract": "" - },{ - "name": "setparams", - "type": "setparams", - "ricardian_contract": "" - }], - "tables": [{ - "name": "producers", - "type": "producer_info", - "index_type": "i64", - "key_names" : ["owner"], - "key_types" : ["uint64"] - },{ - "name": "global", - "type": "eosio_global_state", - "index_type": "i64", - "key_names" : [], - "key_types" : [] - },{ - "name": "voters", - "type": "voter_info", - "index_type": "i64", - "key_names" : ["owner"], - "key_types" : ["account_name"] - },{ - "name": "userres", - "type": "user_resources", - "index_type": "i64", - "key_names" : ["owner"], - "key_types" : ["uint64"] - },{ - "name": "delband", - "type": "delegated_bandwidth", - "index_type": "i64", - "key_names" : ["to"], - "key_types" : ["uint64"] - },{ - "name": "rammarket", - "type": "exchange_state", - "index_type": "i64", - "key_names" : ["supply"], - "key_types" : ["uint64"] - },{ - "name": "refunds", - "type": "refund_request", - "index_type": "i64", - "key_names" : ["owner"], - "key_types" : ["uint64"] - },{ - "name": "namebids", - "type": "namebid_info", - "index_type": "i64", - "key_names" : ["newname"], - "key_types" : ["account_name"] - } - ], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/eosio.system/eosio.system.cpp b/contracts/eosio.system/eosio.system.cpp deleted file mode 100644 index daf40efbb84..00000000000 --- a/contracts/eosio.system/eosio.system.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#include "eosio.system.hpp" -#include - -#include "producer_pay.cpp" -#include "delegate_bandwidth.cpp" -#include "voting.cpp" -#include "exchange_state.cpp" - - -namespace eosiosystem { - - system_contract::system_contract( account_name s ) - :native(s), - _voters(_self,_self), - _producers(_self,_self), - _global(_self,_self), - _rammarket(_self,_self) - { - //print( "construct system\n" ); - _gstate = _global.exists() ? _global.get() : get_default_parameters(); - - auto itr = _rammarket.find(S(4,RAMCORE)); - - if( itr == _rammarket.end() ) { - auto system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount; - if( system_token_supply > 0 ) { - itr = _rammarket.emplace( _self, [&]( auto& m ) { - m.supply.amount = 100000000000000ll; - m.supply.symbol = S(4,RAMCORE); - m.base.balance.amount = int64_t(_gstate.free_ram()); - m.base.balance.symbol = S(0,RAM); - m.quote.balance.amount = system_token_supply / 1000; - m.quote.balance.symbol = CORE_SYMBOL; - }); - } - } else { - //print( "ram market already created" ); - } - } - - eosio_global_state system_contract::get_default_parameters() { - eosio_global_state dp; - get_blockchain_parameters(dp); - return dp; - } - - - system_contract::~system_contract() { - //print( "destruct system\n" ); - _global.set( _gstate, _self ); - //eosio_exit(0); - } - - void system_contract::setram( uint64_t max_ram_size ) { - require_auth( _self ); - - eosio_assert( _gstate.max_ram_size < max_ram_size, "ram may only be increased" ); /// decreasing ram might result market maker issues - eosio_assert( max_ram_size < 1024ll*1024*1024*1024*1024, "ram size is unrealistic" ); - eosio_assert( max_ram_size > _gstate.total_ram_bytes_reserved, "attempt to set max below reserved" ); - - auto delta = int64_t(max_ram_size) - int64_t(_gstate.max_ram_size); - auto itr = _rammarket.find(S(4,RAMCORE)); - - /** - * Increase or decrease the amount of ram for sale based upon the change in max - * ram size. - */ - _rammarket.modify( itr, 0, [&]( auto& m ) { - m.base.balance.amount += delta; - }); - - _gstate.max_ram_size = max_ram_size; - _global.set( _gstate, _self ); - } - - void system_contract::setparams( const eosio::blockchain_parameters& params ) { - require_auth( N(eosio) ); - (eosio::blockchain_parameters&)(_gstate) = params; - eosio_assert( 3 <= _gstate.max_authority_depth, "max_authority_depth should be at least 3" ); - set_blockchain_parameters( params ); - } - - void system_contract::setpriv( account_name account, uint8_t ispriv ) { - require_auth( _self ); - set_privileged( account, ispriv ); - } - - void system_contract::rmvproducer( account_name producer ) { - require_auth( _self ); - auto prod = _producers.find( producer ); - eosio_assert( prod != _producers.end(), "producer not found" ); - _producers.modify( prod, 0, [&](auto& p) { - p.deactivate(); - }); - } - - void system_contract::bidname( account_name bidder, account_name newname, asset bid ) { - require_auth( bidder ); - eosio_assert( eosio::name_suffix(newname) == newname, "you can only bid on top-level suffix" ); - eosio_assert( newname != 0, "the empty name is not a valid account name to bid on" ); - eosio_assert( (newname & 0xFull) == 0, "13 character names are not valid account names to bid on" ); - eosio_assert( (newname & 0x1F0ull) == 0, "accounts with 12 character names and no dots can be created without bidding required" ); - eosio_assert( !is_account( newname ), "account already exists" ); - eosio_assert( bid.symbol == asset().symbol, "asset must be system token" ); - eosio_assert( bid.amount > 0, "insufficient bid" ); - - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {bidder,N(active)}, - { bidder, N(eosio.names), bid, std::string("bid name ")+(name{newname}).to_string() } ); - - name_bid_table bids(_self,_self); - print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" ); - auto current = bids.find( newname ); - if( current == bids.end() ) { - bids.emplace( bidder, [&]( auto& b ) { - b.newname = newname; - b.high_bidder = bidder; - b.high_bid = bid.amount; - b.last_bid_time = current_time(); - }); - } else { - eosio_assert( current->high_bid > 0, "this auction has already closed" ); - eosio_assert( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" ); - eosio_assert( current->high_bidder != bidder, "account is already highest bidder" ); - - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.names),N(active)}, - { N(eosio.names), current->high_bidder, asset(current->high_bid), - std::string("refund bid on name ")+(name{newname}).to_string() } ); - - bids.modify( current, bidder, [&]( auto& b ) { - b.high_bidder = bidder; - b.high_bid = bid.amount; - b.last_bid_time = current_time(); - }); - } - } - - /** - * Called after a new account is created. This code enforces resource-limits rules - * for new accounts as well as new account naming conventions. - * - * Account names containing '.' symbols must have a suffix equal to the name of the creator. - * This allows users who buy a premium name (shorter than 12 characters with no dots) to be the only ones - * who can create accounts with the creator's name as a suffix. - * - */ - void native::newaccount( account_name creator, - account_name newact - /* no need to parse authorities - const authority& owner, - const authority& active*/ ) { - - if( creator != _self ) { - auto tmp = newact >> 4; - bool has_dot = false; - - for( uint32_t i = 0; i < 12; ++i ) { - has_dot |= !(tmp & 0x1f); - tmp >>= 5; - } - if( has_dot ) { // or is less than 12 characters - auto suffix = eosio::name_suffix(newact); - if( suffix == newact ) { - name_bid_table bids(_self,_self); - auto current = bids.find( newact ); - eosio_assert( current != bids.end(), "no active bid for name" ); - eosio_assert( current->high_bidder == creator, "only highest bidder can claim" ); - eosio_assert( current->high_bid < 0, "auction for name is not closed yet" ); - bids.erase( current ); - } else { - eosio_assert( creator == suffix, "only suffix may create this account" ); - } - } - } - - user_resources_table userres( _self, newact); - - userres.emplace( newact, [&]( auto& res ) { - res.owner = newact; - }); - - set_resource_limits( newact, 0, 0, 0 ); - } - -} /// eosio.system - - -EOSIO_ABI( eosiosystem::system_contract, - // native.hpp (newaccount definition is actually in eosio.system.cpp) - (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror) - // eosio.system.cpp - (setram)(setparams)(setpriv)(rmvproducer)(bidname) - // delegate_bandwidth.cpp - (buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund) - // voting.cpp - (regproducer)(unregprod)(voteproducer)(regproxy) - // producer_pay.cpp - (onblock)(claimrewards) -) diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp deleted file mode 100644 index f66375aef0b..00000000000 --- a/contracts/eosio.system/eosio.system.hpp +++ /dev/null @@ -1,236 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -namespace eosiosystem { - - using eosio::asset; - using eosio::indexed_by; - using eosio::const_mem_fun; - using eosio::block_timestamp; - - struct name_bid { - account_name newname; - account_name high_bidder; - int64_t high_bid = 0; ///< negative high_bid == closed auction waiting to be claimed - uint64_t last_bid_time = 0; - - auto primary_key()const { return newname; } - uint64_t by_high_bid()const { return static_cast(-high_bid); } - }; - - typedef eosio::multi_index< N(namebids), name_bid, - indexed_by > - > name_bid_table; - - - struct eosio_global_state : eosio::blockchain_parameters { - uint64_t free_ram()const { return max_ram_size - total_ram_bytes_reserved; } - - uint64_t max_ram_size = 64ll*1024 * 1024 * 1024; - uint64_t total_ram_bytes_reserved = 0; - int64_t total_ram_stake = 0; - - block_timestamp last_producer_schedule_update; - uint64_t last_pervote_bucket_fill = 0; - int64_t pervote_bucket = 0; - int64_t perblock_bucket = 0; - uint32_t total_unpaid_blocks = 0; /// all blocks which have been produced but not paid - int64_t total_activated_stake = 0; - uint64_t thresh_activated_stake_time = 0; - uint16_t last_producer_schedule_size = 0; - double total_producer_vote_weight = 0; /// the sum of all producer votes - block_timestamp last_name_close; - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE_DERIVED( eosio_global_state, eosio::blockchain_parameters, - (max_ram_size)(total_ram_bytes_reserved)(total_ram_stake) - (last_producer_schedule_update)(last_pervote_bucket_fill) - (pervote_bucket)(perblock_bucket)(total_unpaid_blocks)(total_activated_stake)(thresh_activated_stake_time) - (last_producer_schedule_size)(total_producer_vote_weight)(last_name_close) ) - }; - - struct producer_info { - account_name owner; - double total_votes = 0; - eosio::public_key producer_key; /// a packed public key object - bool is_active = true; - std::string url; - uint32_t unpaid_blocks = 0; - uint64_t last_claim_time = 0; - uint16_t location = 0; - - uint64_t primary_key()const { return owner; } - double by_votes()const { return is_active ? -total_votes : total_votes; } - bool active()const { return is_active; } - void deactivate() { producer_key = public_key(); is_active = false; } - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( producer_info, (owner)(total_votes)(producer_key)(is_active)(url) - (unpaid_blocks)(last_claim_time)(location) ) - }; - - struct voter_info { - account_name owner = 0; /// the voter - account_name proxy = 0; /// the proxy set by the voter, if any - std::vector producers; /// the producers approved by this voter if no proxy set - int64_t staked = 0; - - /** - * Every time a vote is cast we must first "undo" the last vote weight, before casting the - * new vote weight. Vote weight is calculated as: - * - * stated.amount * 2 ^ ( weeks_since_launch/weeks_per_year) - */ - double last_vote_weight = 0; /// the vote weight cast the last time the vote was updated - - /** - * Total vote weight delegated to this voter. - */ - double proxied_vote_weight= 0; /// the total vote weight delegated to this voter as a proxy - bool is_proxy = 0; /// whether the voter is a proxy for others - - - uint32_t reserved1 = 0; - time reserved2 = 0; - eosio::asset reserved3; - - uint64_t primary_key()const { return owner; } - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( voter_info, (owner)(proxy)(producers)(staked)(last_vote_weight)(proxied_vote_weight)(is_proxy)(reserved1)(reserved2)(reserved3) ) - }; - - typedef eosio::multi_index< N(voters), voter_info> voters_table; - - - typedef eosio::multi_index< N(producers), producer_info, - indexed_by > - > producers_table; - - typedef eosio::singleton global_state_singleton; - - // static constexpr uint32_t max_inflation_rate = 5; // 5% annual inflation - static constexpr uint32_t seconds_per_day = 24 * 3600; - static constexpr uint64_t system_token_symbol = CORE_SYMBOL; - - class system_contract : public native { - private: - voters_table _voters; - producers_table _producers; - global_state_singleton _global; - - eosio_global_state _gstate; - rammarket _rammarket; - - public: - system_contract( account_name s ); - ~system_contract(); - - // Actions: - void onblock( block_timestamp timestamp, account_name producer ); - // const block_header& header ); /// only parse first 3 fields of block header - - // functions defined in delegate_bandwidth.cpp - - /** - * Stakes SYS from the balance of 'from' for the benfit of 'receiver'. - * If transfer == true, then 'receiver' can unstake to their account - * Else 'from' can unstake at any time. - */ - void delegatebw( account_name from, account_name receiver, - asset stake_net_quantity, asset stake_cpu_quantity, bool transfer ); - - - /** - * Decreases the total tokens delegated by from to receiver and/or - * frees the memory associated with the delegation if there is nothing - * left to delegate. - * - * This will cause an immediate reduction in net/cpu bandwidth of the - * receiver. - * - * A transaction is scheduled to send the tokens back to 'from' after - * the staking period has passed. If existing transaction is scheduled, it - * will be canceled and a new transaction issued that has the combined - * undelegated amount. - * - * The 'from' account loses voting power as a result of this call and - * all producer tallies are updated. - */ - void undelegatebw( account_name from, account_name receiver, - asset unstake_net_quantity, asset unstake_cpu_quantity ); - - - /** - * Increases receiver's ram quota based upon current price and quantity of - * tokens provided. An inline transfer from receiver to system contract of - * tokens will be executed. - */ - void buyram( account_name buyer, account_name receiver, asset tokens ); - void buyrambytes( account_name buyer, account_name receiver, uint32_t bytes ); - - /** - * Reduces quota my bytes and then performs an inline transfer of tokens - * to receiver based upon the average purchase price of the original quota. - */ - void sellram( account_name receiver, int64_t bytes ); - - /** - * This action is called after the delegation-period to claim all pending - * unstaked tokens belonging to owner - */ - void refund( account_name owner ); - - // functions defined in voting.cpp - - void regproducer( const account_name producer, const public_key& producer_key, const std::string& url, uint16_t location ); - - void unregprod( const account_name producer ); - - void setram( uint64_t max_ram_size ); - - void voteproducer( const account_name voter, const account_name proxy, const std::vector& producers ); - - void regproxy( const account_name proxy, bool isproxy ); - - void setparams( const eosio::blockchain_parameters& params ); - - // functions defined in producer_pay.cpp - void claimrewards( const account_name& owner ); - - void setpriv( account_name account, uint8_t ispriv ); - - void rmvproducer( account_name producer ); - - void bidname( account_name bidder, account_name newname, asset bid ); - private: - void update_elected_producers( block_timestamp timestamp ); - - // Implementation details: - - //defind in delegate_bandwidth.cpp - void changebw( account_name from, account_name receiver, - asset stake_net_quantity, asset stake_cpu_quantity, bool transfer ); - - //defined in voting.hpp - static eosio_global_state get_default_parameters(); - - void update_votes( const account_name voter, const account_name proxy, const std::vector& producers, bool voting ); - - // defined in voting.cpp - void propagate_weight_change( const voter_info& voter ); - }; - -} /// eosiosystem diff --git a/contracts/eosio.system/exchange_state.cpp b/contracts/eosio.system/exchange_state.cpp deleted file mode 100644 index 621d3e714b3..00000000000 --- a/contracts/eosio.system/exchange_state.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include - -namespace eosiosystem { - asset exchange_state::convert_to_exchange( connector& c, asset in ) { - - real_type R(supply.amount); - real_type C(c.balance.amount+in.amount); - real_type F(c.weight/1000.0); - real_type T(in.amount); - real_type ONE(1.0); - - real_type E = -R * (ONE - std::pow( ONE + T / C, F) ); - //print( "E: ", E, "\n"); - int64_t issued = int64_t(E); - - supply.amount += issued; - c.balance.amount += in.amount; - - return asset( issued, supply.symbol ); - } - - asset exchange_state::convert_from_exchange( connector& c, asset in ) { - eosio_assert( in.symbol== supply.symbol, "unexpected asset symbol input" ); - - real_type R(supply.amount - in.amount); - real_type C(c.balance.amount); - real_type F(1000.0/c.weight); - real_type E(in.amount); - real_type ONE(1.0); - - - // potentially more accurate: - // The functions std::expm1 and std::log1p are useful for financial calculations, for example, - // when calculating small daily interest rates: (1+x)n - // -1 can be expressed as std::expm1(n * std::log1p(x)). - // real_type T = C * std::expm1( F * std::log1p(E/R) ); - - real_type T = C * (std::pow( ONE + E/R, F) - ONE); - //print( "T: ", T, "\n"); - int64_t out = int64_t(T); - - supply.amount -= in.amount; - c.balance.amount -= out; - - return asset( out, c.balance.symbol ); - } - - asset exchange_state::convert( asset from, symbol_type to ) { - auto sell_symbol = from.symbol; - auto ex_symbol = supply.symbol; - auto base_symbol = base.balance.symbol; - auto quote_symbol = quote.balance.symbol; - - //print( "From: ", from, " TO ", asset( 0,to), "\n" ); - //print( "base: ", base_symbol, "\n" ); - //print( "quote: ", quote_symbol, "\n" ); - //print( "ex: ", supply.symbol, "\n" ); - - if( sell_symbol != ex_symbol ) { - if( sell_symbol == base_symbol ) { - from = convert_to_exchange( base, from ); - } else if( sell_symbol == quote_symbol ) { - from = convert_to_exchange( quote, from ); - } else { - eosio_assert( false, "invalid sell" ); - } - } else { - if( to == base_symbol ) { - from = convert_from_exchange( base, from ); - } else if( to == quote_symbol ) { - from = convert_from_exchange( quote, from ); - } else { - eosio_assert( false, "invalid conversion" ); - } - } - - if( to != from.symbol ) - return convert( from, to ); - - return from; - } - - - -} /// namespace eosiosystem diff --git a/contracts/eosio.system/exchange_state.hpp b/contracts/eosio.system/exchange_state.hpp deleted file mode 100644 index 3705a9b8b98..00000000000 --- a/contracts/eosio.system/exchange_state.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -namespace eosiosystem { - using eosio::asset; - using eosio::symbol_type; - - typedef double real_type; - - /** - * Uses Bancor math to create a 50/50 relay between two asset types. The state of the - * bancor exchange is entirely contained within this struct. There are no external - * side effects associated with using this API. - */ - struct exchange_state { - asset supply; - - struct connector { - asset balance; - double weight = .5; - - EOSLIB_SERIALIZE( connector, (balance)(weight) ) - }; - - connector base; - connector quote; - - uint64_t primary_key()const { return supply.symbol; } - - asset convert_to_exchange( connector& c, asset in ); - asset convert_from_exchange( connector& c, asset in ); - asset convert( asset from, symbol_type to ); - - EOSLIB_SERIALIZE( exchange_state, (supply)(base)(quote) ) - }; - - typedef eosio::multi_index rammarket; - -} /// namespace eosiosystem diff --git a/contracts/eosio.system/native.hpp b/contracts/eosio.system/native.hpp deleted file mode 100644 index e2bcb319575..00000000000 --- a/contracts/eosio.system/native.hpp +++ /dev/null @@ -1,112 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace eosiosystem { - using eosio::permission_level; - using eosio::public_key; - - typedef std::vector bytes; - - struct permission_level_weight { - permission_level permission; - weight_type weight; - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( permission_level_weight, (permission)(weight) ) - }; - - struct key_weight { - public_key key; - weight_type weight; - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( key_weight, (key)(weight) ) - }; - - struct authority { - uint32_t threshold; - uint32_t delay_sec; - std::vector keys; - std::vector accounts; - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( authority, (threshold)(delay_sec)(keys)(accounts) ) - }; - - struct block_header { - uint32_t timestamp; - account_name producer; - uint16_t confirmed = 0; - block_id_type previous; - checksum256 transaction_mroot; - checksum256 action_mroot; - uint32_t schedule_version = 0; - eosio::optional new_producers; - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE(block_header, (timestamp)(producer)(confirmed)(previous)(transaction_mroot)(action_mroot) - (schedule_version)(new_producers)) - }; - - - /* - * Method parameters commented out to prevent generation of code that parses input data. - */ - class native : public eosio::contract { - public: - - using eosio::contract::contract; - - /** - * Called after a new account is created. This code enforces resource-limits rules - * for new accounts as well as new account naming conventions. - * - * 1. accounts cannot contain '.' symbols which forces all acccounts to be 12 - * characters long without '.' until a future account auction process is implemented - * which prevents name squatting. - * - * 2. new accounts must stake a minimal number of tokens (as set in system parameters) - * therefore, this method will execute an inline buyram from receiver for newacnt in - * an amount equal to the current new account creation fee. - */ - void newaccount( account_name creator, - account_name newact - /* no need to parse authorites - const authority& owner, - const authority& active*/ ); - - - void updateauth( /*account_name account, - permission_name permission, - permission_name parent, - const authority& data*/ ) {} - - void deleteauth( /*account_name account, permission_name permission*/ ) {} - - void linkauth( /*account_name account, - account_name code, - action_name type, - permission_name requirement*/ ) {} - - void unlinkauth( /*account_name account, - account_name code, - action_name type*/ ) {} - - void canceldelay( /*permission_level canceling_auth, transaction_id_type trx_id*/ ) {} - - void onerror( /*const bytes&*/ ) {} - - }; -} diff --git a/contracts/eosio.system/producer_pay.cpp b/contracts/eosio.system/producer_pay.cpp deleted file mode 100644 index 1d0af68d432..00000000000 --- a/contracts/eosio.system/producer_pay.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "eosio.system.hpp" - -#include - -namespace eosiosystem { - - const int64_t min_pervote_daily_pay = 100'0000; - const int64_t min_activated_stake = 150'000'000'0000; - const double continuous_rate = 0.04879; // 5% annual rate - const double perblock_rate = 0.0025; // 0.25% - const double standby_rate = 0.0075; // 0.75% - const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year - const uint32_t seconds_per_year = 52*7*24*3600; - const uint32_t blocks_per_day = 2 * 24 * 3600; - const uint32_t blocks_per_hour = 2 * 3600; - const uint64_t useconds_per_day = 24 * 3600 * uint64_t(1000000); - const uint64_t useconds_per_year = seconds_per_year*1000000ll; - - - void system_contract::onblock( block_timestamp timestamp, account_name producer ) { - using namespace eosio; - - require_auth(N(eosio)); - - /** until activated stake crosses this threshold no new rewards are paid */ - if( _gstate.total_activated_stake < min_activated_stake ) - return; - - if( _gstate.last_pervote_bucket_fill == 0 ) /// start the presses - _gstate.last_pervote_bucket_fill = current_time(); - - - /** - * At startup the initial producer may not be one that is registered / elected - * and therefore there may be no producer object for them. - */ - auto prod = _producers.find(producer); - if ( prod != _producers.end() ) { - _gstate.total_unpaid_blocks++; - _producers.modify( prod, 0, [&](auto& p ) { - p.unpaid_blocks++; - }); - } - - /// only update block producers once every minute, block_timestamp is in half seconds - if( timestamp.slot - _gstate.last_producer_schedule_update.slot > 120 ) { - update_elected_producers( timestamp ); - - if( (timestamp.slot - _gstate.last_name_close.slot) > blocks_per_day ) { - name_bid_table bids(_self,_self); - auto idx = bids.get_index(); - auto highest = idx.begin(); - if( highest != idx.end() && - highest->high_bid > 0 && - highest->last_bid_time < (current_time() - useconds_per_day) && - _gstate.thresh_activated_stake_time > 0 && - (current_time() - _gstate.thresh_activated_stake_time) > 14 * useconds_per_day ) { - _gstate.last_name_close = timestamp; - idx.modify( highest, 0, [&]( auto& b ){ - b.high_bid = -b.high_bid; - }); - } - } - } - } - - using namespace eosio; - void system_contract::claimrewards( const account_name& owner ) { - require_auth(owner); - - const auto& prod = _producers.get( owner ); - eosio_assert( prod.active(), "producer does not have an active key" ); - - eosio_assert( _gstate.total_activated_stake >= min_activated_stake, - "cannot claim rewards until the chain is activated (at least 15% of all tokens participate in voting)" ); - - auto ct = current_time(); - - eosio_assert( ct - prod.last_claim_time > useconds_per_day, "already claimed rewards within past day" ); - - const asset token_supply = token( N(eosio.token)).get_supply(symbol_type(system_token_symbol).name() ); - const auto usecs_since_last_fill = ct - _gstate.last_pervote_bucket_fill; - - if( usecs_since_last_fill > 0 && _gstate.last_pervote_bucket_fill > 0 ) { - auto new_tokens = static_cast( (continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year) ); - - auto to_producers = new_tokens / 5; - auto to_savings = new_tokens - to_producers; - auto to_per_block_pay = to_producers / 4; - auto to_per_vote_pay = to_producers - to_per_block_pay; - - INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}}, - {N(eosio), asset(new_tokens), std::string("issue tokens for producer pay and savings")} ); - - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, - { N(eosio), N(eosio.saving), asset(to_savings), "unallocated inflation" } ); - - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, - { N(eosio), N(eosio.bpay), asset(to_per_block_pay), "fund per-block bucket" } ); - - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, - { N(eosio), N(eosio.vpay), asset(to_per_vote_pay), "fund per-vote bucket" } ); - - _gstate.pervote_bucket += to_per_vote_pay; - _gstate.perblock_bucket += to_per_block_pay; - - _gstate.last_pervote_bucket_fill = ct; - } - - int64_t producer_per_block_pay = 0; - if( _gstate.total_unpaid_blocks > 0 ) { - producer_per_block_pay = (_gstate.perblock_bucket * prod.unpaid_blocks) / _gstate.total_unpaid_blocks; - } - int64_t producer_per_vote_pay = 0; - if( _gstate.total_producer_vote_weight > 0 ) { - producer_per_vote_pay = int64_t((_gstate.pervote_bucket * prod.total_votes ) / _gstate.total_producer_vote_weight); - } - if( producer_per_vote_pay < min_pervote_daily_pay ) { - producer_per_vote_pay = 0; - } - _gstate.pervote_bucket -= producer_per_vote_pay; - _gstate.perblock_bucket -= producer_per_block_pay; - _gstate.total_unpaid_blocks -= prod.unpaid_blocks; - - _producers.modify( prod, 0, [&](auto& p) { - p.last_claim_time = ct; - p.unpaid_blocks = 0; - }); - - if( producer_per_block_pay > 0 ) { - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.bpay),N(active)}, - { N(eosio.bpay), owner, asset(producer_per_block_pay), std::string("producer block pay") } ); - } - if( producer_per_vote_pay > 0 ) { - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.vpay),N(active)}, - { N(eosio.vpay), owner, asset(producer_per_vote_pay), std::string("producer vote pay") } ); - } - } - -} //namespace eosiosystem diff --git a/contracts/eosio.system/voting.cpp b/contracts/eosio.system/voting.cpp deleted file mode 100644 index bf82c913802..00000000000 --- a/contracts/eosio.system/voting.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include "eosio.system.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace eosiosystem { - using eosio::indexed_by; - using eosio::const_mem_fun; - using eosio::bytes; - using eosio::print; - using eosio::singleton; - using eosio::transaction; - - /** - * This method will create a producer_config and producer_info object for 'producer' - * - * @pre producer is not already registered - * @pre producer to register is an account - * @pre authority of producer to register - * - */ - void system_contract::regproducer( const account_name producer, const eosio::public_key& producer_key, const std::string& url, uint16_t location ) { - eosio_assert( url.size() < 512, "url too long" ); - eosio_assert( producer_key != eosio::public_key(), "public key should not be the default value" ); - require_auth( producer ); - - auto prod = _producers.find( producer ); - - if ( prod != _producers.end() ) { - _producers.modify( prod, producer, [&]( producer_info& info ){ - info.producer_key = producer_key; - info.is_active = true; - info.url = url; - info.location = location; - }); - } else { - _producers.emplace( producer, [&]( producer_info& info ){ - info.owner = producer; - info.total_votes = 0; - info.producer_key = producer_key; - info.is_active = true; - info.url = url; - info.location = location; - }); - } - } - - void system_contract::unregprod( const account_name producer ) { - require_auth( producer ); - - const auto& prod = _producers.get( producer, "producer not found" ); - - _producers.modify( prod, 0, [&]( producer_info& info ){ - info.deactivate(); - }); - } - - void system_contract::update_elected_producers( block_timestamp block_time ) { - _gstate.last_producer_schedule_update = block_time; - - auto idx = _producers.get_index(); - - std::vector< std::pair > top_producers; - top_producers.reserve(21); - - for ( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { - top_producers.emplace_back( std::pair({{it->owner, it->producer_key}, it->location}) ); - } - - if ( top_producers.size() < _gstate.last_producer_schedule_size ) { - return; - } - - /// sort by producer name - std::sort( top_producers.begin(), top_producers.end() ); - - std::vector producers; - - producers.reserve(top_producers.size()); - for( const auto& item : top_producers ) - producers.push_back(item.first); - - bytes packed_schedule = pack(producers); - - if( set_proposed_producers( packed_schedule.data(), packed_schedule.size() ) >= 0 ) { - _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); - } - } - - double stake2vote( int64_t staked ) { - /// TODO subtract 2080 brings the large numbers closer to this decade - double weight = int64_t( (now() - (block_timestamp::block_timestamp_epoch / 1000)) / (seconds_per_day * 7) ) / double( 52 ); - return double(staked) * std::pow( 2, weight ); - } - /** - * @pre producers must be sorted from lowest to highest and must be registered and active - * @pre if proxy is set then no producers can be voted for - * @pre if proxy is set then proxy account must exist and be registered as a proxy - * @pre every listed producer or proxy must have been previously registered - * @pre voter must authorize this action - * @pre voter must have previously staked some EOS for voting - * @pre voter->staked must be up to date - * - * @post every producer previously voted for will have vote reduced by previous vote weight - * @post every producer newly voted for will have vote increased by new vote amount - * @post prior proxy will proxied_vote_weight decremented by previous vote weight - * @post new proxy will proxied_vote_weight incremented by new vote weight - * - * If voting for a proxy, the producer votes will not change until the proxy updates their own vote. - */ - void system_contract::voteproducer( const account_name voter_name, const account_name proxy, const std::vector& producers ) { - require_auth( voter_name ); - update_votes( voter_name, proxy, producers, true ); - } - - void system_contract::update_votes( const account_name voter_name, const account_name proxy, const std::vector& producers, bool voting ) { - //validate input - if ( proxy ) { - eosio_assert( producers.size() == 0, "cannot vote for producers and proxy at same time" ); - eosio_assert( voter_name != proxy, "cannot proxy to self" ); - require_recipient( proxy ); - } else { - eosio_assert( producers.size() <= 30, "attempt to vote for too many producers" ); - for( size_t i = 1; i < producers.size(); ++i ) { - eosio_assert( producers[i-1] < producers[i], "producer votes must be unique and sorted" ); - } - } - - auto voter = _voters.find(voter_name); - eosio_assert( voter != _voters.end(), "user must stake before they can vote" ); /// staking creates voter object - eosio_assert( !proxy || !voter->is_proxy, "account registered as a proxy is not allowed to use a proxy" ); - - /** - * The first time someone votes we calculate and set last_vote_weight, since they cannot unstake until - * after total_activated_stake hits threshold, we can use last_vote_weight to determine that this is - * their first vote and should consider their stake activated. - */ - if( voter->last_vote_weight <= 0.0 ) { - _gstate.total_activated_stake += voter->staked; - if( _gstate.total_activated_stake >= min_activated_stake && _gstate.thresh_activated_stake_time == 0 ) { - _gstate.thresh_activated_stake_time = current_time(); - } - } - - auto new_vote_weight = stake2vote( voter->staked ); - if( voter->is_proxy ) { - new_vote_weight += voter->proxied_vote_weight; - } - - boost::container::flat_map > producer_deltas; - if ( voter->last_vote_weight > 0 ) { - if( voter->proxy ) { - auto old_proxy = _voters.find( voter->proxy ); - eosio_assert( old_proxy != _voters.end(), "old proxy not found" ); //data corruption - _voters.modify( old_proxy, 0, [&]( auto& vp ) { - vp.proxied_vote_weight -= voter->last_vote_weight; - }); - propagate_weight_change( *old_proxy ); - } else { - for( const auto& p : voter->producers ) { - auto& d = producer_deltas[p]; - d.first -= voter->last_vote_weight; - d.second = false; - } - } - } - - if( proxy ) { - auto new_proxy = _voters.find( proxy ); - eosio_assert( new_proxy != _voters.end(), "invalid proxy specified" ); //if ( !voting ) { data corruption } else { wrong vote } - eosio_assert( !voting || new_proxy->is_proxy, "proxy not found" ); - if ( new_vote_weight >= 0 ) { - _voters.modify( new_proxy, 0, [&]( auto& vp ) { - vp.proxied_vote_weight += new_vote_weight; - }); - propagate_weight_change( *new_proxy ); - } - } else { - if( new_vote_weight >= 0 ) { - for( const auto& p : producers ) { - auto& d = producer_deltas[p]; - d.first += new_vote_weight; - d.second = true; - } - } - } - - for( const auto& pd : producer_deltas ) { - auto pitr = _producers.find( pd.first ); - if( pitr != _producers.end() ) { - eosio_assert( !voting || pitr->active() || !pd.second.second /* not from new set */, "producer is not currently registered" ); - _producers.modify( pitr, 0, [&]( auto& p ) { - p.total_votes += pd.second.first; - if ( p.total_votes < 0 ) { // floating point arithmetics can give small negative numbers - p.total_votes = 0; - } - _gstate.total_producer_vote_weight += pd.second.first; - //eosio_assert( p.total_votes >= 0, "something bad happened" ); - }); - } else { - eosio_assert( !pd.second.second /* not from new set */, "producer is not registered" ); //data corruption - } - } - - _voters.modify( voter, 0, [&]( auto& av ) { - av.last_vote_weight = new_vote_weight; - av.producers = producers; - av.proxy = proxy; - }); - } - - /** - * An account marked as a proxy can vote with the weight of other accounts which - * have selected it as a proxy. Other accounts must refresh their voteproducer to - * update the proxy's weight. - * - * @param isproxy - true if proxy wishes to vote on behalf of others, false otherwise - * @pre proxy must have something staked (existing row in voters table) - * @pre new state must be different than current state - */ - void system_contract::regproxy( const account_name proxy, bool isproxy ) { - require_auth( proxy ); - - auto pitr = _voters.find(proxy); - if ( pitr != _voters.end() ) { - eosio_assert( isproxy != pitr->is_proxy, "action has no effect" ); - eosio_assert( !isproxy || !pitr->proxy, "account that uses a proxy is not allowed to become a proxy" ); - _voters.modify( pitr, 0, [&]( auto& p ) { - p.is_proxy = isproxy; - }); - propagate_weight_change( *pitr ); - } else { - _voters.emplace( proxy, [&]( auto& p ) { - p.owner = proxy; - p.is_proxy = isproxy; - }); - } - } - - void system_contract::propagate_weight_change( const voter_info& voter ) { - eosio_assert( voter.proxy == 0 || !voter.is_proxy, "account registered as a proxy is not allowed to use a proxy" ); - double new_weight = stake2vote( voter.staked ); - if ( voter.is_proxy ) { - new_weight += voter.proxied_vote_weight; - } - - /// don't propagate small changes (1 ~= epsilon) - if ( fabs( new_weight - voter.last_vote_weight ) > 1 ) { - if ( voter.proxy ) { - auto& proxy = _voters.get( voter.proxy, "proxy not found" ); //data corruption - _voters.modify( proxy, 0, [&]( auto& p ) { - p.proxied_vote_weight += new_weight - voter.last_vote_weight; - } - ); - propagate_weight_change( proxy ); - } else { - auto delta = new_weight - voter.last_vote_weight; - for ( auto acnt : voter.producers ) { - auto& pitr = _producers.get( acnt, "producer not found" ); //data corruption - _producers.modify( pitr, 0, [&]( auto& p ) { - p.total_votes += delta; - _gstate.total_producer_vote_weight += delta; - }); - } - } - } - _voters.modify( voter, 0, [&]( auto& v ) { - v.last_vote_weight = new_weight; - } - ); - } - -} /// namespace eosiosystem diff --git a/contracts/eosio.token/CMakeLists.txt b/contracts/eosio.token/CMakeLists.txt deleted file mode 100644 index 00ab99ec249..00000000000 --- a/contracts/eosio.token/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET eosio.token - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/eosio.token/eosio.token.abi b/contracts/eosio.token/eosio.token.abi deleted file mode 100644 index d769deb331b..00000000000 --- a/contracts/eosio.token/eosio.token.abi +++ /dev/null @@ -1,78 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - }], - "structs": [{ - "name": "transfer", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"to", "type":"account_name"}, - {"name":"quantity", "type":"asset"}, - {"name":"memo", "type":"string"} - ] - },{ - "name": "create", - "base": "", - "fields": [ - {"name":"issuer", "type":"account_name"}, - {"name":"maximum_supply", "type":"asset"} - ] - },{ - "name": "issue", - "base": "", - "fields": [ - {"name":"to", "type":"account_name"}, - {"name":"quantity", "type":"asset"}, - {"name":"memo", "type":"string"} - ] - },{ - "name": "account", - "base": "", - "fields": [ - {"name":"balance", "type":"asset"} - ] - },{ - "name": "currency_stats", - "base": "", - "fields": [ - {"name":"supply", "type":"asset"}, - {"name":"max_supply", "type":"asset"}, - {"name":"issuer", "type":"account_name"} - ] - } - ], - "actions": [{ - "name": "transfer", - "type": "transfer", - "ricardian_contract": "" - },{ - "name": "issue", - "type": "issue", - "ricardian_contract": "" - }, { - "name": "create", - "type": "create", - "ricardian_contract": "" - } - - ], - "tables": [{ - "name": "accounts", - "type": "account", - "index_type": "i64", - "key_names" : ["currency"], - "key_types" : ["uint64"] - },{ - "name": "stat", - "type": "currency_stats", - "index_type": "i64", - "key_names" : ["currency"], - "key_types" : ["uint64"] - } - ], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/eosio.token/eosio.token.cpp b/contracts/eosio.token/eosio.token.cpp deleted file mode 100644 index 4570b19b5c9..00000000000 --- a/contracts/eosio.token/eosio.token.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ - -#include "eosio.token.hpp" - -namespace eosio { - -void token::create( account_name issuer, - asset maximum_supply ) -{ - require_auth( _self ); - - auto sym = maximum_supply.symbol; - eosio_assert( sym.is_valid(), "invalid symbol name" ); - eosio_assert( maximum_supply.is_valid(), "invalid supply"); - eosio_assert( maximum_supply.amount > 0, "max-supply must be positive"); - - stats statstable( _self, sym.name() ); - auto existing = statstable.find( sym.name() ); - eosio_assert( existing == statstable.end(), "token with symbol already exists" ); - - statstable.emplace( _self, [&]( auto& s ) { - s.supply.symbol = maximum_supply.symbol; - s.max_supply = maximum_supply; - s.issuer = issuer; - }); -} - - -void token::issue( account_name to, asset quantity, string memo ) -{ - auto sym = quantity.symbol; - eosio_assert( sym.is_valid(), "invalid symbol name" ); - eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); - - auto sym_name = sym.name(); - stats statstable( _self, sym_name ); - auto existing = statstable.find( sym_name ); - eosio_assert( existing != statstable.end(), "token with symbol does not exist, create token before issue" ); - const auto& st = *existing; - - require_auth( st.issuer ); - eosio_assert( quantity.is_valid(), "invalid quantity" ); - eosio_assert( quantity.amount > 0, "must issue positive quantity" ); - - eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); - eosio_assert( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply"); - - statstable.modify( st, 0, [&]( auto& s ) { - s.supply += quantity; - }); - - add_balance( st.issuer, quantity, st.issuer ); - - if( to != st.issuer ) { - SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} ); - } -} - -void token::transfer( account_name from, - account_name to, - asset quantity, - string memo ) -{ - eosio_assert( from != to, "cannot transfer to self" ); - require_auth( from ); - eosio_assert( is_account( to ), "to account does not exist"); - auto sym = quantity.symbol.name(); - stats statstable( _self, sym ); - const auto& st = statstable.get( sym ); - - require_recipient( from ); - require_recipient( to ); - - eosio_assert( quantity.is_valid(), "invalid quantity" ); - eosio_assert( quantity.amount > 0, "must transfer positive quantity" ); - eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); - eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); - - - sub_balance( from, quantity ); - add_balance( to, quantity, from ); -} - -void token::sub_balance( account_name owner, asset value ) { - accounts from_acnts( _self, owner ); - - const auto& from = from_acnts.get( value.symbol.name(), "no balance object found" ); - eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" ); - - - if( from.balance.amount == value.amount ) { - from_acnts.erase( from ); - } else { - from_acnts.modify( from, owner, [&]( auto& a ) { - a.balance -= value; - }); - } -} - -void token::add_balance( account_name owner, asset value, account_name ram_payer ) -{ - accounts to_acnts( _self, owner ); - auto to = to_acnts.find( value.symbol.name() ); - if( to == to_acnts.end() ) { - to_acnts.emplace( ram_payer, [&]( auto& a ){ - a.balance = value; - }); - } else { - to_acnts.modify( to, 0, [&]( auto& a ) { - a.balance += value; - }); - } -} - -} /// namespace eosio - -EOSIO_ABI( eosio::token, (create)(issue)(transfer) ) diff --git a/contracts/eosio.token/eosio.token.hpp b/contracts/eosio.token/eosio.token.hpp deleted file mode 100644 index 48312c9edb4..00000000000 --- a/contracts/eosio.token/eosio.token.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include - -#include - -namespace eosiosystem { - class system_contract; -} - -namespace eosio { - - using std::string; - - class token : public contract { - public: - token( account_name self ):contract(self){} - - void create( account_name issuer, - asset maximum_supply); - - void issue( account_name to, asset quantity, string memo ); - - void transfer( account_name from, - account_name to, - asset quantity, - string memo ); - - - inline asset get_supply( symbol_name sym )const; - - inline asset get_balance( account_name owner, symbol_name sym )const; - - private: - struct account { - asset balance; - - uint64_t primary_key()const { return balance.symbol.name(); } - }; - - struct currency_stats { - asset supply; - asset max_supply; - account_name issuer; - - uint64_t primary_key()const { return supply.symbol.name(); } - }; - - typedef eosio::multi_index accounts; - typedef eosio::multi_index stats; - - void sub_balance( account_name owner, asset value ); - void add_balance( account_name owner, asset value, account_name ram_payer ); - - public: - struct transfer_args { - account_name from; - account_name to; - asset quantity; - string memo; - }; - }; - - asset token::get_supply( symbol_name sym )const - { - stats statstable( _self, sym ); - const auto& st = statstable.get( sym ); - return st.supply; - } - - asset token::get_balance( account_name owner, symbol_name sym )const - { - accounts accountstable( _self, owner ); - const auto& ac = accountstable.get( sym ); - return ac.balance; - } - -} /// namespace eosio diff --git a/contracts/eosiolib/CMakeLists.txt b/contracts/eosiolib/CMakeLists.txt deleted file mode 100644 index f7dc3b0c5a0..00000000000 --- a/contracts/eosiolib/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/core_symbol.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/core_symbol.hpp) - -add_wast_library(TARGET eosiolib - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" ${CMAKE_SOURCE_DIR}/externals/magic_get/include - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/eosiolib/action.h b/contracts/eosiolib/action.h deleted file mode 100644 index f8deba837b8..00000000000 --- a/contracts/eosiolib/action.h +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include - -extern "C" { - /** - * @defgroup actionapi Action API - * @ingroup contractdev - * @brief Defines API for for querying action and sending action - * - */ - - /** - * @defgroup actioncapi Action C API - * @ingroup actionapi - * @brief Defines API for querying action and sending action - * - * - * A EOS.IO action has the following abstract structure: - * - * ``` - * struct action { - * scope_name scope; // the contract defining the primary code to execute for code/type - * action_name name; // the action to be taken - * permission_level[] authorization; // the accounts and permission levels provided - * bytes data; // opaque data processed by code - * }; - * ``` - * - * This API enables your contract to inspect the fields on the current action and act accordingly. - * - * Example: - * @code - * // Assume this action is used for the following examples: - * // { - * // "code": "eos", - * // "type": "transfer", - * // "authorization": [{ "account": "inita", "permission": "active" }], - * // "data": { - * // "from": "inita", - * // "to": "initb", - * // "amount": 1000 - * // } - * // } - * - * char buffer[128]; - * uint32_t total = read_action(buffer, 5); // buffer contains the content of the action up to 5 bytes - * print(total); // Output: 5 - * - * uint32_t msgsize = action_size(); - * print(msgsize); // Output: size of the above action's data field - * - * require_recipient(N(initc)); // initc account will be notified for this action - * - * require_auth(N(inita)); // Do nothing since inita exists in the auth list - * require_auth(N(initb)); // Throws an exception - * - * print(current_time()); // Output: timestamp (in microseconds since 1970) of current block - * - * @endcode - * - * - * @{ - */ - - /** - * Copy up to @ref len bytes of current action data to the specified location - * - * @brief Copy current action data to the specified location - * @param msg - a pointer where up to @ref len bytes of the current action data will be copied - * @param len - len of the current action data to be copied, 0 to report required size - * @return the number of bytes copied to msg, or number of bytes that can be copied if len==0 passed - * @pre `msg` is a valid pointer to a range of memory at least `len` bytes long - * @post `msg` is filled with packed action data - */ - uint32_t read_action_data( void* msg, uint32_t len ); - - /** - * Get the length of the current action's data field. This method is useful for dynamically sized actions - * - * @brief Get the length of current action's data field - * @return the length of the current action's data field - */ - uint32_t action_data_size(); - - /** - * Add the specified account to set of accounts to be notified - * - * @brief Add the specified account to set of accounts to be notified - * @param name - name of the account to be verified - */ - void require_recipient( account_name name ); - - /** - * Verifies that @ref name exists in the set of provided auths on a action. Throws if not found. - * - * @brief Verify specified account exists in the set of provided auths - * @param name - name of the account to be verified - */ - void require_auth( account_name name ); - - /** - * Verifies that @ref name has auth. - * - * @brief Verifies that @ref name has auth. - * @param name - name of the account to be verified - */ - bool has_auth( account_name name ); - - /** - * Verifies that @ref name exists in the set of provided auths on a action. Throws if not found. - * - * @brief Verify specified account exists in the set of provided auths - * @param name - name of the account to be verified - * @param permission - permission level to be verified - */ - void require_auth2( account_name name, permission_name permission ); - - bool is_account( account_name name ); - - /** - * Send an inline action in the context of this action's parent transaction - * - * @param serialized_action - serialized action - * @param size - size of serialized action in bytes - * @pre `serialized_action` is a valid pointer to an array at least `size` bytes long - */ - void send_inline(char *serialized_action, size_t size); - - /** - * Send an inline context free action in the context of this action's parent transaction - * - * @param serialized_action - serialized action - * @param size - size of serialized action in bytes - * @pre `serialized_action` is a valid pointer to an array at least `size` bytes long - */ - void send_context_free_inline(char *serialized_action, size_t size); - - /** - * Verifies that @ref name exists in the set of write locks held on a action. Throws if not found - * @brief Verifies that @ref name exists in the set of write locks held - * @param name - name of the account to be verified - */ - void require_write_lock( account_name name ); - - /** - * Verifies that @ref name exists in the set of read locks held on a action. Throws if not found - * @brief Verifies that @ref name exists in the set of read locks held - * @param name - name of the account to be verified - */ - void require_read_lock( account_name name ); - - /** - * Returns the time in microseconds from 1970 of the publication_time - * @brief Get the publication time - * @return the time in microseconds from 1970 of the publication_time - */ - uint64_t publication_time(); - - /** - * Get the current receiver of the action - * @brief Get the current receiver of the action - * @return the account which specifies the current receiver of the action - */ - account_name current_receiver(); - ///@ } actioncapi -} diff --git a/contracts/eosiolib/action.hpp b/contracts/eosiolib/action.hpp deleted file mode 100644 index d4538c2972e..00000000000 --- a/contracts/eosiolib/action.hpp +++ /dev/null @@ -1,395 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include -#include -#include - -#include -#include -#include -#include - -namespace eosio { - - /** - * @defgroup actioncppapi Action C++ API - * @ingroup actionapi - * @brief Defines type-safe C++ wrapers for querying action and sending action - * - * @note There are some methods from the @ref actioncapi that can be used directly from C++ - * - * @{ - */ - - /** - * - * This method unpacks the current action at type T. - * - * @brief Interpret the action body as type T. - * @return Unpacked action data casted as T. - * - * Example: - * - * @code - * struct dummy_action { - * char a; //1 - * unsigned long long b; //8 - * int c; //4 - * - * EOSLIB_SERIALIZE( dummy_action, (a)(b)(c) ) - * }; - * dummy_action msg = unpack_action_data(); - * @endcode - */ - template - T unpack_action_data() { - constexpr size_t max_stack_buffer_size = 512; - size_t size = action_data_size(); - const bool heap_allocation = max_stack_buffer_size < size; - char* buffer = (char*)( heap_allocation ? malloc(size) : alloca(size) ); - read_action_data( buffer, size ); - auto res = unpack( buffer, size ); - // Free allocated memory - if ( heap_allocation ) { - free(buffer); - } - return res; - } - - using ::require_auth; - using ::require_recipient; - - /** - * All of the listed accounts will be added to the set of accounts to be notified - * - * This helper method enables you to add multiple accounts to accounts to be notified list with a single - * call rather than having to call the similar C API multiple times. - * - * @note action.code is also considered as part of the set of notified accounts - * - * @brief Notify an account for this action - * @param name account to be notified - * @param remaining_accounts accounts to be notified - * - * Example: - * - * @code - * require_recipient(N(Account1), N(Account2), N(Account3)); // throws exception if any of them not in set. - * @endcode - */ - template - void require_recipient( account_name name, accounts... remaining_accounts ){ - require_recipient( name ); - require_recipient( remaining_accounts... ); - } - - /** - * Packed representation of a permission level (Authorization) - * - * @brief Packed representation of a permission level (Authorization) - */ - struct permission_level { - /** - * Construct a new permission level object with actor name and permission name - * - * @brief Construct a new permission level object - * @param a - Name of the account who owns this authorization - * @param p - Name of the permission - */ - permission_level( account_name a, permission_name p ):actor(a),permission(p){} - - /** - * Default Constructor - * - * @brief Construct a new permission level object - */ - permission_level(){} - - /** - * Name of the account who owns this permission - * - * @brief Name of the account who owns this permission - */ - account_name actor; - /** - * Name of the permission - * - * @brief Name of the permission - */ - permission_name permission; - - /** - * Check equality of two permissions - * - * @brief Check equality of two permissions - * @param a - first permission to compare - * @param b - second permission to compare - * @return true if equal - * @return false if unequal - */ - friend bool operator == ( const permission_level& a, const permission_level& b ) { - return std::tie( a.actor, a.permission ) == std::tie( b.actor, b.permission ); - } - - EOSLIB_SERIALIZE( permission_level, (actor)(permission) ) - }; - - /** - * Require the specified authorization for this action. If this action doesn't contain the specified auth, it will fail. - * - * @brief Require the specified authorization for this action - * - * @param level - Authorization to be required - */ - void require_auth(const permission_level& level) { - require_auth2( level.actor, level.permission ); - } - - /** - * This is the packed representation of an action along with - * meta-data about the authorization levels. - * - * @brief Packed representation of an action - */ - struct action { - /** - * Name of the account the action is intended for - * - * @brief Name of the account the action is intended for - */ - account_name account; - - /** - * Name of the action - * - * @brief Name of the action - */ - action_name name; - - /** - * List of permissions that authorize this action - * - * @brief List of permissions that authorize this action - */ - vector authorization; - - /** - * Payload data - * - * @brief Payload data - */ - bytes data; - - /** - * Default Constructor - * - * @brief Construct a new action object - */ - action() = default; - - /** - * Construct a new action object with the given permission and action struct - * - * @brief Construct a new action object with the given permission and action struct - * @tparam Action - Type of action struct - * @param auth - The permission that authorizes this action - * @param value - The action struct that will be serialized via pack into data - */ - template - action( vector&& auth, const Action& value ) { - account = Action::get_account(); - name = Action::get_name(); - authorization = move(auth); - data = pack(value); - } - - /** - * Construct a new action object with the given list of permissions and action struct - * - * @brief Construct a new action object with the given list of permissions and action struct - * @tparam Action - Type of action struct - * @param auth - The list of permissions that authorizes this action - * @param value - The action struct that will be serialized via pack into data - */ - template - action( const permission_level& auth, const Action& value ) - :authorization(1,auth) { - account = Action::get_account(); - name = Action::get_name(); - data = pack(value); - } - - - /** - * Construct a new action object with the given action struct - * - * @brief Construct a new action object with the given action struct - * @tparam Action - Type of action struct - * @param value - The action struct that will be serialized via pack into data - */ - template - action( const Action& value ) { - account = Action::get_account(); - name = Action::get_name(); - data = pack(value); - } - - /** - * Construct a new action object with the given action struct - * - * @brief Construct a new action object with the given permission, action receiver, action name, action struct - * @tparam T - Type of action struct, must be serializable by `pack(...)` - * @param auth - The permissions that authorizes this action - * @param a - The name of the account this action is intended for (action receiver) - * @param n - The name of the action - * @param value - The action struct that will be serialized via pack into data - */ - template - action( const permission_level& auth, account_name a, action_name n, T&& value ) - :account(a), name(n), authorization(1,auth), data(pack(std::forward(value))) {} - - /** - * Construct a new action object with the given action struct - * - * @brief Construct a new action object with the given list of permissions, action receiver, action name, action struct - * @tparam T - Type of action struct, must be serializable by `pack(...)` - * @param auths - The list of permissions that authorize this action - * @param a - The name of the account this action is intended for (action receiver) - * @param n - The name of the action - * @param value - The action struct that will be serialized via pack into data - */ - template - action( vector auths, account_name a, action_name n, T&& value ) - :account(a), name(n), authorization(std::move(auths)), data(pack(std::forward(value))) {} - - EOSLIB_SERIALIZE( action, (account)(name)(authorization)(data) ) - - /** - * Send the action as inline action - * - * @brief Send the action as inline action - */ - void send() const { - auto serialize = pack(*this); - ::send_inline(serialize.data(), serialize.size()); - } - - /** - * Send the action as inline context free action - * - * @brief Send the action as inline context free action - * @pre This action should not contain any authorizations - */ - void send_context_free() const { - eosio_assert( authorization.size() == 0, "context free actions cannot have authorizations"); - auto serialize = pack(*this); - ::send_context_free_inline(serialize.data(), serialize.size()); - } - - /** - * Retrieve the unpacked data as T - * - * @brief Retrieve the unpacked data as T - * @tparam T expected type of data - * @return the action data - */ - template - T data_as() { - eosio_assert( name == T::get_name(), "Invalid name" ); - eosio_assert( account == T::get_account(), "Invalid account" ); - return unpack( &data[0], data.size() ); - } - - }; - - /** - * Base class to derive a new defined action from so it can take advantage of the dispatcher - * - * @brief Base class to derive a new defined action from - * @tparam Account - The account this action is intended for - * @tparam Name - The name of the action - */ - template - struct action_meta { - /** - * Get the account this action is intended for - * - * @brief Get the account this action is intended for - * @return uint64_t The account this action is intended for - */ - static uint64_t get_account() { return Account; } - /** - * Get the name of this action - * - * @brief Get the name of this action - * @return uint64_t Name of the action - */ - static uint64_t get_name() { return Name; } - }; - - ///@} actioncpp api - - template - void dispatch_inline( account_name code, action_name act, - vector perms, - std::tuple args ) { - action( perms, code, act, std::move(args) ).send(); - } - - - template - struct inline_dispatcher; - - - template - struct inline_dispatcher { - static void call(account_name code, const permission_level& perm, std::tuple args) { - dispatch_inline(code, Name, vector(1, perm), std::move(args)); - } - static void call(account_name code, vector perms, std::tuple args) { - dispatch_inline(code, Name, std::move(perms), std::move(args)); - } - }; - - -} // namespace eosio - -#define INLINE_ACTION_SENDER3( CONTRACT_CLASS, FUNCTION_NAME, ACTION_NAME )\ -::eosio::inline_dispatcher::call - -#define INLINE_ACTION_SENDER2( CONTRACT_CLASS, NAME )\ -INLINE_ACTION_SENDER3( CONTRACT_CLASS, NAME, ::eosio::string_to_name(#NAME) ) - -#define INLINE_ACTION_SENDER(...) BOOST_PP_OVERLOAD(INLINE_ACTION_SENDER,__VA_ARGS__)(__VA_ARGS__) - -/** - * @addtogroup actioncppapi - * Additional documentation for group - * @{ - */ - -/** - * Send inline action - * - * @brief Send inline action - * @param CONTRACT - The account this action is intended for - * @param NAME - The name of the action - * @param ... - The member of the action specified as ("action_member1_name", action_member1_value)("action_member2_name", action_member2_value) - */ -#define SEND_INLINE_ACTION( CONTRACT, NAME, ... )\ -INLINE_ACTION_SENDER(std::decay_t, NAME)( (CONTRACT).get_self(),\ -BOOST_PP_TUPLE_ENUM(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__)) ); - -/** - * Extend a new defined action with theaction meta, so it can work with the dispatcher - * - * @brief Extend a new defined action with the action meta - * @param CODE - The account this action is intended for - * @param NAME - The name of the action - */ -#define ACTION( CODE, NAME ) struct NAME : ::eosio::action_meta - - /// @} diff --git a/contracts/eosiolib/asset.hpp b/contracts/eosiolib/asset.hpp deleted file mode 100644 index c3e454384ff..00000000000 --- a/contracts/eosiolib/asset.hpp +++ /dev/null @@ -1,472 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace eosio { - - /** - * @defgroup assetapi Asset API - * @brief Defines API for managing assets - * @ingroup contractdev - */ - - /** - * @defgroup assetcppapi Asset CPP API - * @brief Defines %CPP API for managing assets - * @ingroup assetapi - * @{ - */ - - /** - * \struct Stores information for owner of asset - * - * @brief Stores information for owner of asset - */ - - struct asset { - /** - * The amount of the asset - * - * @brief The amount of the asset - */ - int64_t amount; - - /** - * The symbol name of the asset - * - * @brief The symbol name of the asset - */ - symbol_type symbol; - - /** - * Maximum amount possible for this asset. It's capped to 2^62 - 1 - * - * @brief Maximum amount possible for this asset - */ - static constexpr int64_t max_amount = (1LL << 62) - 1; - - /** - * Construct a new asset given the symbol name and the amount - * - * @brief Construct a new asset object - * @param a - The amount of the asset - * @param s - THe name of the symbol, default to CORE_SYMBOL - */ - explicit asset( int64_t a = 0, symbol_type s = CORE_SYMBOL ) - :amount(a),symbol{s} - { - eosio_assert( is_amount_within_range(), "magnitude of asset amount must be less than 2^62" ); - eosio_assert( symbol.is_valid(), "invalid symbol name" ); - } - - /** - * Check if the amount doesn't exceed the max amount - * - * @brief Check if the amount doesn't exceed the max amount - * @return true - if the amount doesn't exceed the max amount - * @return false - otherwise - */ - bool is_amount_within_range()const { return -max_amount <= amount && amount <= max_amount; } - - /** - * Check if the asset is valid. %A valid asset has its amount <= max_amount and its symbol name valid - * - * @brief Check if the asset is valid - * @return true - if the asset is valid - * @return false - otherwise - */ - bool is_valid()const { return is_amount_within_range() && symbol.is_valid(); } - - /** - * Set the amount of the asset - * - * @brief Set the amount of the asset - * @param a - New amount for the asset - */ - void set_amount( int64_t a ) { - amount = a; - eosio_assert( is_amount_within_range(), "magnitude of asset amount must be less than 2^62" ); - } - - /** - * Unary minus operator - * - * @brief Unary minus operator - * @return asset - New asset with its amount is the negative amount of this asset - */ - asset operator-()const { - asset r = *this; - r.amount = -r.amount; - return r; - } - - /** - * Subtraction assignment operator - * - * @brief Subtraction assignment operator - * @param a - Another asset to subtract this asset with - * @return asset& - Reference to this asset - * @post The amount of this asset is subtracted by the amount of asset a - */ - asset& operator-=( const asset& a ) { - eosio_assert( a.symbol == symbol, "attempt to subtract asset with different symbol" ); - amount -= a.amount; - eosio_assert( -max_amount <= amount, "subtraction underflow" ); - eosio_assert( amount <= max_amount, "subtraction overflow" ); - return *this; - } - - /** - * Addition Assignment operator - * - * @brief Addition Assignment operator - * @param a - Another asset to subtract this asset with - * @return asset& - Reference to this asset - * @post The amount of this asset is added with the amount of asset a - */ - asset& operator+=( const asset& a ) { - eosio_assert( a.symbol == symbol, "attempt to add asset with different symbol" ); - amount += a.amount; - eosio_assert( -max_amount <= amount, "addition underflow" ); - eosio_assert( amount <= max_amount, "addition overflow" ); - return *this; - } - - /** - * Addition operator - * - * @brief Addition operator - * @param a - The first asset to be added - * @param b - The second asset to be added - * @return asset - New asset as the result of addition - */ - inline friend asset operator+( const asset& a, const asset& b ) { - asset result = a; - result += b; - return result; - } - - /** - * Subtraction operator - * - * @brief Subtraction operator - * @param a - The asset to be subtracted - * @param b - The asset used to subtract - * @return asset - New asset as the result of subtraction of a with b - */ - inline friend asset operator-( const asset& a, const asset& b ) { - asset result = a; - result -= b; - return result; - } - - /** - * Multiplication assignment operator. Multiply the amount of this asset with a number and then assign the value to itself. - * - * @brief Multiplication assignment operator, with a number - * @param a - The multiplier for the asset's amount - * @return asset - Reference to this asset - * @post The amount of this asset is multiplied by a - */ - asset& operator*=( int64_t a ) { - int128_t tmp = (int128_t)amount * (int128_t)a; - eosio_assert( tmp <= max_amount, "multiplication overflow" ); - eosio_assert( tmp >= -max_amount, "multiplication underflow" ); - amount = (int64_t)tmp; - return *this; - } - - /** - * Multiplication operator, with a number proceeding - * - * @brief Multiplication operator, with a number proceeding - * @param a - The asset to be multiplied - * @param b - The multiplier for the asset's amount - * @return asset - New asset as the result of multiplication - */ - friend asset operator*( const asset& a, int64_t b ) { - asset result = a; - result *= b; - return result; - } - - - /** - * Multiplication operator, with a number preceeding - * - * @brief Multiplication operator, with a number preceeding - * @param a - The multiplier for the asset's amount - * @param b - The asset to be multiplied - * @return asset - New asset as the result of multiplication - */ - friend asset operator*( int64_t b, const asset& a ) { - asset result = a; - result *= b; - return result; - } - - /** - * Division assignment operator. Divide the amount of this asset with a number and then assign the value to itself. - * - * @brief Division assignment operator, with a number - * @param a - The divisor for the asset's amount - * @return asset - Reference to this asset - * @post The amount of this asset is divided by a - */ - asset& operator/=( int64_t a ) { - eosio_assert( a != 0, "divide by zero" ); - eosio_assert( !(amount == std::numeric_limits::min() && a == -1), "signed division overflow" ); - amount /= a; - return *this; - } - - /** - * Division operator, with a number proceeding - * - * @brief Division operator, with a number proceeding - * @param a - The asset to be divided - * @param b - The divisor for the asset's amount - * @return asset - New asset as the result of division - */ - friend asset operator/( const asset& a, int64_t b ) { - asset result = a; - result /= b; - return result; - } - - /** - * Division operator, with another asset - * - * @brief Division operator, with another asset - * @param a - The asset which amount acts as the dividend - * @param b - The asset which amount acts as the divisor - * @return int64_t - the resulted amount after the division - * @pre Both asset must have the same symbol - */ - friend int64_t operator/( const asset& a, const asset& b ) { - eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount / b.amount; - } - - /** - * Equality operator - * - * @brief Equality operator - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if both asset has the same amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator==( const asset& a, const asset& b ) { - eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount == b.amount; - } - - /** - * Inequality operator - * - * @brief Inequality operator - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if both asset doesn't have the same amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator!=( const asset& a, const asset& b ) { - return !( a == b); - } - - /** - * Less than operator - * - * @brief Less than operator - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if the first asset's amount is less than the second asset amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator<( const asset& a, const asset& b ) { - eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount < b.amount; - } - - /** - * Less or equal to operator - * - * @brief Less or equal to operator - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if the first asset's amount is less or equal to the second asset amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator<=( const asset& a, const asset& b ) { - eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount <= b.amount; - } - - /** - * Greater than operator - * - * @brief Greater than operator - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if the first asset's amount is greater than the second asset amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator>( const asset& a, const asset& b ) { - eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount > b.amount; - } - - /** - * Greater or equal to operator - * - * @brief Greater or equal to operator - * @param a - The first asset to be compared - * @param b - The second asset to be compared - * @return true - if the first asset's amount is greater or equal to the second asset amount - * @return false - otherwise - * @pre Both asset must have the same symbol - */ - friend bool operator>=( const asset& a, const asset& b ) { - eosio_assert( a.symbol == b.symbol, "comparison of assets with different symbols is not allowed" ); - return a.amount >= b.amount; - } - - /** - * %Print the asset - * - * @brief %Print the asset - */ - void print()const { - int64_t p = (int64_t)symbol.precision(); - int64_t p10 = 1; - while( p > 0 ) { - p10 *= 10; --p; - } - p = (int64_t)symbol.precision(); - - char fraction[p+1]; - fraction[p] = '\0'; - auto change = amount % p10; - - for( int64_t i = p -1; i >= 0; --i ) { - fraction[i] = (change % 10) + '0'; - change /= 10; - } - printi( amount / p10 ); - prints("."); - prints_l( fraction, uint32_t(p) ); - prints(" "); - symbol.print(false); - } - - EOSLIB_SERIALIZE( asset, (amount)(symbol) ) - }; - - /** - * \struct Extended asset which stores the information of the owner of the asset - * - * @brief Extended asset which stores the information of the owner of the asset - */ - struct extended_asset : public asset { - /** - * The owner of the asset - * - * @brief The owner of the asset - */ - account_name contract; - - /** - * Get the extended symbol of the asset - * - * @brief Get the extended symbol of the asset - * @return extended_symbol - The extended symbol of the asset - */ - extended_symbol get_extended_symbol()const { return extended_symbol( symbol, contract ); } - - /** - * Default constructor - * - * @brief Construct a new extended asset object - */ - extended_asset() = default; - - /** - * Construct a new extended asset given the amount and extended symbol - * - * @brief Construct a new extended asset object - */ - extended_asset( int64_t v, extended_symbol s ):asset(v,s),contract(s.contract){} - /** - * Construct a new extended asset given the asset and owner name - * - * @brief Construct a new extended asset object - */ - extended_asset( asset a, account_name c ):asset(a),contract(c){} - - /** - * %Print the extended asset - * - * @brief %Print the extended asset - */ - void print()const { - asset::print(); - prints("@"); - printn(contract); - } - - /** - * Unary minus operator - * - * @brief Unary minus operator - * @return extended_asset - New extended asset with its amount is the negative amount of this extended asset - */ - extended_asset operator-()const { - asset r = this->asset::operator-(); - return {r, contract}; - } - - /** - * Subtraction operator. This subtracts the amount of the extended asset. - * - * @brief Subtraction operator - * @param a - The extended asset to be subtracted - * @param b - The extended asset used to subtract - * @return extended_asset - New extended asset as the result of subtraction - * @pre The owner of both extended asset need to be the same - */ - friend extended_asset operator - ( const extended_asset& a, const extended_asset& b ) { - eosio_assert( a.contract == b.contract, "type mismatch" ); - asset r = static_cast(a) - static_cast(b); - return {r, a.contract}; - } - - /** - * Addition operator. This adds the amount of the extended asset. - * - * @brief Addition operator - * @param a - The extended asset to be added - * @param b - The extended asset to be added - * @return extended_asset - New extended asset as the result of addition - * @pre The owner of both extended asset need to be the same - */ - friend extended_asset operator + ( const extended_asset& a, const extended_asset& b ) { - eosio_assert( a.contract == b.contract, "type mismatch" ); - asset r = static_cast(a) + static_cast(b); - return {r, a.contract}; - } - - EOSLIB_SERIALIZE( extended_asset, (amount)(symbol)(contract) ) - }; - -/// @} asset type -} /// namespace eosio diff --git a/contracts/eosiolib/chain.h b/contracts/eosiolib/chain.h deleted file mode 100644 index ec4f219b4b9..00000000000 --- a/contracts/eosiolib/chain.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include - -/** - * @defgroup chainapi Chain API - * @brief Defines API for querying internal chain state - * @ingroup contractdev - */ - -/** - * @defgroup chaincapi Chain C API - * @brief Defines %C API for querying internal chain state - * @ingroup chainapi - * @{ - */ - -extern "C" { - /** - * Gets the set of active producers. - * @brief Gets the set of active producers. - * - * @param producers - Pointer to a buffer of account names - * @param datalen - Byte length of buffer, when passed 0 will return the size required to store full output. - * - * @return uint32_t - Number of bytes actually populated - * @pre `producers` is a pointer to a range of memory at least `datalen` bytes long - * @post the passed in `producers` pointer gets the array of active producers. - * - * Example: - * - * @code - * account_name producers[21]; - * uint32_t bytes_populated = get_active_producers(producers, sizeof(account_name)*21); - * @endcode - */ - - uint32_t get_active_producers( account_name* producers, uint32_t datalen ); - - ///@ } chaincapi -} diff --git a/contracts/eosiolib/compiler_builtins.h b/contracts/eosiolib/compiler_builtins.h deleted file mode 100644 index c2dc09bb356..00000000000 --- a/contracts/eosiolib/compiler_builtins.h +++ /dev/null @@ -1,423 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include - -extern "C" { - /** - * @defgroup compilerbuiltinsapi Compiler Builtins API - * @ingroup mathapi - * @brief Declares int128 helper builtins generated by the toolchain. - * - * @{ - */ - - /** - * Multiply two 128 bit integers split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Multiply two 128 unsigned bit integers (which are represented as two 64 bit unsigned integers. - * @param res It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @post `res` is replaced with the result of multiplication - * Example: - * @code - * __int128 res = 0; - * __int128 a = 100; - * __int128 b = 100; - * __multi3(res, a, (a >> 64), b, (b >> 64)); - * printi128(&res); // Output: 10000 - * @endcode - */ - void __multi3(__int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); - - /** - * Divide two 128 bit integers split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Divide two 128 bit integers (which are represented as two 64 bit unsigned integers) - * @param res It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @post `res` is replaced with the result of division - * Example: - * @code - * __int128 res = 0; - * __int128 a = 100; - * __int128 b = 100; - * __divti3(res, a, (a >> 64), b, (b >> 64)); - * printi128(&res); // Output: 1 - * @endcode - */ - void __divti3(__int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); - - /** - * Divide two 128 bit unsigned integers split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Divide two 128 unsigned bit integers (which are represented as two 64 bit unsigned integers) - * @param res It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * Example: - * @code - * unsigned __int128 res = 0; - * unsigned __int128 a = 100; - * unsigned __int128 b = 100; - * __udivti3(res, a, (a >> 64), b, (b >> 64)); - * printi128(&res); // Output: 1 - * @endcode - */ - void __udivti3(unsigned __int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); - - /** - * Perform modular arithmetic on two 128 bit integers split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Perform modular arithmetic on two 128 bit integers (which are represented as two 64 bit unsigned integers) - * @param res It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @post `res` is replaced with the result of modulus - * Example: - * @code - * __int128 res = 0; - * __int128 a = 100; - * __int128 b = 3; - * __modti3(res, a, (a >> 64), b, (b >> 64)); - * printi128(&res); // Output: 1 - * @endcode - */ - void __modti3(__int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); - - /** - * Perform modular arithmetic on two 128 unsigned bit integers split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Perform modular arithmetic on two 128 unsigned bit integers (which are represented as two 64 bit unsigned integers) - * @param res It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @post `res` is replaced with the result of modulus - * Example: - * @code - * unsigned __int128 res = 0; - * unsigned __int128 a = 100; - * unsigned __int128 b = 3; - * __umodti3(res, a, (a >> 64), b, (b >> 64)); - * printi128(&res); // Output: 1 - * @endcode - */ - void __umodti3(unsigned __int128& res, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb); - -/** - * Perform logical shift left on a 128 bit integer split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Perform logical shift left on a 128 bit integer (which is represented as two 64 bit unsigned integers) - * @param res It will be replaced with the result product. - * @param lo Low 64 bits of the 128 bit factor. - * @param hi High 64 bits of the 128 bit factor. - * @param shift Number of bits to shift. - * @post `res` is replaced with the result of the operation - * Example: - * @code - * __int128 res = 0; - * __int128 a = 8; - * __lshlti3(res, a, (a >> 64), 1); - * printi128(&res); // Output: 16 - * @endcode - */ - void __lshlti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift); - - /** - * Perform logical shift right on a 128 bit integer split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Perform logical shift right on a 128 bit integer (which is represented as two 64 bit unsigned integers) - * @param res It will be replaced with the result product. - * @param lo Low 64 bits of the 128 bit factor. - * @param hi High 64 bits of the 128 bit factor. - * @param shift Number of bits to shift. - * @post `res` is replaced with the result of the operation - * Example: - * @code - * __int128 res = 0; - * __int128 a = 8; - * __lshrti3(res, a, (a >> 64), 1); - * printi128(&res); // Output: 4 - * @endcode - */ - void __lshrti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift); - -/** - * Perform arithmetic shift left on a 128 bit integer split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Perform arithmetic shift left on a 128 bit integer (which is represented as two 64 bit unsigned integers) - * @param res It will be replaced with the result product. - * @param lo Low 64 bits of the 128 bit factor. - * @param hi High 64 bits of the 128 bit factor. - * @param shift Number of bits to shift. - * @post `res` is replaced with the result of the operation - * Example: - * @code - * __int128 res = 0; - * __int128 a = 8; - * __ashlti3(res, a, (a >> 64), 1); - * printi128(&res); // Output: 16 - * @endcode - */ - void __ashlti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift); - - /** - * Perform arithmetic shift right on a 128 bit integer split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Perform arithmetic shift right on a 128 bit integer (which is represented as two 64 bit unsigned integers) - * @param res It will be replaced with the result product. - * @param lo Low 64 bits of the 128 bit factor. - * @param hi High 64 bits of the 128 bit factor. - * @param shift Number of bits to shift. - * @post `res` is replaced with the result of the operation - * Example: - * @code - * __int128 res = 0; - * __int128 a = -8; - * __ashrti3(res, a, (a >> 64), 1); - * printi128(&res); // Output: -4 - * @endcode - */ - void __ashrti3(__int128& res, uint64_t lo, uint64_t hi, uint32_t shift); - - /** - * Add two long doubles split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Add two long doubles (which are represented as two 64 bit unsigned integers) - * @param ret It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @post `ret` is replaced with the result of the operation - */ - void __addtf3( long double& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Subtract two long doubles split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Subtract two long doubles (which are represented as two 64 bit unsigned integers) - * @param ret It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @post `ret` is replaced with the result of the operation - */ - void __subtf3( long double& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Multiply two long doubles split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Multiply two long doubles (which are represented as two 64 bit unsigned integers) - * @param ret It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @post `ret` is replaced with the result of the operation - */ - void __multf3( long double& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Divide two long doubles split as two 64 bit unsigned integers and assign the value to the first parameter. - * @brief Divide two long doubles (which are represented as two 64 bit unsigned integers) - * @param ret It will be replaced with the result product. - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @post `ret` is replaced with the result of the operation - */ - void __divtf3( long double& ret, uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Check equality between two doubles split as two 64 bit unsigned integers - * @brief Check equality between two doubles (which are represented as two 64 bit unsigned integers) - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @return 1 if a greater than b - * @return 0 if a equal to b - * @return -1 if a less than b - * @return 1 if either a or b is NaN - */ - int __eqtf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Check inequality between two doubles split as two 64 bit unsigned integers - * @brief Check inequality between two doubles (which are represented as two 64 bit unsigned integers) - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @return 1 if a greater than b - * @return 0 if a equal to b - * @return -1 if a less than b - * @return1 if either a or b is NaN - */ - int __netf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - - /** - * Check if the first double is greater or equal to the second double, the doubles are split as two 64 bit unsigned integers - * @brief Check if the first double is greater or equal to the second double, (the doubles are represented as two 64 bit unsigned integers) - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @return 1 if a greater than b - * @return 0 if a equal to b - * @return -1 if a less than b - * @return -1 if either a or b is NaN - */ - int __getf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Check if the first double is greater than the second double, the doubles are split as two 64 bit unsigned integers - * @brief Check if the first double is greater than the second double, (the doubles are represented as two 64 bit unsigned integers) - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @return 1 if a greater than b - * @return 0 if a equal to b - * @return -1 if a less than b - * @return 0 if either a or b is NaN - */ - int __gttf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Check if the first double is less or equal to the second double, the doubles are split as two 64 bit unsigned integers - * @brief Check if the first double is less or equal to the second double, (the doubles are represented as two 64 bit unsigned integers) - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @return 1 if a greater than b - * @return 0 if a equal to b - * @return -1 if a less than b - * @return 1 if either a or b is NaN - */ - int __letf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Check if the first double is less than the second double, the doubles are split as two 64 bit unsigned integers - * @brief Check if the first double is less than the second double, (the doubles are represented as two 64 bit unsigned integers) - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @return 1 if a greater than b - * @return 0 if a equal to b - * @return -1 if a less than b - * @return 0 if either a or b is NaN - */ - int __lttf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Compare two doubles which are split as two 64 bit unsigned integers - * @brief Compare two doubles (the doubles are represented as two 64 bit unsigned integers) - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @return 1 if a greater than b - * @return 0 if a equal to b - * @return -1 if a less than b - * @return 1 if either a or b is NaN - */ - int __cmptf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Check if either of the doubles is NaN, the doubles are split as two 64 bit unsigned integers - * @brief Check if either of the doubles is NaN, (the doubles are represented as two 64 bit unsigned integers) - * @param la Low 64 bits of the first 128 bit factor. - * @param ha High 64 bits of the first 128 bit factor. - * @param lb Low 64 bits of the second 128 bit factor. - * @param hb High 64 bits of the second 128 bit factor. - * @return 1 if either a or b is NaN - * @return 0 if either a or b is not NaN - */ - int __unordtf2( uint64_t la, uint64_t ha, uint64_t lb, uint64_t hb ); - - /** - * Extend float to long double - * @brief Extend float to long double - * @param ret It will be replaced with the result product. - * @param f Input float to be extended - * @post `ret` is replaced with the extended float - */ - void __extendsftf2( long double& ret, float f ); - - /** - * Extend double to long double - * @brief Extend float to long double - * @param ret It will be replaced with the result product. - * @param f Input float to be extended - * @post `ret` is replaced with the extended float - */ - void __extenddftf2( long double& ret, double f ); - - /** - * Convert long double (which are split as two 64 bit unsigned integers) into 64 bit integer - * @brief Convert long double (which are split as two 64 bit unsigned integers) into 64 bit integer - * @param l Low 64 bits of the first 128 bit factor. - * @param h High 64 bits of the first 128 bit factor. - * @return the converted 64 bit integer. - */ - int64_t __fixtfdi( uint64_t l, uint64_t h ); - - /** - * Convert long double (which are split as two 64 bit unsigned integers) into 32 bit integer - * @brief Convert long double (which are split as two 64 bit unsigned integers) into 32 bit integer - * @param l Low 64 bits of the first 128 bit factor. - * @param h High 64 bits of the first 128 bit factor. - * @return the converted 32 bit integer. - */ - int32_t __fixtfsi( uint64_t l, uint64_t h ); - - /** - * Convert long double (which are split as two 64 bit unsigned integers) into 64 bit unsigned integer - * @brief Convert long double (which are split as two 64 bit unsigned integers) into 64 bit unsigned integer - * @param l Low 64 bits of the first 128 bit factor. - * @param h High 64 bits of the first 128 bit factor. - * @return the converted 64 bit unsigned integer. - */ - uint64_t __fixunstfdi( uint64_t l, uint64_t h ); - - /** - * Convert long double (which are split as two 64 bit unsigned integers) into 32 bit unsigned integer - * @brief Convert long double (which are split as two 64 bit unsigned integers) into 32 bit unsigned integer - * @param l Low 64 bits of the first 128 bit factor. - * @param h High 64 bits of the first 128 bit factor. - * @return the converted 32 bit unsigned integer. - */ - uint32_t __fixunstfsi( uint64_t l, uint64_t h ); - - /** - * Truncate long double (which are split as two 64 bit unsigned integers) into double - * @brief Convert long double (which are split as two 64 bit unsigned integers) into double - * @param l Low 64 bits of the first 128 bit factor. - * @param h High 64 bits of the first 128 bit factor. - * @return the converted double - */ - double __trunctfdf2( uint64_t l, uint64_t h ); - - /** - * Truncate long double (which are split as two 64 bit unsigned integers) into float - * @brief Convert long double (which are split as two 64 bit unsigned integers) into float - * @param l Low 64 bits of the first 128 bit factor. - * @param h High 64 bits of the first 128 bit factor. - * @return the converted float - */ - float __trunctfsf2( uint64_t l, uint64_t h ); - - void __break_point(); - -/// @} -} // extern "C" diff --git a/contracts/eosiolib/contract.hpp b/contracts/eosiolib/contract.hpp deleted file mode 100644 index 307731bd726..00000000000 --- a/contracts/eosiolib/contract.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -namespace eosio { - -/** - * @defgroup contracttype Contract Type - * @ingroup types - * @brief Defines contract type which is %base class for every EOSIO contract - * - * @{ - * - */ - -/** - * @brief %Base class for EOSIO contract. - * @details %Base class for EOSIO contract. %A new contract should derive from this class, so it can make use of EOSIO_ABI macro. - */ -class contract { - public: - /** - * Construct a new contract given the contract name - * - * @brief Construct a new contract object. - * @param n - The name of this contract - */ - contract( account_name n ):_self(n){} - - /** - * - * Get this contract name - * - * @brief Get this contract name. - * @return account_name - The name of this contract - */ - inline account_name get_self()const { return _self; } - - protected: - /** - * The name of this contract - * - * @brief The name of this contract. - */ - account_name _self; -}; - -/// @} contracttype -} /// namespace eosio diff --git a/contracts/eosiolib/contracts.dox b/contracts/eosiolib/contracts.dox deleted file mode 100644 index 3bc851b6c56..00000000000 --- a/contracts/eosiolib/contracts.dox +++ /dev/null @@ -1,65 +0,0 @@ -/** - @defgroup contractdev Smart Contract API Reference - @brief Introduction to writing contracts for EOS.IO - - @section background Background - - EOS.IO contracts (aka applications) are deployed to a blockchain as pre-compiled Web Assembly (aka WASM). WASM is compiled - from C/C++ using LLVM and clang, which means that you will require knowledge of C/C++ in order to develop your blockchain - applications. While it is possible to develop in C, we strongly recommend that all developers use the EOS.IO C++ API which - provides much stronger type safety and is generally easier to read. - - @section programstructure Application Structure - - EOS.IO applications are designed around event (aka action) handlers that respond to user actions. For example, - a user might transfer tokens to another user. This event can be processed and potentially rejected by the sender, - the receiver, and the currency application itself. - - As an application developer you get to decide what actions users can take and which handlers may or must be called - in response to those events. - - - @subsection programentry Entry Points - - EOS.IO applications have a `apply` which is like `main` in traditional applications: - - ``` - extern "C" { - void init(); - void apply( uint64_t code, uint64_t action ); - } - ``` - - `apply` is given the arguments `code` and `action` which uniquely identify every event in - the system. For example, `code` could be a *currency* contract and `action` could be *transfer*. This event (code,action) - may be passed to several contracts including the `sender` and `receiver`. It is up to your application to figure - out what to do in response to such an event. - - `init` is another entry point that is called once immediately after loading the code. It is where you should perform - one-time initialization of state. - - -### Example Apply Entry Handler - - Generally speaking, you should use your entry handler to dispatch events to functions that implement the majority - of your logic and optionally reject events that your contract is unable or unwilling to accept. - - ``` - extern "C" { - void apply( uint64_t code, uint64_t action ) { - if( code == N(currency) ) { - if( action == N(transfer) ) - currency::apply_currency_transfer( current_action< currency::transfer >() ); - } else { - eosio_assert( false, "rejecting unexpected event" ); - } - } - } - ``` - - @note When defining your entry points it is required that they are placed in an `extern "C"` code block so that - c++ name mangling does not get applied to the function. - - - -*/ diff --git a/contracts/eosiolib/core_symbol.hpp.in b/contracts/eosiolib/core_symbol.hpp.in deleted file mode 100644 index 3262d2aad10..00000000000 --- a/contracts/eosiolib/core_symbol.hpp.in +++ /dev/null @@ -1,7 +0,0 @@ -/** @file - * @copyright defined in eos/LICENSE - * - * \warning This file is machine generated. DO NOT EDIT. See core_symbol.hpp.in for changes. - */ - -#define CORE_SYMBOL S(4,${CORE_SYMBOL_NAME}) \ No newline at end of file diff --git a/contracts/eosiolib/crypto.h b/contracts/eosiolib/crypto.h deleted file mode 100644 index 0133762c43b..00000000000 --- a/contracts/eosiolib/crypto.h +++ /dev/null @@ -1,240 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include -extern "C" { - -/** - * @defgroup cryptoapi Chain API - * @brief Defines API for calculating and checking hash - * @ingroup contractdev - */ - -/** - * @defgroup cryptocapi Chain C API - * @brief Defines %C API for calculating and checking hash - * @ingroup chainapi - * @{ - */ - -/** - * Tests if the sha256 hash generated from data matches the provided checksum. - * This method is optimized to a NO-OP when in fast evaluation mode. - * @brief Tests if the sha256 hash generated from data matches the provided checksum. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - `checksum256*` hash to compare to - * - * @pre **assert256 hash** of `data` equals provided `hash` parameter. - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum hash; - * char data; - * uint32_t length; - * assert_sha256( data, length, hash ) - * //If the sha256 hash generated from data does not equal provided hash, anything below will never fire. - * eosio::print("sha256 hash generated from data equals provided hash"); - * @endcode - */ -void assert_sha256( const char* data, uint32_t length, const checksum256* hash ); - -/** - * Tests if the sha1 hash generated from data matches the provided checksum. - * This method is optimized to a NO-OP when in fast evaluation mode. - * @brief Tests if the sha1 hash generated from data matches the provided checksum. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - `checksum160*` hash to compare to - * - * @pre **sha1 hash** of `data` equals provided `hash` parameter. - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum hash; - * char data; - * uint32_t length; - * assert_sha1( data, length, hash ) - * //If the sha1 hash generated from data does not equal provided hash, anything below will never fire. - * eosio::print("sha1 hash generated from data equals provided hash"); - * @endcode - */ -void assert_sha1( const char* data, uint32_t length, const checksum160* hash ); - -/** - * Tests if the sha512 hash generated from data matches the provided checksum. - * This method is optimized to a NO-OP when in fast evaluation mode. - * @brief Tests if the sha512 hash generated from data matches the provided checksum. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - `checksum512*` hash to compare to - * - * @pre **assert512 hash** of `data` equals provided `hash` parameter. - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum hash; - * char data; - * uint32_t length; - * assert_sha512( data, length, hash ) - * //If the sha512 hash generated from data does not equal provided hash, anything below will never fire. - * eosio::print("sha512 hash generated from data equals provided hash"); - * @endcode - */ -void assert_sha512( const char* data, uint32_t length, const checksum512* hash ); - -/** - * Tests if the ripemod160 hash generated from data matches the provided checksum. - * @brief Tests if the ripemod160 hash generated from data matches the provided checksum. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - `checksum160*` hash to compare to - * - * @pre **assert160 hash** of `data` equals provided `hash` parameter. - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum hash; - * char data; - * uint32_t length; - * assert_ripemod160( data, length, hash ) - * //If the ripemod160 hash generated from data does not equal provided hash, anything below will never fire. - * eosio::print("ripemod160 hash generated from data equals provided hash"); - * @endcode - */ -void assert_ripemd160( const char* data, uint32_t length, const checksum160* hash ); - -/** - * Hashes `data` using `sha256` and stores result in memory pointed to by hash. - * @brief Hashes `data` using `sha256` and stores result in memory pointed to by hash. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - Hash pointer - * - * Example: -* - * @code - * checksum calc_hash; - * sha256( data, length, &calc_hash ); - * eos_assert( calc_hash == hash, "invalid hash" ); - * @endcode - */ -void sha256( const char* data, uint32_t length, checksum256* hash ); - -/** - * Hashes `data` using `sha1` and stores result in memory pointed to by hash. - * @brief Hashes `data` using `sha1` and stores result in memory pointed to by hash. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - Hash pointer - * - * Example: -* - * @code - * checksum calc_hash; - * sha1( data, length, &calc_hash ); - * eos_assert( calc_hash == hash, "invalid hash" ); - * @endcode - */ -void sha1( const char* data, uint32_t length, checksum160* hash ); - -/** - * Hashes `data` using `sha512` and stores result in memory pointed to by hash. - * @brief Hashes `data` using `sha512` and stores result in memory pointed to by hash. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - Hash pointer - * - * Example: -* - * @code - * checksum calc_hash; - * sha512( data, length, &calc_hash ); - * eos_assert( calc_hash == hash, "invalid hash" ); - * @endcode - */ -void sha512( const char* data, uint32_t length, checksum512* hash ); - -/** - * Hashes `data` using `ripemod160` and stores result in memory pointed to by hash. - * @brief Hashes `data` using `ripemod160` and stores result in memory pointed to by hash. - * - * @param data - Data you want to hash - * @param length - Data length - * @param hash - Hash pointer - * - * Example: -* - * @code - * checksum calc_hash; - * ripemod160( data, length, &calc_hash ); - * eos_assert( calc_hash == hash, "invalid hash" ); - * @endcode - */ -void ripemd160( const char* data, uint32_t length, checksum160* hash ); - -/** - * Calculates the public key used for a given signature and hash used to create a message. - * @brief Calculates the public key used for a given signature and hash used to create a message. - * - * @param digest - Hash used to create a message - * @param sig - Signature - * @param siglen - Signature length - * @param pub - Public key - * @param publen - Public key length - * - * Example: -* - * @code - * @endcode - */ -int recover_key( const checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen ); - -/** - * Tests a given public key with the generated key from digest and the signature. - * @brief Tests a given public key with the generated key from digest and the signature. - * - * @param digest - What the key will be generated from - * @param sig - Signature - * @param siglen - Signature length - * @param pub - Public key - * @param publen - Public key length - * - * @pre **assert recovery key** of `pub` equals the key generated from the `digest` parameter - * @post Executes next statement. If was not `true`, hard return. - * - * Example: -* - * @code - * checksum digest; - * char sig; - * size_t siglen; - * char pub; - * size_t publen; - * assert_recover_key( digest, sig, siglen, pub, publen ) - * // If the given public key does not match with the generated key from digest and the signature, anything below will never fire. - * eosio::print("pub key matches the pub key generated from digest"); - * @endcode - */ -void assert_recover_key( const checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen ); - -/// }@cryptocapi - -} diff --git a/contracts/eosiolib/datastream.hpp b/contracts/eosiolib/datastream.hpp deleted file mode 100644 index 97aed9f4cf7..00000000000 --- a/contracts/eosiolib/datastream.hpp +++ /dev/null @@ -1,1019 +0,0 @@ -/** - * @file datastream.hpp - * @copyright defined in eos/LICENSE - */ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - - -namespace eosio { - -/** - * @defgroup datastream Data Stream - * @brief Defines data stream for reading and writing data in the form of bytes - * @ingroup serialize - * @{ - */ - -/** - * %A data stream for reading and writing data in the form of bytes - * - * @brief %A data stream for reading and writing data in the form of bytes. - * @tparam T - Type of the datastream buffer - */ -template -class datastream { - public: - /** - * Construct a new datastream object given the size of the buffer and start position of the buffer - * - * @brief Construct a new datastream object - * @param start - The start position of the buffer - * @param s - The size of the buffer - */ - datastream( T start, size_t s ) - :_start(start),_pos(start),_end(start+s){} - - /** - * Skips a specified number of bytes from this stream - * - * @brief Skips a specific number of bytes from this stream - * @param s - The number of bytes to skip - */ - inline void skip( size_t s ){ _pos += s; } - - /** - * Reads a specified number of bytes from the stream into a buffer - * - * @brief Reads a specified number of bytes from this stream into a buffer - * @param d - The pointer to the destination buffer - * @param s - the number of bytes to read - * @return true - */ - inline bool read( char* d, size_t s ) { - eosio_assert( size_t(_end - _pos) >= (size_t)s, "read" ); - memcpy( d, _pos, s ); - _pos += s; - return true; - } - - /** - * Writes a specified number of bytes into the stream from a buffer - * - * @brief Writes a specified number of bytes into the stream from a buffer - * @param d - The pointer to the source buffer - * @param s - The number of bytes to write - * @return true - */ - inline bool write( const char* d, size_t s ) { - eosio_assert( _end - _pos >= (int32_t)s, "write" ); - memcpy( (void*)_pos, d, s ); - _pos += s; - return true; - } - - /** - * Writes a byte into the stream - * - * @brief Writes a byte into the stream - * @param c byte to write - * @return true - */ - inline bool put(char c) { - eosio_assert( _pos < _end, "put" ); - *_pos = c; - ++_pos; - return true; - } - - /** - * Reads a byte from the stream - * - * @brief Reads a byte from the stream - * @param c - The reference to destination byte - * @return true - */ - inline bool get( unsigned char& c ) { return get( *(char*)&c ); } - - /** - * Reads a byte from the stream - * - * @brief Reads a byte from the stream - * @param c - The reference to destination byte - * @return true - */ - inline bool get( char& c ) - { - eosio_assert( _pos < _end, "get" ); - c = *_pos; - ++_pos; - return true; - } - - /** - * Retrieves the current position of the stream - * - * @brief Retrieves the current position of the stream - * @return T - The current position of the stream - */ - T pos()const { return _pos; } - inline bool valid()const { return _pos <= _end && _pos >= _start; } - - /** - * Sets the position within the current stream - * - * @brief Sets the position within the current stream - * @param p - The offset relative to the origin - * @return true if p is within the range - * @return false if p is not within the rawnge - */ - inline bool seekp(size_t p) { _pos = _start + p; return _pos <= _end; } - - /** - * Gets the position within the current stream - * - * @brief Gets the position within the current stream - * @return p - The position within the current stream - */ - inline size_t tellp()const { return size_t(_pos - _start); } - - /** - * Returns the number of remaining bytes that can be read/skipped - * - * @brief Returns the number of remaining bytes that can be read/skipped - * @return size_t - The number of remaining bytes - */ - inline size_t remaining()const { return _end - _pos; } - private: - /** - * The start position of the buffer - * - * @brief The start position of the buffer - */ - T _start; - /** - * The current position of the buffer - * - * @brief The current position of the buffer - */ - T _pos; - /** - * The end position of the buffer - * - * @brief The end position of the buffer - */ - T _end; -}; - -/** - * @brief Specialization of datastream used to help determine the final size of a serialized value. - * Specialization of datastream used to help determine the final size of a serialized value - */ -template<> -class datastream { - public: - /** - * Construct a new specialized datastream object given the initial size - * - * @brief Construct a new specialized datastream object - * @param init_size - The initial size - */ - datastream( size_t init_size = 0):_size(init_size){} - - /** - * Increment the size by s. This behaves the same as write( const char* ,size_t s ). - * - * @brief Increase the size by s - * @param s - The amount of size to increase - * @return true - */ - inline bool skip( size_t s ) { _size += s; return true; } - - /** - * Increment the size by s. This behaves the same as skip( size_t s ) - * - * @brief Increase the size by s - * @param s - The amount of size to increase - * @return true - */ - inline bool write( const char* ,size_t s ) { _size += s; return true; } - - /** - * Increment the size by one - * - * @brief Increase the size by one - * @return true - */ - inline bool put(char ) { ++_size; return true; } - - /** - * Check validity. It's always valid - * - * @brief Check validity - * @return true - */ - inline bool valid()const { return true; } - - /** - * Set new size - * - * @brief Set new size - * @param p - The new size - * @return true - */ - inline bool seekp(size_t p) { _size = p; return true; } - - /** - * Get the size - * - * @brief Get the size - * @return size_t - The size - */ - inline size_t tellp()const { return _size; } - - /** - * Always returns 0 - * - * @brief Always returns 0 - * @return size_t - 0 - */ - inline size_t remaining()const { return 0; } - private: - /** - * The size used to determine the final size of a serialized value. - * - * @brief The size used to determine the final size of a serialized value. - */ - size_t _size; -}; - -/** - * Serialize a public_key into a stream - * - * @brief Serialize a public_key - * @param ds - The stream to write - * @param pubkey - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const public_key pubkey) { - ds.write( (const char*)&pubkey, sizeof(pubkey)); - return ds; -} - -/** - * Deserialize a public_key from a stream - * - * @brief Deserialize a public_key - * @param ds - The stream to read - * @param pubkey - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, public_key& pubkey) { - ds.read((char*)&pubkey, sizeof(pubkey)); - return ds; -} - -/** - * Serialize a key256 into a stream - * - * @brief Serialize a key256 - * @param ds - The stream to write - * @param d - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const key256& d) { - ds.write( (const char*)d.data(), d.size() ); - return ds; -} - -/** - * Deserialize a key256 from a stream - * - * @brief Deserialize a key256 - * @param ds - The stream to read - * @param d - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, key256& d) { - ds.read((char*)d.data(), d.size() ); - return ds; -} - -/** - * Serialize a bool into a stream - * - * @brief Serialize a bool into a stream - * @param ds - The stream to read - * @param d - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const bool& d) { - return ds << uint8_t(d); -} - -/** - * Deserialize a bool from a stream - * - * @brief Deserialize a bool - * @param ds - The stream to read - * @param d - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, bool& d) { - uint8_t t; - ds >> t; - d = t; - return ds; -} - -/** - * Serialize a checksum256 into a stream - * - * @brief Serialize a checksum256 - * @param ds - The stream to write - * @param d - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const checksum256& d) { - ds.write( (const char*)&d.hash[0], sizeof(d.hash) ); - return ds; -} - -/** - * Deserialize a checksum256 from a stream - * - * @brief Deserialize a checksum256 - * @param ds - The stream to read - * @param d - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, checksum256& d) { - ds.read((char*)&d.hash[0], sizeof(d.hash) ); - return ds; -} - -/** - * Serialize a string into a stream - * - * @brief Serialize a string - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::string& v ) { - ds << unsigned_int( v.size() ); - if (v.size()) - ds.write(v.data(), v.size()); - return ds; -} - -/** - * Deserialize a string from a stream - * - * @brief Deserialize a string - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::string& v ) { - std::vector tmp; - ds >> tmp; - if( tmp.size() ) - v = std::string(tmp.data(),tmp.data()+tmp.size()); - else - v = std::string(); - return ds; -} - -/** - * Serialize a fixed size array into a stream - * - * @brief Serialize a fixed size array - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the array - * @tparam N - Size of the array - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::array& v ) { - for( const auto& i : v ) - ds << i; - return ds; -} - - -/** - * Deserialize a fixed size array from a stream - * - * @brief Deserialize a fixed size array - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the array - * @tparam N - Size of the array - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::array& v ) { - for( auto& i : v ) - ds >> i; - return ds; -} - -namespace _datastream_detail { - /** - * Check if type T is a pointer - * - * @brief Check if type T is a pointer - * @tparam T - The type to be checked - * @return true if T is a pointer - * @return false otherwise - */ - template - constexpr bool is_pointer() { - return std::is_pointer::value || - std::is_null_pointer::value || - std::is_member_pointer::value; - } - - /** - * Check if type T is a primitive type - * - * @brief Check if type T is a primitive type - * @tparam T - The type to be checked - * @return true if T is a primitive type - * @return false otherwise - */ - template - constexpr bool is_primitive() { - return std::is_arithmetic::value || - std::is_enum::value; - } -} - -/** - * Pointer should not be serialized, so this function will always throws an error - * - * @brief Deserialize a a pointer - * @param ds - The stream to read - * @tparam DataStream - Type of datastream - * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream - * @post Throw an exception if it is a pointer - */ -template()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T ) { - static_assert(!_datastream_detail::is_pointer(), "Pointers should not be serialized" ); - return ds; -} - -/** - * Serialize a fixed size array of non-primitive and non-pointer type - * - * @brief Serialize a fixed size array of non-primitive and non-pointer type - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream - */ -template() && - !_datastream_detail::is_pointer()>* = nullptr> -DataStream& operator << ( DataStream& ds, const T (&v)[N] ) { - ds << unsigned_int( N ); - for( uint32_t i = 0; i < N; ++i ) - ds << v[i]; - return ds; -} - -/** - * Serialize a fixed size array of non-primitive type - * - * @brief Serialize a fixed size array of non-primitive type - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream - */ -template()>* = nullptr> -DataStream& operator << ( DataStream& ds, const T (&v)[N] ) { - ds << unsigned_int( N ); - ds.write((char*)&v[0], sizeof(v)); - return ds; -} - -/** - * Deserialize a fixed size array of non-primitive and non-pointer type - * - * @brief Deserialize a fixed size array of non-primitive and non-pointer type - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam T - Type of the object contained in the array - * @tparam N - Size of the array - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template() && - !_datastream_detail::is_pointer()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T (&v)[N] ) { - unsigned_int s; - ds >> s; - eosio_assert( N == s.value, "T[] size and unpacked size don't match"); - for( uint32_t i = 0; i < N; ++i ) - ds >> v[i]; - return ds; -} - -/** - * Deserialize a fixed size array of non-primitive type - * - * @brief Deserialize a fixed size array of non-primitive type - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam T - Type of the object contained in the array - * @tparam N - Size of the array - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T (&v)[N] ) { - unsigned_int s; - ds >> s; - eosio_assert( N == s.value, "T[] size and unpacked size don't match"); - ds.read((char*)&v[0], sizeof(v)); - return ds; -} - -/** - * Serialize a vector of char - * - * @brief Serialize a vector of char - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const vector& v ) { - ds << unsigned_int( v.size() ); - ds.write( v.data(), v.size() ); - return ds; -} - -/** - * Serialize a vector - * - * @brief Serialize a vector - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the vector - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const vector& v ) { - ds << unsigned_int( v.size() ); - for( const auto& i : v ) - ds << i; - return ds; -} - -/** - * Deserialize a vector of char - * - * @brief Deserialize a vector of char - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, vector& v ) { - unsigned_int s; - ds >> s; - v.resize( s.value ); - ds.read( v.data(), v.size() ); - return ds; -} - -/** - * Deserialize a vector - * - * @brief Deserialize a vector - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of the object contained in the vector - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, vector& v ) { - unsigned_int s; - ds >> s; - v.resize(s.value); - for( auto& i : v ) - ds >> i; - return ds; -} - -template -DataStream& operator << ( DataStream& ds, const std::set& s ) { - ds << unsigned_int( s.size() ); - for( const auto& i : s ) { - ds << i; - } - return ds; -} - -template -DataStream& operator >> ( DataStream& ds, std::set& s ) { - s.clear(); - unsigned_int sz; ds >> sz; - - for( uint32_t i = 0; i < sz.value; ++i ) { - T v; - ds >> v; - s.emplace( std::move(v) ); - } - return ds; -} - -/** - * Serialize a map - * - * @brief Serialize a map - * @param ds - The stream to write - * @param m - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam K - Type of the key contained in the map - * @tparam V - Type of the value contained in the map - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator << ( DataStream& ds, const std::map& m ) { - ds << unsigned_int( m.size() ); - for( const auto& i : m ) { - ds << i.first << i.second; - } - return ds; -} - -/** - * Deserialize a map - * - * @brief Deserialize a map - * @param ds - The stream to read - * @param m - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam K - Type of the key contained in the map - * @tparam V - Type of the value contained in the map - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator >> ( DataStream& ds, std::map& m ) { - m.clear(); - unsigned_int s; ds >> s; - - for (uint32_t i = 0; i < s.value; ++i) { - K k; V v; - ds >> k >> v; - m.emplace( std::move(k), std::move(v) ); - } - return ds; -} - -template -DataStream& operator << ( DataStream& ds, const boost::container::flat_set& s ) { - ds << unsigned_int( s.size() ); - for( const auto& i : s ) { - ds << i; - } - return ds; -} - -template -DataStream& operator >> ( DataStream& ds, boost::container::flat_set& s ) { - s.clear(); - unsigned_int sz; ds >> sz; - - for( uint32_t i = 0; i < sz.value; ++i ) { - T v; - ds >> v; - s.emplace( std::move(v) ); - } - return ds; -} - - -/** - * Serialize a flat map - * - * @brief Serialize a flat map - * @param ds - The stream to write - * @param m - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam K - Type of the key contained in the flat map - * @tparam V - Type of the value contained in the flat map - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator<<( DataStream& ds, const boost::container::flat_map& m ) { - ds << unsigned_int( m.size() ); - for( const auto& i : m ) - ds << i.first << i.second; - return ds; -} - -/** - * Deserialize a flat map - * - * @brief Deserialize a flat map - * @param ds - The stream to read - * @param m - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam K - Type of the key contained in the flat map - * @tparam V - Type of the value contained in the flat map - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator>>( DataStream& ds, boost::container::flat_map& m ) { - m.clear(); - unsigned_int s; ds >> s; - - for( uint32_t i = 0; i < s.value; ++i ) { - K k; V v; - ds >> k >> v; - m.emplace( std::move(k), std::move(v) ); - } - return ds; -} - -/** - * Serialize a tuple - * - * @brief Serialize a tuple - * @param ds - The stream to write - * @param t - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator<<( DataStream& ds, const std::tuple& t ) { - boost::fusion::for_each( t, [&]( const auto& i ) { - ds << i; - }); - return ds; -} - -/** - * Deserialize a tuple - * - * @brief Deserialize a tuple - * @param ds - The stream to read - * @param t - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream - */ -template -DataStream& operator>>( DataStream& ds, std::tuple& t ) { - boost::fusion::for_each( t, [&]( auto& i ) { - ds >> i; - }); - return ds; -} - -/** - * Serialize a class - * - * @brief Serialize a class - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of class - * @return DataStream& - Reference to the datastream - */ -template::value>* = nullptr> -DataStream& operator<<( DataStream& ds, const T& v ) { - boost::pfr::for_each_field(v, [&](const auto& field) { - ds << field; - }); - return ds; -} - -/** - * Deserialize a class - * - * @brief Deserialize a class - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of class - * @return DataStream& - Reference to the datastream - */ -template::value>* = nullptr> -DataStream& operator>>( DataStream& ds, T& v ) { - boost::pfr::for_each_field(v, [&](auto& field) { - ds >> field; - }); - return ds; -} - -/** - * Serialize a primitive type - * - * @brief Serialize a primitive type - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @tparam T - Type of the primitive type - * @return DataStream& - Reference to the datastream - */ -template()>* = nullptr> -DataStream& operator<<( DataStream& ds, const T& v ) { - ds.write( (const char*)&v, sizeof(T) ); - return ds; -} - -/** - * Deserialize a primitive type - * - * @brief Deserialize a primitive type - * @param ds - The stream to read - * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @tparam T - Type of the primitive type - * @return DataStream& - Reference to the datastream - */ -template()>* = nullptr> -DataStream& operator>>( DataStream& ds, T& v ) { - ds.read( (char*)&v, sizeof(T) ); - return ds; -} - -/** - * Unpack data inside a fixed size buffer as T - * - * @brief Unpack data inside a fixed size buffer as T - * @tparam T - Type of the unpacked data - * @param buffer - Pointer to the buffer - * @param len - Length of the buffer - * @return T - The unpacked data - */ -template -T unpack( const char* buffer, size_t len ) { - T result; - datastream ds(buffer,len); - ds >> result; - return result; -} - -/** - * Unpack data inside a variable size buffer as T - * - * @brief Unpack data inside a variable size buffer as T - * @tparam T - Type of the unpacked data - * @param bytes - Buffer - * @return T - The unpacked data - */ -template -T unpack( const vector& bytes ) { - return unpack( bytes.data(), bytes.size() ); -} - -/** - * Get the size of the packed data - * - * @brief Get the size of the packed data - * @tparam T - Type of the data to be packed - * @param value - Data to be packed - * @return size_t - Size of the packed data - */ -template -size_t pack_size( const T& value ) { - datastream ps; - ps << value; - return ps.tellp(); -} - -/** - * Get packed data - * - * @brief Get packed data - * @tparam T - Type of the data to be packed - * @param value - Data to be packed - * @return bytes - The packed data - */ -template -bytes pack( const T& value ) { - bytes result; - result.resize(pack_size(value)); - - datastream ds( result.data(), result.size() ); - ds << value; - return result; -} - -/** - * Serialize a checksum160 type - * - * @brief Serialize a checksum160 type - * @param ds - The stream to write - * @param cs - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const checksum160& cs) { - ds.write((const char*)&cs.hash[0], sizeof(cs.hash)); - return ds; -} - -/** - * Deserialize a checksum160 type - * - * @brief Deserialize a checksum160 type - * @param ds - The stream to read - * @param cs - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, checksum160& cs) { - ds.read((char*)&cs.hash[0], sizeof(cs.hash)); - return ds; -} - -/** - * Serialize a checksum512 type - * - * @brief Serialize a checksum512 type - * @param ds - The stream to write - * @param cs - The value to serialize - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator<<(datastream& ds, const checksum512& cs) { - ds.write((const char*)&cs.hash[0], sizeof(cs.hash)); - return ds; -} - -/** - * Deserialize a checksum512 type - * - * @brief Deserialize a checksum512 type - * @param ds - The stream to read - * @param cs - The destination for deserialized value - * @tparam Stream - Type of datastream buffer - * @return datastream& - Reference to the datastream - */ -template -inline datastream& operator>>(datastream& ds, checksum512& cs) { - ds.read((char*)&cs.hash[0], sizeof(cs.hash)); - return ds; -} -/// @} datastream -} diff --git a/contracts/eosiolib/db.h b/contracts/eosiolib/db.h deleted file mode 100644 index f112ef5bf6d..00000000000 --- a/contracts/eosiolib/db.h +++ /dev/null @@ -1,940 +0,0 @@ -/** - * @file db.h - * @copyright defined in eos/LICENSE - * @brief Defines C API for interfacing with blockchain database - */ -#pragma once - -#include -extern "C" { -/** - * @defgroup database Database API - * @brief Defines APIs that store and retrieve data on the blockchain - * @ingroup contractdev - * - * @defgroup databasecpp Database C++ API - * @brief Defines an interface to EOSIO database - * @ingroup database - * - * @details - * EOSIO organizes data according to the following broad structure: - * - **code** - the account name which has write permission - * - **scope** - an area where the data is stored - * - **table** - a name for the table that is being stored - * - **record** - a row in the table - */ - -/** - * @defgroup databasec Database C API - * @brief Defines %C APIs for interfacing with the database. - * @ingroup database - * - * @details Database C API provides low level interface to EOSIO database. - * - * @section tabletypes Supported Table Types - * Following are the table types supported by the C API: - * 1. Primary Table - * - 64-bit integer key - * 2. Secondary Index Table - * - 64-bit integer key - * - 128-bit integer key - * - 256-bit integer key - * - double key - * - long double key - * @{ - */ - -/** - * - * Store a record in a primary 64-bit integer index table - * - * @brief Store a record in a primary 64-bit integer index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - ID of the entry - * @param data - Record to store - * @param len - Size of data - * @pre `data` is a valid pointer to a range of memory at least `len` bytes long - * @pre `*((uint64_t*)data)` stores the primary key - * @return iterator to the newly created table row - * @post a new entry is created in the table - */ -int32_t db_store_i64(account_name scope, table_name table, account_name payer, uint64_t id, const void* data, uint32_t len); - -/** - * - * Update a record in a primary 64-bit integer index table - * - * @brief Update a record in a primary 64-bit integer index table - * @param iterator - Iterator to the table row containing the record to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param data - New updated record - * @param len - Size of data - * @pre `data` is a valid pointer to a range of memory at least `len` bytes long - * @pre `*((uint64_t*)data)` stores the primary key - * @pre `iterator` points to an existing table row in the table - * @post the record contained in the table row pointed to by `iterator` is replaced with the new updated record - */ -void db_update_i64(int32_t iterator, account_name payer, const void* data, uint32_t len); - -/** - * - * Remove a record from a primary 64-bit integer index table - * - * @brief Remove a record from a primary 64-bit integer index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - * - * Example: - * - * @code - * int32_t itr = db_find_i64(receiver, receiver, table1, N(alice)); - * eosio_assert(itr >= 0, "Alice cannot be removed since she was already not found in the table"); - * db_remove_i64(itr); - * @endcode - */ -void db_remove_i64(int32_t iterator); - -/** - * - * Get a record in a primary 64-bit integer index table - * - * @brief Get a record in a primary 64-bit integer index table - * @param iterator - The iterator to the table row containing the record to retrieve - * @param data - Pointer to the buffer which will be filled with the retrieved record - * @param len - Size of the buffer - * @return size of the data copied into the buffer if `len > 0`, or size of the retrieved record if `len == 0`. - * @pre `iterator` points to an existing table row in the table - * @pre `data` is a valid pointer to a range of memory at least `len` bytes long - * @post `data` will be filled with the retrieved record (truncated to the first `len` bytes if necessary) - * - * Example: - * - * @code - * char value[50]; - * auto len = db_get_i64(itr, value, 0); - * eosio_assert(len <= 50, "buffer to small to store retrieved record"); - * db_get_i64(itr, value, len); - * @endcode - */ -int32_t db_get_i64(int32_t iterator, const void* data, uint32_t len); - -/** - * - * Find the table row following the referenced table row in a primary 64-bit integer index table - * - * @brief Find the table row following the referenced table row in a primary 64-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - * - * Example: - * - * @code - * int32_t charlie_itr = db_find_i64(receiver, receiver, table1, N(charlie)); - * // expect nothing after charlie - * uint64_t prim = 0 - * int32_t end_itr = db_next_i64(charlie_itr, &prim); - * eosio_assert(end_itr < -1, "Charlie was not the last entry in the table"); - * @endcode - */ -int32_t db_next_i64(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a primary 64-bit integer index table - * - * @brief Find the table row preceding the referenced table row in a primary 64-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - * - * Example: - * - * @code - * uint64_t prim = 0; - * int32_t itr_prev = db_previous_i64(itr, &prim); - * @endcode - */ -int32_t db_previous_i64(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a primary 64-bit integer index table by primary key - * - * @brief Find a table row in a primary 64-bit integer index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param id - The primary key of the table row to look up - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - * - * Example: - * - * @code - * int itr = db_find_i64(receiver, receiver, table1, N(charlie)); - * @endcode - */ -int32_t db_find_i64(account_name code, account_name scope, table_name table, uint64_t id); - -/** - * - * Find the table row in a primary 64-bit integer index table that matches the lowerbound condition for a given primary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest primary key that is >= the given key - * - * @brief Find the table row in a primary 64-bit integer index table that matches the lowerbound condition for a given primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param id - The primary key used to determine the lowerbound - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_lowerbound_i64(account_name code, account_name scope, table_name table, uint64_t id); - -/** - * - * Find the table row in a primary 64-bit integer index table that matches the upperbound condition for a given primary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest primary key that is > the given key - * - * @brief Find the table row in a primary 64-bit integer index table that matches the upperbound condition for a given primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param id - The primary key used to determine the upperbound - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_upperbound_i64(account_name code, account_name scope, table_name table, uint64_t id); - -/** - * - * Get an iterator representing just-past-the-end of the last table row of a primary 64-bit integer index table - * - * @brief Get an iterator representing just-past-the-end of the last table row of a primary 64-bit integer index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -int32_t db_end_i64(account_name code, account_name scope, table_name table); - -/** - * - * Store an association of a 64-bit integer secondary key to a primary key in a secondary 64-bit integer index table - * - * @brief Store an association of a 64-bit integer secondary key to a primary key in a secondary 64-bit integer index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param secondary - Pointer to the secondary key - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and secondary key `*secondary` is created in the secondary 64-bit integer index table - */ -int32_t db_idx64_store(account_name scope, table_name table, account_name payer, uint64_t id, const uint64_t* secondary); - -/** - * - * Update an association for a 64-bit integer secondary key to a primary key in a secondary 64-bit integer index table - * - * @brief Update an association for a 64-bit integer secondary key to a primary key in a secondary 64-bit integer index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param secondary - Pointer to the **new** secondary key that will replace the existing one of the association - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by `*secondary` - */ -void db_idx64_update(int32_t iterator, account_name payer, const uint64_t* secondary); - -/** - * - * Remove a table row from a secondary 64-bit integer index table - * - * @brief Remove a table row from a secondary 64-bit integer index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -void db_idx64_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary 64-bit integer index table - * - * @brief Find the table row following the referenced table row in a secondary 64-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx64_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary 64-bit integer index table - * - * @brief Find the table row preceding the referenced table row in a secondary 64-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx64_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary 64-bit integer index table by primary key - * - * @brief Find a table row in a secondary 64-bit integer index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to a `uint64_t` variable which will have its value set to the secondary key of the found table row - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx64_find_primary(account_name code, account_name scope, table_name table, uint64_t* secondary, uint64_t primary); - -/** - * - * Find a table row in a secondary 64-bit integer index table by secondary key - * - * @brief Find a table row in a secondary 64-bit integer index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key used to lookup the table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to `*secondary` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx64_find_secondary(account_name code, account_name scope, table_name table, const uint64_t* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary 64-bit integer index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key - * - * @brief Find the table row in a secondary 64-bit integer index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx64_lowerbound(account_name code, account_name scope, table_name table, uint64_t* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary 64-bit integer index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key - * - * @brief Find the table row in a secondary 64-bit integer index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx64_upperbound(account_name code, account_name scope, table_name table, uint64_t* secondary, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary 64-bit integer index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary 64-bit integer index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -int32_t db_idx64_end(account_name code, account_name scope, table_name table); - - - -/** - * - * Store an association of a 128-bit integer secondary key to a primary key in a secondary 128-bit integer index table - * - * @brief Store an association of a 128-bit integer secondary key to a primary key in a secondary 128-bit integer index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param secondary - Pointer to the secondary key - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and secondary key `*secondary` is created in the secondary 128-bit integer index table - */ -int32_t db_idx128_store(account_name scope, table_name table, account_name payer, uint64_t id, const uint128_t* secondary); - -/** - * - * Update an association for a 128-bit integer secondary key to a primary key in a secondary 128-bit integer index table - * - * @brief Update an association for a 128-bit integer secondary key to a primary key in a secondary 128-bit integer index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param secondary - Pointer to the **new** secondary key that will replace the existing one of the association - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by `*secondary` - */ -void db_idx128_update(int32_t iterator, account_name payer, const uint128_t* secondary); - -/** - * - * Remove a table row from a secondary 128-bit integer index table - * - * @brief Remove a table row from a secondary 128-bit integer index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -void db_idx128_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary 128-bit integer index table - * - * @brief Find the table row following the referenced table row in a secondary 128-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx128_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary 128-bit integer index table - * - * @brief Find the table row preceding the referenced table row in a secondary 128-bit integer index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx128_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary 128-bit integer index table by primary key - * - * @brief Find a table row in a secondary 128-bit integer index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to a `uint128_t` variable which will have its value set to the secondary key of the found table row - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx128_find_primary(account_name code, account_name scope, table_name table, uint128_t* secondary, uint64_t primary); - -/** - * - * Find a table row in a secondary 128-bit integer index table by secondary key - * - * @brief Find a table row in a secondary 128-bit integer index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key used to lookup the table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to `*secondary` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx128_find_secondary(account_name code, account_name scope, table_name table, const uint128_t* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary 128-bit integer index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key - * - * @brief Find the table row in a secondary 128-bit integer index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx128_lowerbound(account_name code, account_name scope, table_name table, uint128_t* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary 128-bit integer index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key - * - * @brief Find the table row in a secondary 128-bit integer index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx128_upperbound(account_name code, account_name scope, table_name table, uint128_t* secondary, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary 128-bit integer index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary 128-bit integer index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -int32_t db_idx128_end(account_name code, account_name scope, table_name table); - -/** - * - * Store an association of a 256-bit secondary key to a primary key in a secondary 256-bit index table - * - * @brief Store an association of a 256-bit secondary key to a primary key in a secondary 256-bit index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param data - Pointer to the secondary key data stored as an array of 2 `uint128_t` integers - * @param data_len - Must be set to 2 - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and the specified secondary key is created in the secondary 256-bit index table - */ -int32_t db_idx256_store(account_name scope, table_name table, account_name payer, uint64_t id, const uint128_t* data, uint32_t data_len ); - -/** - * - * Update an association for a 256-bit secondary key to a primary key in a secondary 256-bit index table - * - * @brief Update an association for a 256-bit secondary key to a primary key in a secondary 256-bit index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param data - Pointer to the **new** secondary key data (which is stored as an array of 2 `uint128_t` integers) that will replace the existing one of the association - * @param data_len - Must be set to 2 - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by the specified secondary key - */ -void db_idx256_update(int32_t iterator, account_name payer, const uint128_t* data, uint32_t data_len); - -/** - * - * Remove a table row from a secondary 256-bit index table - * - * @brief Remove a table row from a secondary 256-bit index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -void db_idx256_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary 256-bit index table - * - * @brief Find the table row following the referenced table row in a secondary 256-bit index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx256_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary 256-bit index table - * - * @brief Find the table row preceding the referenced table row in a secondary 256-bit index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx256_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary 256-bit index table by primary key - * - * @brief Find a table row in a secondary 128-bit integer index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param data - Pointer to the an array of 2 `uint128_t` integers which will act as the buffer to hold the retrieved secondary key of the found table row - * @param data_len - Must be set to 2 - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, the buffer pointed to by `data` will be filled with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx256_find_primary(account_name code, account_name scope, table_name table, uint128_t* data, uint32_t data_len, uint64_t primary); - -/** - * - * Find a table row in a secondary 256-bit index table by secondary key - * - * @brief Find a table row in a secondary 256-bit index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param data - Pointer to the secondary key data (which is stored as an array of 2 `uint128_t` integers) used to lookup the table row - * @param data_len - Must be set to 2 - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to the specified secondary key or the end iterator of the table if the table row could not be found - */ -int32_t db_idx256_find_secondary(account_name code, account_name scope, table_name table, const uint128_t* data, uint32_t data_len, uint64_t* primary); - -/** - * - * Find the table row in a secondary 256-bit index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key (uses lexicographical ordering on the 256-bit keys) - * - * @brief Find the table row in a secondary 256-bit index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param data - Pointer to the secondary key data (which is stored as an array of 2 `uint128_t` integers) first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param data_len - Must be set to 2 - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, the buffer pointed to by `data` will be filled with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx256_lowerbound(account_name code, account_name scope, table_name table, uint128_t* data, uint32_t data_len, uint64_t* primary); - -/** - * - * Find the table row in a secondary 256-bit index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key (uses lexicographical ordering on the 256-bit keys) - * - * @brief Find the table row in a secondary 256-bit index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param data - Pointer to the secondary key data (which is stored as an array of 2 `uint128_t` integers) first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param data_len - Must be set to 2 - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, the buffer pointed to by `data` will be filled with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx256_upperbound(account_name code, account_name scope, table_name table, uint128_t* data, uint32_t data_len, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary 256-bit index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary 256-bit index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -int32_t db_idx256_end(account_name code, account_name scope, table_name table); - -/** - * - * Store an association of a double-precision floating-point secondary key to a primary key in a secondary double-precision floating-point index table - * - * @brief Store an association of a double-precision floating-point secondary key to a primary key in a secondary double-precision floating-point index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param secondary - Pointer to the secondary key - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and secondary key `*secondary` is created in the secondary double-precision floating-point index table - */ -int32_t db_idx_double_store(account_name scope, table_name table, account_name payer, uint64_t id, const double* secondary); - -/** - * - * Update an association for a double-precision floating-point secondary key to a primary key in a secondary double-precision floating-point index table - * - * @brief Update an association for a double-precision floating-point secondary key to a primary key in a secondary double-precision floating-point index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param secondary - Pointer to the **new** secondary key that will replace the existing one of the association - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by `*secondary` - */ -void db_idx_double_update(int32_t iterator, account_name payer, const double* secondary); - -/** - * - * Remove a table row from a secondary double-precision floating-point index table - * - * @brief Remove a table row from a secondary double-precision floating-point index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -void db_idx_double_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary double-precision floating-point index table - * - * @brief Find the table row following the referenced table row in a secondary double-precision floating-point index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx_double_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary double-precision floating-point index table - * - * @brief Find the table row preceding the referenced table row in a secondary double-precision floating-point index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx_double_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary double-precision floating-point index table by primary key - * - * @brief Find a table row in a secondary double-precision floating-point index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to a `double` variable which will have its value set to the secondary key of the found table row - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx_double_find_primary(account_name code, account_name scope, table_name table, double* secondary, uint64_t primary); - -/** - * - * Find a table row in a secondary double-precision floating-point index table by secondary key - * - * @brief Find a table row in a secondary double-precision floating-point index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key used to lookup the table row - * @param primary - Pointer to a `double` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to `*secondary` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx_double_find_secondary(account_name code, account_name scope, table_name table, const double* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary double-precision floating-point index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key - * - * @brief Find the table row in a secondary double-precision floating-point index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx_double_lowerbound(account_name code, account_name scope, table_name table, double* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary double-precision floating-point index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key - * - * @brief Find the table row in a secondary double-precision floating-point index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx_double_upperbound(account_name code, account_name scope, table_name table, double* secondary, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary double-precision floating-point index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary double-precision floating-point index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -int32_t db_idx_double_end(account_name code, account_name scope, table_name table); - -/** - * - * Store an association of a quadruple-precision floating-point secondary key to a primary key in a secondary quadruple-precision floating-point index table - * - * @brief Store an association of a quadruple-precision floating-point secondary key to a primary key in a secondary quadruple-precision floating-point index table - * @param scope - The scope where the table resides (implied to be within the code of the current receiver) - * @param table - The table name - * @param payer - The account that pays for the storage costs - * @param id - The primary key to which to associate the secondary key - * @param secondary - Pointer to the secondary key - * @return iterator to the newly created table row - * @post new secondary key association between primary key `id` and secondary key `*secondary` is created in the secondary quadruple-precision floating-point index table - */ -int32_t db_idx_long_double_store(account_name scope, table_name table, account_name payer, uint64_t id, const long double* secondary); - -/** - * - * Update an association for a quadruple-precision floating-point secondary key to a primary key in a secondary quadruple-precision floating-point index table - * - * @brief Update an association for a quadruple-precision floating-point secondary key to a primary key in a secondary quadruple-precision floating-point index table - * @param iterator - The iterator to the table row containing the secondary key association to update - * @param payer - The account that pays for the storage costs (use 0 to continue using current payer) - * @param secondary - Pointer to the **new** secondary key that will replace the existing one of the association - * @pre `iterator` points to an existing table row in the table - * @post the secondary key of the table row pointed to by `iterator` is replaced by `*secondary` - */ -void db_idx_long_double_update(int32_t iterator, account_name payer, const long double* secondary); - -/** - * - * Remove a table row from a secondary quadruple-precision floating-point index table - * - * @brief Remove a table row from a secondary quadruple-precision floating-point index table - * @param iterator - Iterator to the table row to remove - * @pre `iterator` points to an existing table row in the table - * @post the table row pointed to by `iterator` is removed and the associated storage costs are refunded to the payer - */ -void db_idx_long_double_remove(int32_t iterator); - -/** - * - * Find the table row following the referenced table row in a secondary quadruple-precision floating-point index table - * - * @brief Find the table row following the referenced table row in a secondary quadruple-precision floating-point index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the next table row - * @return iterator to the table row following the referenced table row (or the end iterator of the table if the referenced table row is the last one in the table) - * @pre `iterator` points to an existing table row in the table - * @post `*primary` will be replaced with the primary key of the table row following the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx_long_double_next(int32_t iterator, uint64_t* primary); - -/** - * - * Find the table row preceding the referenced table row in a secondary quadruple-precision floating-point index table - * - * @brief Find the table row preceding the referenced table row in a secondary quadruple-precision floating-point index table - * @param iterator - The iterator to the referenced table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the previous table row - * @return iterator to the table row preceding the referenced table row assuming one exists (it will return -1 if the referenced table row is the first one in the table) - * @pre `iterator` points to an existing table row in the table or it is the end iterator of the table - * @post `*primary` will be replaced with the primary key of the table row preceding the referenced table row if it exists, otherwise `*primary` will be left untouched - */ -int32_t db_idx_long_double_previous(int32_t iterator, uint64_t* primary); - -/** - * - * Find a table row in a secondary quadruple-precision floating-point index table by primary key - * - * @brief Find a table row in a secondary quadruple-precision floating-point index table by primary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to a `long double` variable which will have its value set to the secondary key of the found table row - * @param primary - The primary key of the table row to look up - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @return iterator to the table row with a primary key equal to `id` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx_long_double_find_primary(account_name code, account_name scope, table_name table, long double* secondary, uint64_t primary); - -/** - * - * Find a table row in a secondary quadruple-precision floating-point index table by secondary key - * - * @brief Find a table row in a secondary quadruple-precision floating-point index table by secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key used to lookup the table row - * @param primary - Pointer to a `long double` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the first table row with a secondary key equal to `*secondary` or the end iterator of the table if the table row could not be found - */ -int32_t db_idx_long_double_find_secondary(account_name code, account_name scope, table_name table, const long double* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary quadruple-precision floating-point index table that matches the lowerbound condition for a given secondary key - * The table row that matches the lowerbound condition is the first table row in the table with the lowest secondary key that is >= the given key - * - * @brief Find the table row in a secondary quadruple-precision floating-point index table that matches the lowerbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the lowerbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx_long_double_lowerbound(account_name code, account_name scope, table_name table, long double* secondary, uint64_t* primary); - -/** - * - * Find the table row in a secondary quadruple-precision floating-point index table that matches the upperbound condition for a given secondary key - * The table row that matches the upperbound condition is the first table row in the table with the lowest secondary key that is > the given key - * - * @brief Find the table row in a secondary quadruple-precision floating-point index table that matches the upperbound condition for a given secondary key - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @param secondary - Pointer to secondary key first used to determine the upperbound and which is then replaced with the secondary key of the found table row - * @param primary - Pointer to a `uint64_t` variable which will have its value set to the primary key of the found table row - * @post If and only if the table row is found, `*secondary` will be replaced with the secondary key of the found table row - * @post If and only if the table row is found, `*primary` will be replaced with the primary key of the found table row - * @return iterator to the found table row or the end iterator of the table if the table row could not be found - */ -int32_t db_idx_long_double_upperbound(account_name code, account_name scope, table_name table, long double* secondary, uint64_t* primary); - -/** - * - * Get an end iterator representing just-past-the-end of the last table row of a secondary quadruple-precision floating-point index table - * - * @brief Get an end iterator representing just-past-the-end of the last table row of a secondary quadruple-precision floating-point index table - * @param code - The name of the owner of the table - * @param scope - The scope where the table resides - * @param table - The table name - * @return end iterator of the table - */ -int32_t db_idx_long_double_end(account_name code, account_name scope, table_name table); - -///@} databasec -} diff --git a/contracts/eosiolib/dispatcher.hpp b/contracts/eosiolib/dispatcher.hpp deleted file mode 100644 index eadc55bc3e8..00000000000 --- a/contracts/eosiolib/dispatcher.hpp +++ /dev/null @@ -1,155 +0,0 @@ -#pragma once -#include -#include - -#include -#include - -#include -#define N(X) ::eosio::string_to_name(#X) -namespace eosio { - - template - bool dispatch( uint64_t code, uint64_t act ) { - if( code == FirstAction::get_account() && FirstAction::get_name() == act ) { - Contract().on( unpack_action_data() ); - return true; - } - return false; - } - - - /** - * This method will dynamically dispatch an incoming set of actions to - * - * ``` - * static Contract::on( ActionType ) - * ``` - * - * For this to work the Actions must be derived from eosio::contract - * - */ - template - bool dispatch( uint64_t code, uint64_t act ) { - if( code == FirstAction::get_account() && FirstAction::get_name() == act ) { - Contract().on( unpack_action_data() ); - return true; - } - return eosio::dispatch( code, act ); - } - - /** - * @defgroup dispatcher Dispatcher API - * @brief Defines functions to dispatch action to proper action handler inside a contract - * @ingroup contractdev - */ - - /** - * @defgroup dispatchercpp Dispatcher C++ API - * @brief Defines C++ functions to dispatch action to proper action handler inside a contract - * @ingroup dispatcher - * @{ - */ - - /** - * Unpack the received action and execute the correponding action handler - * - * @brief Unpack the received action and execute the correponding action handler - * @tparam T - The contract class that has the correponding action handler, this contract should be derived from eosio::contract - * @tparam Q - The namespace of the action handler function - * @tparam Args - The arguments that the action handler accepts, i.e. members of the action - * @param obj - The contract object that has the correponding action handler - * @param func - The action handler - * @return true - */ - template - bool execute_action( T* obj, void (Q::*func)(Args...) ) { - size_t size = action_data_size(); - - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - constexpr size_t max_stack_buffer_size = 512; - void* buffer = nullptr; - if( size > 0 ) { - buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); - read_action_data( buffer, size ); - } - - auto args = unpack...>>( (char*)buffer, size ); - - if ( max_stack_buffer_size < size ) { - free(buffer); - } - - auto f2 = [&]( auto... a ){ - (obj->*func)( a... ); - }; - - boost::mp11::tuple_apply( f2, args ); - return true; - } - /// @} dispatcher - -// Helper macro for EOSIO_API -#define EOSIO_API_CALL( r, OP, elem ) \ - case ::eosio::string_to_name( BOOST_PP_STRINGIZE(elem) ): \ - eosio::execute_action( &thiscontract, &OP::elem ); \ - break; - -// Helper macro for EOSIO_ABI -#define EOSIO_API( TYPE, MEMBERS ) \ - BOOST_PP_SEQ_FOR_EACH( EOSIO_API_CALL, TYPE, MEMBERS ) - -/** - * @addtogroup dispatcher - * @{ - */ - -/** - * Convenient macro to create contract apply handler - * To be able to use this macro, the contract needs to be derived from eosio::contract - * - * @brief Convenient macro to create contract apply handler - * @param TYPE - The class name of the contract - * @param MEMBERS - The sequence of available actions supported by this contract - * - * Example: - * @code - * EOSIO_ABI( eosio::bios, (setpriv)(setalimits)(setglimits)(setprods)(reqauth) ) - * @endcode - */ -#define EOSIO_ABI( TYPE, MEMBERS ) \ -extern "C" { \ - void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \ - auto self = receiver; \ - if( action == N(onerror)) { \ - /* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission */ \ - eosio_assert(code == N(eosio), "onerror action's are only valid from the \"eosio\" system account"); \ - } \ - if( code == self || action == N(onerror) ) { \ - TYPE thiscontract( self ); \ - switch( action ) { \ - EOSIO_API( TYPE, MEMBERS ) \ - } \ - /* does not allow destructor of thiscontract to run: eosio_exit(0); */ \ - } \ - } \ -} \ - /// @} dispatcher - - - /* - template - struct dispatcher { - dispatcher( account_name code ):_contract(code){} - - template - void dispatch( account_name action, FuncPtr ) { - } - - T contract; - }; - - void dispatch( account_name code, account_name action, - */ - -} diff --git a/contracts/eosiolib/eosio.hpp b/contracts/eosiolib/eosio.hpp deleted file mode 100644 index 2126abb3203..00000000000 --- a/contracts/eosiolib/eosio.hpp +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include -#include -#include -#include -#include -#include diff --git a/contracts/eosiolib/eosiolib.cpp b/contracts/eosiolib/eosiolib.cpp deleted file mode 100644 index 48d80b1037b..00000000000 --- a/contracts/eosiolib/eosiolib.cpp +++ /dev/null @@ -1,558 +0,0 @@ -#include "datastream.hpp" -#include "memory.hpp" -#include "privileged.hpp" - -void* sbrk(size_t num_bytes) { - constexpr uint32_t NBPPL2 = 16U; - constexpr uint32_t NBBP = 65536U; - - static bool initialized; - static uint32_t sbrk_bytes; - if(!initialized) { - sbrk_bytes = __builtin_wasm_current_memory() * NBBP; - initialized = true; - } - - if(num_bytes > INT32_MAX) - return reinterpret_cast(-1); - - //uint32_t num_bytes = (uint32_t)num_bytesI; - const uint32_t prev_num_bytes = sbrk_bytes; - const uint32_t current_pages = __builtin_wasm_current_memory(); - - // round the absolute value of num_bytes to an alignment boundary - num_bytes = (num_bytes + 7U) & ~7U; - - // update the number of bytes allocated, and compute the number of pages needed - const uint32_t num_desired_pages = (sbrk_bytes + num_bytes + NBBP - 1) >> NBPPL2; - - if(num_desired_pages > current_pages) { - //unfortuately clang4 doesn't provide the return code of grow_memory, that's why need - //to go back around and double check current_memory to make sure it has actually grown! - __builtin_wasm_grow_memory(num_desired_pages - current_pages); - if(num_desired_pages != __builtin_wasm_current_memory()) - return reinterpret_cast(-1); - } - - sbrk_bytes += num_bytes; - return reinterpret_cast(prev_num_bytes); -} - -namespace eosio { - - void set_blockchain_parameters(const eosio::blockchain_parameters& params) { - char buf[sizeof(eosio::blockchain_parameters)]; - eosio::datastream ds( buf, sizeof(buf) ); - ds << params; - set_blockchain_parameters_packed( buf, ds.tellp() ); - } - - void get_blockchain_parameters(eosio::blockchain_parameters& params) { - char buf[sizeof(eosio::blockchain_parameters)]; - size_t size = get_blockchain_parameters_packed( buf, sizeof(buf) ); - eosio_assert( size <= sizeof(buf), "buffer is too small" ); - eosio::datastream ds( buf, size_t(size) ); - ds >> params; - } - - using ::memset; - using ::memcpy; - - - - class memory_manager // NOTE: Should never allocate another instance of memory_manager - { - friend void* ::malloc(size_t size); - friend void* ::calloc(size_t count, size_t size); - friend void* ::realloc(void* ptr, size_t size); - friend void ::free(void* ptr); - public: - memory_manager() - // NOTE: it appears that WASM has an issue with initialization lists if the object is globally allocated, - // and seems to just initialize members to 0 - : _heaps_actual_size(0) - , _active_heap(0) - , _active_free_heap(0) - { - } - - private: - class memory; - - memory* next_active_heap() - { - constexpr uint32_t wasm_page_size = 64*1024; - memory* const current_memory = _available_heaps + _active_heap; - - const uint32_t current_memory_size = reinterpret_cast(sbrk(0)); - if(static_cast(current_memory_size) < 0) - return nullptr; - - //grab up to the end of the current WASM memory page provided that it has 1KiB remaining, otherwise - // grow to end of next page - uint32_t heap_adj; - if(current_memory_size % wasm_page_size <= wasm_page_size-1024) - heap_adj = (current_memory_size + wasm_page_size) - (current_memory_size % wasm_page_size) - current_memory_size; - else - heap_adj = (current_memory_size + wasm_page_size*2) - (current_memory_size % (wasm_page_size*2)) - current_memory_size; - char* new_memory_start = reinterpret_cast(sbrk(heap_adj)); - if(reinterpret_cast(new_memory_start) == -1) { - // ensure that any remaining unallocated memory gets cleaned up - current_memory->cleanup_remaining(); - ++_active_heap; - _heaps_actual_size = _active_heap; - return nullptr; - } - - // if we can expand the current memory, keep working with it - if (current_memory->expand_memory(new_memory_start, heap_adj)) - return current_memory; - - // ensure that any remaining unallocated memory gets cleaned up - current_memory->cleanup_remaining(); - - ++_active_heap; - memory* const next = _available_heaps + _active_heap; - next->init(new_memory_start, heap_adj); - - return next; - } - - void* malloc(uint32_t size) - { - if (size == 0) - return nullptr; - - // see Note on ctor - if (_heaps_actual_size == 0) - _heaps_actual_size = _heaps_size; - - adjust_to_mem_block(size); - - // first pass of loop never has to initialize the slot in _available_heap - char* buffer = nullptr; - memory* current = nullptr; - // need to make sure - if (_active_heap < _heaps_actual_size) - { - memory* const start_heap = &_available_heaps[_active_heap]; - // only heap 0 won't be initialized already - if(_active_heap == 0 && !start_heap->is_init()) - { - start_heap->init(_initial_heap, _initial_heap_size); - } - - current = start_heap; - } - - while (current != nullptr) - { - buffer = current->malloc(size); - // done if we have a buffer - if (buffer != nullptr) - break; - - current = next_active_heap(); - } - - if (buffer == nullptr) - { - const uint32_t end_free_heap = _active_free_heap; - - do - { - buffer = _available_heaps[_active_free_heap].malloc_from_freed(size); - - if (buffer != nullptr) - break; - - if (++_active_free_heap == _heaps_actual_size) - _active_free_heap = 0; - - } while (_active_free_heap != end_free_heap); - } - - return buffer; - } - - void* realloc(void* ptr, uint32_t size) - { - if (size == 0) - { - free(ptr); - return nullptr; - } - - adjust_to_mem_block(size); - - char* realloc_ptr = nullptr; - uint32_t orig_ptr_size = 0; - if (ptr != nullptr) - { - char* const char_ptr = static_cast(ptr); - for (memory* realloc_heap = _available_heaps; realloc_heap < _available_heaps + _heaps_actual_size && realloc_heap->is_init(); ++realloc_heap) - { - if (realloc_heap->is_in_heap(char_ptr)) - { - realloc_ptr = realloc_heap->realloc_in_place(char_ptr, size, &orig_ptr_size); - - if (realloc_ptr != nullptr) - return realloc_ptr; - else - break; - } - } - } - - char* new_alloc = static_cast(malloc(size)); - if (new_alloc == nullptr) - return nullptr; - - const uint32_t copy_size = (size < orig_ptr_size) ? size : orig_ptr_size; - if (copy_size > 0) - { - memcpy(new_alloc, ptr, copy_size); - free (ptr); - } - - return new_alloc; - } - - void free(void* ptr) - { - if (ptr == nullptr) - return; - - char* const char_ptr = static_cast(ptr); - for (memory* free_heap = _available_heaps; free_heap < _available_heaps + _heaps_actual_size && free_heap->is_init(); ++free_heap) - { - if (free_heap->is_in_heap(char_ptr)) - { - free_heap->free(char_ptr); - break; - } - } - } - - void adjust_to_mem_block(uint32_t& size) - { - const uint32_t remainder = (size + _size_marker) & _rem_mem_block_mask; - if (remainder > 0) - { - size += _mem_block - remainder; - } - } - - class memory - { - public: - memory() - : _heap_size(0) - , _heap(nullptr) - , _offset(0) - { - } - - void init(char* const mem_heap, uint32_t size) - { - _heap_size = size; - _heap = mem_heap; - } - - uint32_t is_init() const - { - return _heap != nullptr; - } - - uint32_t is_in_heap(const char* const ptr) const - { - const char* const end_of_buffer = _heap + _heap_size; - const char* const first_ptr_of_buffer = _heap + _size_marker; - return ptr >= first_ptr_of_buffer && ptr < end_of_buffer; - } - - uint32_t is_capacity_remaining() const - { - return _offset + _size_marker < _heap_size; - } - - char* malloc(uint32_t size) - { - uint32_t used_up_size = _offset + size + _size_marker; - if (used_up_size > _heap_size) - { - return nullptr; - } - - buffer_ptr new_buff(&_heap[_offset + _size_marker], size, _heap + _heap_size); - _offset += size + _size_marker; - new_buff.mark_alloc(); - return new_buff.ptr(); - } - - char* malloc_from_freed(uint32_t size) - { - eosio_assert(_offset == _heap_size, "malloc_from_freed was designed to only be called after _heap was completely allocated"); - - char* current = _heap + _size_marker; - while (current != nullptr) - { - buffer_ptr current_buffer(current, _heap + _heap_size); - if (!current_buffer.is_alloc()) - { - // done if we have enough contiguous memory - if (current_buffer.merge_contiguous(size)) - { - current_buffer.mark_alloc(); - return current; - } - } - - current = current_buffer.next_ptr(); - } - - // failed to find any free memory - return nullptr; - } - - char* realloc_in_place(char* const ptr, uint32_t size, uint32_t* orig_ptr_size) - { - const char* const end_of_buffer = _heap + _heap_size; - - buffer_ptr orig_buffer(ptr, end_of_buffer); - *orig_ptr_size = orig_buffer.size(); - // is the passed in pointer valid - char* const orig_buffer_end = orig_buffer.end(); - if (orig_buffer_end > end_of_buffer) - { - *orig_ptr_size = 0; - return nullptr; - } - - if (ptr > end_of_buffer - size) - { - // cannot resize in place - return nullptr; - } - - if( *orig_ptr_size > size ) - { - // use a buffer_ptr to allocate the memory to free - char* const new_ptr = ptr + size + _size_marker; - buffer_ptr excess_to_free(new_ptr, *orig_ptr_size - size, _heap + _heap_size); - excess_to_free.mark_free(); - - return ptr; - } - // if ptr was the last allocated buffer, we can expand - else if (orig_buffer_end == &_heap[_offset]) - { - orig_buffer.size(size); - _offset += size - *orig_ptr_size; - - return ptr; - } - if (size == *orig_ptr_size ) - return ptr; - - if (!orig_buffer.merge_contiguous_if_available(size)) - // could not resize in place - return nullptr; - - orig_buffer.mark_alloc(); - return ptr; - } - - void free(char* ptr) - { - buffer_ptr to_free(ptr, _heap + _heap_size); - to_free.mark_free(); - } - - void cleanup_remaining() - { - if (_offset == _heap_size) - return; - - // take the remaining memory and act like it was allocated - const uint32_t size = _heap_size - _offset - _size_marker; - buffer_ptr new_buff(&_heap[_offset + _size_marker], size, _heap + _heap_size); - _offset = _heap_size; - new_buff.mark_free(); - } - - bool expand_memory(char* exp_mem, uint32_t size) - { - if (_heap + _heap_size != exp_mem) - return false; - - _heap_size += size; - - return true; - } - - private: - class buffer_ptr - { - public: - buffer_ptr(void* ptr, const char* const heap_end) - : _ptr(static_cast(ptr)) - , _size(*reinterpret_cast(static_cast(ptr) - _size_marker) & ~_alloc_memory_mask) - , _heap_end(heap_end) - { - } - - buffer_ptr(void* ptr, uint32_t buff_size, const char* const heap_end) - : _ptr(static_cast(ptr)) - , _heap_end(heap_end) - { - size(buff_size); - } - - uint32_t size() const - { - return _size; - } - - char* next_ptr() const - { - char* const next = end() + _size_marker; - if (next >= _heap_end) - return nullptr; - - return next; - } - - void size(uint32_t val) - { - // keep the same state (allocated or free) as was set before - const uint32_t memory_state = *reinterpret_cast(_ptr - _size_marker) & _alloc_memory_mask; - *reinterpret_cast(_ptr - _size_marker) = val | memory_state; - _size = val; - } - - char* end() const - { - return _ptr + _size; - } - - char* ptr() const - { - return _ptr; - } - - void mark_alloc() - { - *reinterpret_cast(_ptr - _size_marker) |= _alloc_memory_mask; - } - - void mark_free() - { - *reinterpret_cast(_ptr - _size_marker) &= ~_alloc_memory_mask; - } - - bool is_alloc() const - { - return *reinterpret_cast(_ptr - _size_marker) & _alloc_memory_mask; - } - - bool merge_contiguous_if_available(uint32_t needed_size) - { - return merge_contiguous(needed_size, true); - } - - bool merge_contiguous(uint32_t needed_size) - { - return merge_contiguous(needed_size, false); - } - private: - bool merge_contiguous(uint32_t needed_size, bool all_or_nothing) - { - // do not bother if there isn't contiguious space to allocate - if( all_or_nothing && uint32_t(_heap_end - _ptr) < needed_size ) - return false; - - uint32_t possible_size = _size; - while (possible_size < needed_size && (_ptr + possible_size < _heap_end)) - { - const uint32_t next_mem_flag_size = *reinterpret_cast(_ptr + possible_size); - // if ALLOCed then done with contiguous free memory - if (next_mem_flag_size & _alloc_memory_mask) - break; - - possible_size += (next_mem_flag_size & ~_alloc_memory_mask) + _size_marker; - } - - if (all_or_nothing && possible_size < needed_size) - return false; - - // combine - const uint32_t new_size = possible_size < needed_size ? possible_size : needed_size; - size(new_size); - - if (possible_size > needed_size) - { - const uint32_t freed_size = possible_size - needed_size - _size_marker; - buffer_ptr freed_remainder(_ptr + needed_size + _size_marker, freed_size, _heap_end); - freed_remainder.mark_free(); - } - - return new_size == needed_size; - } - - char* _ptr; - uint32_t _size; - const char* const _heap_end; - }; - - uint32_t _heap_size; - char* _heap; - uint32_t _offset; - }; - - static const uint32_t _size_marker = sizeof(uint32_t); - // allocate memory in 8 char blocks - static const uint32_t _mem_block = 8; - static const uint32_t _rem_mem_block_mask = _mem_block - 1; - static const uint32_t _initial_heap_size = 8192;//32768; - // if sbrk is not called outside of this file, then this is the max times we can call it - static const uint32_t _heaps_size = 16; - char _initial_heap[_initial_heap_size]; - memory _available_heaps[_heaps_size]; - uint32_t _heaps_actual_size; - uint32_t _active_heap; - uint32_t _active_free_heap; - static const uint32_t _alloc_memory_mask = uint32_t(1) << 31; - }; - - memory_manager memory_heap; - -} /// namespace eosio - -extern "C" { - -void* __dso_handle = 0; - -void* malloc(size_t size) -{ - return eosio::memory_heap.malloc(size); -} - -void* calloc(size_t count, size_t size) -{ - void* ptr = eosio::memory_heap.malloc(count*size); - memset(ptr, 0, count*size); - return ptr; -} - -void* realloc(void* ptr, size_t size) -{ - return eosio::memory_heap.realloc(ptr, size); -} - -void free(void* ptr) -{ - return eosio::memory_heap.free(ptr); -} - -} diff --git a/contracts/eosiolib/fixed_key.hpp b/contracts/eosiolib/fixed_key.hpp deleted file mode 100644 index 4e8cd8241da..00000000000 --- a/contracts/eosiolib/fixed_key.hpp +++ /dev/null @@ -1,291 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include -#include - -#include - -namespace eosio { - - template - class fixed_key; - - template - bool operator==(const fixed_key &c1, const fixed_key &c2); - - template - bool operator!=(const fixed_key &c1, const fixed_key &c2); - - template - bool operator>(const fixed_key &c1, const fixed_key &c2); - - template - bool operator<(const fixed_key &c1, const fixed_key &c2); - - /** - * @defgroup fixed_key Fixed Size Key - * @brief Fixed size key sorted lexicographically for Multi Index Table - * @ingroup types - * @{ - */ - - /** - * Fixed size key sorted lexicographically for Multi Index Table - * - * @brief Fixed size key sorted lexicographically for Multi Index Table - * @tparam Size - Size of the fixed_key object - * @ingroup types - */ - template - class fixed_key { - private: - - template struct bool_pack; - template - using all_true = std::is_same< bool_pack, bool_pack >; - - template - static void set_from_word_sequence(const std::array& arr, fixed_key& key) - { - auto itr = key._data.begin(); - word_t temp_word = 0; - const size_t sub_word_shift = 8 * sizeof(Word); - const size_t num_sub_words = sizeof(word_t) / sizeof(Word); - auto sub_words_left = num_sub_words; - for( auto&& w : arr ) { - if( sub_words_left > 1 ) { - temp_word |= static_cast(w); - temp_word <<= sub_word_shift; - --sub_words_left; - continue; - } - - eosio_assert( sub_words_left == 1, "unexpected error in fixed_key constructor" ); - temp_word |= static_cast(w); - sub_words_left = num_sub_words; - - *itr = temp_word; - temp_word = 0; - ++itr; - } - if( sub_words_left != num_sub_words ) { - if( sub_words_left > 1 ) - temp_word <<= 8 * (sub_words_left-1); - *itr = temp_word; - } - } - - public: - - typedef uint128_t word_t; - - /** - * Get number of words contained in this fixed_key object. A word is defined to be 16 bytes in size - * - * @brief Get number of words contained in this fixed_key object - */ - - static constexpr size_t num_words() { return (Size + sizeof(word_t) - 1) / sizeof(word_t); } - - /** - * Get number of padded bytes contained in this fixed_key object. Padded bytes are the remaining bytes - * inside the fixed_key object after all the words are allocated - * - * @brief Get number of padded bytes contained in this fixed_key object - */ - static constexpr size_t padded_bytes() { return num_words() * sizeof(word_t) - Size; } - - /** - * @brief Default constructor to fixed_key object - * - * @details Default constructor to fixed_key object which initializes all bytes to zero - */ - constexpr fixed_key() : _data() {} - - /** - * @brief Constructor to fixed_key object from std::array of num_words() words - * - * @details Constructor to fixed_key object from std::array of num_words() words - * @param arr data - */ - fixed_key(const std::array& arr) - { - std::copy(arr.begin(), arr.end(), _data.begin()); - } - - /** - * @brief Constructor to fixed_key object from std::array of num_words() words - * - * @details Constructor to fixed_key object from std::array of num_words() words - * @param arr - Source data - */ - template::value && - !std::is_same::value && - sizeof(Word) < sizeof(word_t)>::type > - fixed_key(const std::array& arr) - { - static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(Word)) * sizeof(Word), - "size of the backing word size is not divisible by the size of the array element" ); - static_assert( sizeof(Word) * NumWords <= Size, "too many words supplied to fixed_key constructor" ); - - set_from_word_sequence(arr, *this); - } - - /** - * @brief Create a new fixed_key object from a sequence of words - * - * @details Create a new fixed_key object from a sequence of words - * @tparam FirstWord - The type of the first word in the sequence - * @tparam Rest - THe type of the remaining words in the sequence - * @param first_word - The first word in the sequence - * @param rest - The remaining words in the sequence - */ - template - static - fixed_key - make_from_word_sequence(typename std::enable_if::value && - !std::is_same::value && - sizeof(FirstWord) <= sizeof(word_t) && - all_true<(std::is_same::value)...>::value, - FirstWord>::type first_word, - Rest... rest) - { - static_assert( sizeof(word_t) == (sizeof(word_t)/sizeof(FirstWord)) * sizeof(FirstWord), - "size of the backing word size is not divisible by the size of the words supplied as arguments" ); - static_assert( sizeof(FirstWord) * (1 + sizeof...(Rest)) <= Size, "too many words supplied to make_from_word_sequence" ); - - fixed_key key; - set_from_word_sequence(std::array{{ first_word, rest... }}, key); - return key; - } - - /** - * Get the contained std::array - * @brief Get the contained std::array - */ - const auto& get_array()const { return _data; } - - /** - * Get the underlying data of the contained std::array - * @brief Get the underlying data of the contained std::array - */ - auto data() { return _data.data(); } - - /** - * Get the underlying data of the contained std::array - * @brief Get the underlying data of the contained std::array - */ - auto data()const { return _data.data(); } - - /** - * Get the size of the contained std::array - * @brief Get the size of the contained std::array - */ - auto size()const { return _data.size(); } - - - /** - * Extract the contained data as an array of bytes - * @brief Extract the contained data as an array of bytes - * @return - the extracted data as array of bytes - */ - std::array extract_as_byte_array()const { - std::array arr; - - const size_t num_sub_words = sizeof(word_t); - - auto arr_itr = arr.begin(); - auto data_itr = _data.begin(); - - for( size_t counter = _data.size(); counter > 0; --counter, ++data_itr ) { - size_t sub_words_left = num_sub_words; - - if( counter == 1 ) { // If last word in _data array... - sub_words_left -= padded_bytes(); - } - auto temp_word = *data_itr; - for( ; sub_words_left > 0; --sub_words_left ) { - *(arr_itr + sub_words_left - 1) = static_cast(temp_word & 0xFF); - temp_word >>= 8; - } - arr_itr += num_sub_words; - } - - return arr; - } - - // Comparison operators - friend bool operator== <>(const fixed_key &c1, const fixed_key &c2); - - friend bool operator!= <>(const fixed_key &c1, const fixed_key &c2); - - friend bool operator> <>(const fixed_key &c1, const fixed_key &c2); - - friend bool operator< <>(const fixed_key &c1, const fixed_key &c2); - - private: - - std::array _data; - }; - - /** - * @brief Compares two fixed_key variables c1 and c2 - * - * @details Lexicographically compares two fixed_key variables c1 and c2 - * @param c1 - First fixed_key object to compare - * @param c2 - Second fixed_key object to compare - * @return if c1 == c2, return true, otherwise false - */ - template - bool operator==(const fixed_key &c1, const fixed_key &c2) { - return c1._data == c2._data; - } - - /** - * @brief Compares two fixed_key variables c1 and c2 - * - * @details Lexicographically compares two fixed_key variables c1 and c2 - * @param c1 - First fixed_key object to compare - * @param c2 - Second fixed_key object to compare - * @return if c1 != c2, return true, otherwise false - */ - template - bool operator!=(const fixed_key &c1, const fixed_key &c2) { - return c1._data != c2._data; - } - - /** - * @brief Compares two fixed_key variables c1 and c2 - * - * @details Lexicographically compares two fixed_key variables c1 and c2 - * @param c1 - First fixed_key object to compare - * @param c2 - Second fixed_key object to compare - * @return if c1 > c2, return true, otherwise false - */ - template - bool operator>(const fixed_key& c1, const fixed_key& c2) { - return c1._data > c2._data; - } - - /** - * @brief Compares two fixed_key variables c1 and c2 - * - * @details Lexicographically compares two fixed_key variables c1 and c2 - * @param c1 - First fixed_key object to compare - * @param c2 - Second fixed_key object to compare - * @return if c1 < c2, return true, otherwise false - */ - template - bool operator<(const fixed_key &c1, const fixed_key &c2) { - return c1._data < c2._data; - } - /// @} fixed_key - - typedef fixed_key<32> key256; -} diff --git a/contracts/eosiolib/fixedpoint.hpp b/contracts/eosiolib/fixedpoint.hpp deleted file mode 100644 index 8c36f5ea54b..00000000000 --- a/contracts/eosiolib/fixedpoint.hpp +++ /dev/null @@ -1,922 +0,0 @@ -#pragma once -#include -#include - -namespace eosio -{ - /** - * @defgroup fixedpoint Fixed Point - * @ingroup mathcppapi - * @brief 32,64,128,256 bits version of fixed point variables - * - * Floating point operations are indeterministic, hence is prevented in smart contract. - * The smart contract developers should use the appropriate Fixed_Point template class - * by passing the number to be represented in integer format and the number of decimals - * required. - * These template classes also support the arithmetic operations and basic comparison operators - * @{ - */ - - // Some forward declarations - template struct fixed_point32; - template struct fixed_point64; - template struct fixed_point128; - - // Will support fixed_point256 in next release -#if 0 - template struct fixed_point256; - /** - * @defgroup Template class for Fixed Point 256 bits representaton - * @ingroup contractdev - * @brief Template param Q is the Q factor i.e. number of decimals - * - */ - template - struct fixed_point256 - { - int128_t val; - fixed_point256(int256_t v=0) : val(v) {} - template fixed_point256(const fixed_point256 &r); - template fixed_point256(const fixed_point128 &r); - template fixed_point256(const fixed_point64 &r); - template fixed_point256(const fixed_point32 &r); - /** - * Get the integer part of the 64 bit fixed number - * @brief To get the integer part of the fixed number - * @return Returns integer part of the fixed number - * - * Example: - * @code - * fixed64<18> a(1234.455667) - * std::cout << a.int_part(); // Output: 1234 - * @endcode - */ - int128_t int_part() const { - return val >> q; - } - - /** - * Get the decimal part of the 64 bit fixed number - * @brief To get the decimal part of the fixed number - * @return Returns decimal part of the fixed number - * - * Example: - * @code - * fixed64<18> a(1234.455667) - * std::cout << a.decimal_part(); // Output: 45567 - * @endcode - */ - uint128_t frac_part() const { - if(!Q) return 0; - return val << (32-Q); - } - - - - template fixed_point256 &operator=(const fixed_point32 &r); - template fixed_point256 &operator=(const fixed_point64 &r); - template fixed_point256 &operator=(const fixed_point128 &r); - template fixed_point256 &operator=(const fixed_point256 &r); - // Comparison functions - template bool operator==(const fixed_point256 &r) { return (val == r.val);} - template bool operator>(const fixed_point256 &r) { return (val > r.val);} - template bool operator<(const fixed_point256 &r) { return (val < r.val);} - }; -#endif - - /** - * The template param Q represents the Q Factor i.e number of decimals - * - * @brief 128 bits representation of Fixed Point class. - * - * Example: - * @code - * fixed_point128<6> a(123232.455667233) - * fixed_point128<0> a(123424) - * fixed_point128<18> c = a*b; - * fixed_point128<24> d = a+b+c; - * fixed_point128<24> e = b/a; - * @endcode - */ - template - struct fixed_point128 - { - static_assert(Q < 128, "Maximum number of decimals supported in fixed_point128 is 128 decimals"); - - /** - * @brief Value of the fixed point represented as int128_t - * - * Value of the fixed point represented as int128_t - */ - int128_t val; - - /** - * Various constructors for fixed_point128. Can create fixed_point128 instance from an int128_t, fixed_point128,64,32 instance - * - * @brief Various constructors for fixed_point128 - * - * Example: - * @code - * fixed_point64<18> a(1234.455667); - * fixed_point128<3> b(a); - * fixed_point32<6> b(13324.32323); - * fixed_point128<5> c(a); - * @endcode - */ - - /** - * Construct a new fixed point128 object from int128_t - * - * @brief Construct a new fixed point128 object - * @param v - int128_t representation of the fixed point value - */ - fixed_point128(int128_t v=0) : val(v) {} - - /** - * Construct a new fixed point128 object from another fixed_point128 - * - * @brief Construct a new fixed point128 object from another fixed_point128 - * @param r - Another fixed_point128 as source - */ - template fixed_point128(const fixed_point128 &r); - - /** - * Construct a new fixed point128 object from another fixed_point64 - * - * @brief Construct a new fixed point128 object from another fixed_point64 - * @param r -fixed_point64 as source - */ - template fixed_point128(const fixed_point64 &r); - - /** - * Construct a new fixed point128 object from another fixed_point32 - * - * @brief Construct a new fixed point128 object from another fixed_point32 - * @param r -fixed_point32 as source - */ - template fixed_point128(const fixed_point32 &r); - - /** - * Get the integer part of the 64 bit fixed number - * - * @brief To get the integer part of the fixed number - * @return Returns integer part of the fixed number - * - * Example: - * @code - * fixed_point64<5> a(1234.455667) - * std::cout << a.int_part(); // Output: 1234 - * @endcode - */ - int128_t int_part() const { - return val >> Q; - } - - /** - * Get the decimal part of the 64 bit fixed number - * - * @brief To get the decimal part of the fixed number - * @return Returns decimal part of the fixed number - * - * Example: - * @code - * fixed_point128<3> a(1234.455667) - * std::cout << a.decimal_part(); // Output: 455 - * @endcode - */ - uint128_t frac_part() const { - if(!Q) return 0; - return uint128_t(val << (32-Q)); - } - - /** - * Prints the fixed point value - * - * @brief Prints the fixed point value - */ - void print() const { - uint128_t ip((uint128_t)int_part()); - uint128_t fp(frac_part()); - printui128(&ip); - prints("."); - printui128(&fp); - } - - // Various assignment operators - /** - * Assignment operator. Assign fixed_point32 to fixed_point128 - * - * @brief Assignment operator - * @tparam qr - Precision of the source - * @param r - Source - * @return fixed_point128& - Reference to this object - */ - template fixed_point128 &operator=(const fixed_point32 &r); - /** - * Assignment operator. Assign fixed_point32 to fixed_point64 - * - * @brief Assignment operator - * @tparam qr - Precision of the source - * @param r - Source - * @return fixed_point128& - Reference to this object - */ - template fixed_point128 &operator=(const fixed_point64 &r); - /** - * Assignment operator. Assign fixed_point32 to fixed_point32 - * - * @brief Assignment operator - * @tparam qr - Precision of the source - * @param r - Source - * @return fixed_point128& - Reference to this object - */ - template fixed_point128 &operator=(const fixed_point128 &r); - - // Comparison functions - /** - * Equality operator - * - * @brief Equality operator - * @tparam qr - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator==(const fixed_point128 &r) { return (val == r.val);} - - /** - * Greater than operator - * - * @brief Greater than operator - * @tparam qr - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator>(const fixed_point128 &r) { return (val > r.val);} - - /** - * Less than operator - * - * @brief Less than operator - * @tparam qr - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator<(const fixed_point128 &r) { return (val < r.val);} - }; - - - /** - * @brief 64 bits representation of Fixed Point class. - * - * Example: - * @code - * fixed_point64<6> a(123232.455667233) - * fixed_point64<0> a(123424) - * fixed_point64<18> c = a*b; - * fixed_point64<24> d = a+b+c; - * fixed_point64<24> e = b/a; - * @endcode - */ - template - struct fixed_point64 - { - static_assert(Q < 128, "Maximum number of decimals supported in fixed_point64 is 128 decimals"); - - /** - * @brief Value of the fixed point represented as int64_t - * - * Value of the fixed point represented as int64_t - */ - int64_t val; - - /** - * Construct a new fixed point64 object from int64_t - * - * @brief Construct a new fixed point64 object - * @param v - int64_t representation of the fixed point value - */ - fixed_point64(int64_t v=0) : val(v) {} - - /** - * Construct a new fixed point64 object from another fixed_point64 - * - * @brief Construct a new fixed point64 object from another fixed_point64 - * @param r - Another fixed_point64 as source - */ - template fixed_point64(const fixed_point64 &r); - - /** - * Construct a new fixed point64 object from another fixed_point32 - * - * @brief Construct a new fixed point64 object from another fixed_point32 - * @param r - fixed_point64 as source - */ - template fixed_point64(const fixed_point32 &r); - - /** - * Get the integer part of the 64 bit fixed number - * @brief To get the integer part of the fixed number - * @return Returns integer part of the fixed number - * - * Example: - * @code - * fixed_point64<18> a(1234.455667) - * std::cout << a.int_part(); // Output: 1234 - * @endcode - */ - int64_t int_part() const { - return val >> Q; - } - - /** - * Get the decimal part of the 64 bit fixed number - * @brief To get the decimal part of the fixed number - * @return Returns decimal part of the fixed number - * - * Example: - * @code - * fixed64<3> a(1234.455667) - * std::cout << a.decimal_part(); // Output: 455 - * @endcode - */ - uint64_t frac_part() const { - if(!Q) return 0; - return uint64_t(val << (32-Q)); - } - - /** - * Prints the fixed point value - * - * @brief Prints the fixed point value - */ - void print() const { - printi(int_part()); - prints("."); - printi128(frac_part()); - } - - // Various assignment operators - /** - * Assignment operator. Assign fixed_point32 to fixed_point64 - * - * @brief Assignment operator - * @tparam QR - Precision of the source - * @param r - Source - * @return fixed_point64& - Reference to this object - */ - template fixed_point64 &operator=(const fixed_point32 &r); - - /** - * Assignment operator. Assign fixed_point64 to fixed_point64 - * - * @brief Assignment operator - * @tparam QR - Precision of the source - * @param r - Source - * @return fixed_point64& - Reference to this object - */ - template fixed_point64 &operator=(const fixed_point64 &r); - - // Arithmetic operations - /** - * Addition operator - * - * @brief Addition operator - * @tparam QR - Precision of the second addend - * @param r - Second addend - * @return - The result of addition - */ - template fixed_point64< (Q>QR)?Q:QR > operator+(const fixed_point64 &r) const; - - /** - * Subtraction operator - * - * @brief Subtraction operator - * @tparam QR - Precision of the minuend - * @param r - Minuend - * @return - The result of subtraction - */ - template fixed_point64< (Q>QR)?Q:QR > operator-(const fixed_point64 &r) const; - - // product and division of two fixed_point64 instances will be fixed_point128 - // The total number of decimals will be the max - /** - * Multiplication operator - * - * @brief Multiplication operator - * @tparam QR - Precision of the multiplier - * @param r - Multiplier - * @return - The result of multiplication - */ - template fixed_point128 operator*(const fixed_point64 &r) const; - - /** - * Division operator - * - * @brief Division operator - * @tparam QR - Precision of the divisor - * @param r - Divisor - * @return - The result of division - */ - template fixed_point128 operator/(const fixed_point64 &r) const; - - // Comparison functions - /** - * Equality operator - * - * @brief Equality operator - * @tparam QR - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator==(const fixed_point64 &r) { return (val == r.val);} - - /** - * Greater than operator - * - * @brief Greater than operator - * @tparam QR - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator>(const fixed_point64 &r) { return (val > r.val);} - - /** - * Less than operator - * - * @brief Less than operator - * @tparam QR - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator<(const fixed_point64 &r) { return (val < r.val);} - }; - - /** - * @brief 32 bits representation of Fixed Point class. - * - * This class is implemented to to replace the floating point variables - * It can resolve floating point undetermenistic related issues - * - * Example: - * @code - * - * fixed_point32<17> b(9.654); - * fixed_point32<18> c = a*b; - * fixed_point32<24> d = a+b+c; - * fixed_point32<24> e = b/a; - * @endcode - * - */ - // fixed_point 32 bit version. The template param 'q' is the scale factor - template - struct fixed_point32 - { - static_assert(Q < 128, "Maximum number of decimals supported in fixed_point32 is 128 decimals"); - - /** - * @brief Value of the fixed point represented as int32_t - * - * Value of the fixed point represented as int32_t - */ - int32_t val; - - /** - * Construct a new fixed point32 object from another fixed_point32 - * - * @brief Construct a new fixed point32 object from another fixed_point32 - * @param r - Another fixed_point32 as source - */ - template fixed_point32(const fixed_point32 &r); - - /** - * Construct a new fixed point32 object from another fixed_point64. It will be truncated. - * - * @brief Construct a new fixed point32 object from another fixed_point64 - * @param r - Another fixed_point32 as source - */ - template fixed_point32(const fixed_point64 &r); - - - /** - * Construct a new fixed point32 object from int32_t - * - * @brief Construct a new fixed point32 object - * @param param - int32_t representation of the fixed point value - */ - fixed_point32(int32_t param=0) : val(param) {} - - // translates given double variable to the int32 based on the scale factor - // fixed_point32(double d=0) : val(d * (1< a(1234.455667) - * std::cout << a.int_part(); // Output: 1234 - * @endcode - */ - int32_t int_part() const { - return val >> Q; - } - uint32_t frac_part() const { - if(!Q) return 0; - return uint32_t(val << (32-Q)); - } - - /** - * Prints the fixed point value - * - * @brief Prints the fixed point value - */ - void print() const { - printi(int_part()); - prints("."); - printi128(frac_part()); - } - - // Various assignment operators - /** - * Assignment operator. Assign fixed_point32 to fixed_point32 - * - * @brief Assignment operator - * @tparam QR - Precision of the source - * @param r - Source - * @return fixed_point32& - Reference to this object - */ - template fixed_point32 &operator=(const fixed_point32 &r); - - /** - * Assignment operator. Assign fixed_point64 to fixed_point32 - * - * @brief Assignment operator - * @tparam QR - Precision of the source - * @param r - Source - * @return fixed_point32& - Reference to this object - */ - template fixed_point32 &operator=(const fixed_point64 &r); - - /** - * Addition operator - * - * @brief Addition operator - * @tparam QR - Precision of the second addend - * @param r - Second addend - * @return - The result of addition - */ - template fixed_point32< (Q>QR)?Q:QR > operator+(const fixed_point32 &r) const; - - /** - * Subtraction operator - * - * @brief Subtraction operator - * @tparam QR - Precision of the minuend - * @param r - Minuend - * @return - The result of subtraction - */ - template fixed_point32< (Q>QR)?Q:QR > operator-(const fixed_point32 &r) const; - - // productd of to fixed_point32 instances will be fixed_point64 - /** - * Multiplication operator - * - * @brief Multiplication operator - * @tparam QR - Precision of the multiplier - * @param r - Multiplier - * @return - The result of multiplication - */ - template fixed_point64 operator*(const fixed_point32 &r) const; - - /** - * Division operator - * - * @brief Division operator - * @tparam QR - Precision of the divisor - * @param r - Divisor - * @return - The result of division - */ - template fixed_point64 operator/(const fixed_point32 &r) const; - - // Comparison functions - /** - * Equality operator - * - * @brief Equality operator - * @tparam QR - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator==(const fixed_point32 &r) { return (val == r.val);} - - /** - * Greater than operator - * - * @brief Greater than operator - * @tparam QR - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator>(const fixed_point32 &r) { return (val > r.val);} - - /** - * Less than operator - * - * @brief Less than operator - * @tparam QR - Precision of the source - * @param r - Source - * @return true - if equal - * @return false - otherwise - */ - template bool operator<(const fixed_point32 &r) { return (val < r.val);} - }; - - - /// @} fixedpoint - - // Helper functions - template - T assignHelper(T rhs_val, uint8_t q, uint8_t qr) - { - T result = (q > qr) ? rhs_val << (q-qr) : rhs_val >> (qr-q); - return result; - } - - -#if 0 - // fixed_point256 methods - template template - fixed_point256::fixed_point256(const fixed_point256 &r) { - val = assignHelper(r.val, q, qr); - } - - template template - fixed_point256::fixed_point256(const fixed_point128 &r) { - val = assignHelper(r.val, q, qr); - } - - template template - fixed_point256::fixed_point256(const fixed_point64 &r) { - val = assignHelper(r.val, q, qr); - } - - template template - fixed_point256::fixed_point256(const fixed_point32 &r) { - val = assignHelper(r.val, q, qr); - } -#endif - - // fixed_point128 methods - template template - fixed_point128::fixed_point128(const fixed_point128 &r) { - val = assignHelper(r.val, Q, QR); - } - - template template - fixed_point128::fixed_point128(const fixed_point64 &r) { - val = assignHelper(r.val, Q, QR); - } - - template template - fixed_point128::fixed_point128(const fixed_point32 &r) { - val = assignHelper(r.val, Q, QR); - } - - - // fixed_point64 methods - template template - fixed_point64::fixed_point64(const fixed_point64 &r) { - val = assignHelper(r.val, Q, QR); - } - - template template - fixed_point64::fixed_point64(const fixed_point32 &r) { - val = assignHelper(r.val, Q, QR); - } - - /** - * @brief Addition between two fixed_point64 variables and the result goes to fixed_point64 - * - * Addition between two fixed_point64 variables - * Number of decimal on result will be max of decimals of lhs and rhs - */ - template template - fixed_point64< (Q>QR)?Q:QR > fixed_point64::operator+(const fixed_point64 &rhs) const - { - // if the scaling factor for both are same, no need to make any intermediate objects except the result - if(Q == QR) - { - return fixed_point64(val + rhs.val); - } - return fixed_point64<(Q>QR)?Q:QR>( - fixed_point64<(Q>QR)?Q:QR>( *this ).val + - fixed_point64<(Q>QR)?Q:QR>( rhs ).val - ); - } - - /** - * @brief Subtraction between two fixed_point64 variables and the result goes to fixed_point64 - * - * Subtraction between two fixed_point64 variables - * Number of decimal on result will be max of decimals of lhs and rhs - */ - template template - fixed_point64< (Q>QR)?Q:QR > fixed_point64::operator-(const fixed_point64 &rhs) const - { - // if the scaling factor for both are same, no need to make any intermediate objects except the result - if(Q == QR) - { - return fixed_point64(val - rhs.val); - } - return fixed_point64<(Q>QR)?Q:QR>( - fixed_point64<(Q>QR)?Q:QR>( *this ).val - - fixed_point64<(Q>QR)?Q:QR>( rhs ).val - ); - } - - /** - * @brief Multiplication operator for fixed_point64. The result goes to fixed_point64 - * - * Multiplication operator for fixed_point64. The result goes to fixed_point128 - * Number of decimal on result will be sum of number of decimals of lhs and rhs - * - * Example: - * @code - * fixed_point128<33> result = fixed_point64<0>(131313) / fixed_point64<0>(2323) - * @endcode - */ - template template - fixed_point128 fixed_point64::operator*(const fixed_point64 &r) const { - return fixed_point128(int128_t(val)*r.val); - } - - /** - * @brief Division of two fixed_point64 result will be stored in fixed_point128 - * - * Division operator for fixed_point64 - * - * Example: - * @code - * fixed_point128<33> result = fixed_point64<0>(131313) / fixed_point64<0>(2323) - * @endcode - */ - template template - fixed_point128 fixed_point64::operator/(const fixed_point64 &r) const { - // std::cout << "Performing division on " << val << ", with " << q << " precision / " << r.val << ", with " << qr << " precision. Result precision " << ((q>qr) ? q:qr) << std::endl; - // Convert val to 128 bit by additionally shifting 64 bit and take the result to 128bit - // Q(X+64-Y) = Q(X+64) / Q(Y) - eosio_assert( !(r.int_part() == 0 && r.frac_part() == 0), "divide by zero" ); - return fixed_point128((int128_t(val)<<64)/r.val); - } - - // fixed_point32 methods - template template - fixed_point32::fixed_point32(const fixed_point32 &r) { - val = assignHelper(r.val, Q, QR); - } - - template template - fixed_point32::fixed_point32(const fixed_point64 &r) { - val = assignHelper(r.val, Q, QR); - } - - template template - fixed_point32 &fixed_point32::operator=(const fixed_point32 &r) { - val = assignHelper(r.val, Q, QR); - } - - template template - fixed_point32 &fixed_point32::operator=(const fixed_point64 &r) { - val = assignHelper(r.val, Q, QR); - } - - /** - * @brief Addition between two fixed_point32 variables and the result goes to fixed_point32 - * - * Addition between two fixed_point32 variables - * Number of decimal on result will be max of decimals of lhs and rhs - * - */ - template template - fixed_point32< (Q>QR)?Q:QR > fixed_point32::operator+(const fixed_point32 &rhs) const - { - // if the scaling factor for both are same, no need to make any intermediate objects except the result - if(Q == QR) - { - return fixed_point32(val + rhs.val); - } - return fixed_point32<(Q>QR)?Q:QR>( - fixed_point32<(Q>QR)?Q:QR>( *this ).val + - fixed_point32<(Q>QR)?Q:QR>( rhs ).val - ); - } - - /** - * @brief Subtraction between two fixed_point32 variables and the result goes to fixed_point32 - * - * Subtraction between two fixed_point32 variables - * Number of decimal on result will be max of decimals of lhs and rhs - * - */ - template template - fixed_point32< (Q>QR)?Q:QR > fixed_point32::operator-(const fixed_point32 &rhs) const - { - // if the scaling factor for both are same, no need to make any intermediate objects except the result - if(Q == QR) - { - return fixed_point32(val - rhs.val); - } - return fixed_point32<(Q>QR)?Q:QR>( - fixed_point32<(Q>QR)?Q:QR>( *this ).val - - fixed_point32<(Q>QR)?Q:QR>( rhs ).val - ); - } - - /** - * @brief Multiplication operator for fixed_point32. The result goes to fixed_point64 - * - * Multiplication operator for fixed_point32. The result goes to fixed_point64 - * Number of decimal on result will be sum of number of decimals of lhs and rhs - * - * Example: - * @code - * fixed_point64<33> result = fixed_point32<0>(131313) / fixed_point32<0>(2323) - * @endcode - */ - template template - fixed_point64 fixed_point32::operator*(const fixed_point32 &r) const { - return fixed_point64(int64_t(val)*r.val); - } - - /** - * @brief Division of two fixed_point32 result will be stored in fixed_point64 - * - * Division operator for fixed_point32 - * - * Example: - * @code - * fixed_point64<33> result = fixed_point32<0>(131313) / fixed_point32<0>(2323) - * @endcode - */ - template template - fixed_point64 fixed_point32::operator/(const fixed_point32 &r) const { - // Convert val into 64 bit and perform the division - // Q(X+32-Y) = Q(X+32) / Q(Y) - eosio_assert( !(r.int_part() == 0 && r.frac_part() == 0), "divide by zero" ); - return fixed_point64((int64_t(val)<<32)/r.val); - } - - /** - * @brief Wrapper function for dividing two unit64 variable and stores result in fixed_point64 - * - * Wrapper function for dividing two unit32 variable and stores result in fixed_point64 - * - * Example: - * @code - * fixed_point64<33> result = fixed_divide(131313, 2323) - * @endcode - */ - template - fixed_point64 fixed_divide(uint32_t lhs, uint32_t rhs) - { - - eosio_assert( rhs != 0, "divide by zero" ); - fixed_point64 result = fixed_point32<0>((int32_t)lhs) / fixed_point32<0>((int32_t)rhs); - return result; - } - - /** - * @brief Wrapper function for dividing two unit64 variable and stores result in fixed_point128 - * Wrapper function for dividing two unit64 variable and stores result in fixed_point128 - * - * Example: - * @code - * fixed_point128<33> result = fixed_divide(131313, 2323) - * @endcode - */ - - template - fixed_point128 fixed_divide(uint64_t lhs, uint64_t rhs) - { - - eosio_assert( rhs != 0, "divide by zero" ); - fixed_point128 result = fixed_point64<0>((int32_t)lhs) / fixed_point64<0>((int32_t)rhs); - return fixed_point128(result); - } - - -}; diff --git a/contracts/eosiolib/mainpage.md b/contracts/eosiolib/mainpage.md deleted file mode 100644 index e9c9d0cd8a6..00000000000 --- a/contracts/eosiolib/mainpage.md +++ /dev/null @@ -1,20 +0,0 @@ -Welcome to the EOS.IO Documentation ------------------------------------ - -@note This documentation is in progress and subject to change due to rapid development. Please report inaccuracies identified to the [EOS.IO Developer Telegram Group](https://t.me/joinchat/EaEnSUPktgfoI-XPfMYtcQ) - -## EOS.IO - - [Additional resources - Github Readme](https://github.com/EOSIO/eos#readme) - -## Smart Contract Developers -- @ref eosiorpc -- @ref contractdev - - @ref chainapi - Define API for querying internal chain state - - @ref database - APIs that store and retreive data on the blockchainEOS.IO organizes data according to the following broad structure - - @ref actionapi - Defines API for querying action properties - - @ref consoleapi - Enables applications to log/print text messages - - @ref systemapi - Define API for interating with system level intrinsics - - @ref transactionapi - Define API for sending transactions and inline messages - - @ref types - Specifies typedefs and aliases - - diff --git a/contracts/eosiolib/memory.h b/contracts/eosiolib/memory.h deleted file mode 100644 index 474e7c7b598..00000000000 --- a/contracts/eosiolib/memory.h +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include diff --git a/contracts/eosiolib/memory.hpp b/contracts/eosiolib/memory.hpp deleted file mode 100644 index f2abbf898d2..00000000000 --- a/contracts/eosiolib/memory.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include - -void* sbrk(size_t num_bytes); - - /** - * @defgroup memoryapi Memory API - * @brief Defines common memory functions - * @ingroup contractdev - */ - - /** - * @defgroup memorycppapi Memory C++ API - * @brief Defines common memory functions - * @ingroup memoryapi - * - * @{ - */ - -extern "C" { - -/** - * Allocate additional memory - * - * @brief Allocate additional memory - * @param size - Number of additional bytes to be allocated - * @return void* - Pointer to start of the new allocated memory - */ -void* malloc(size_t size); - -/** - * Allocate a block of memory for an array of **count** elements, each of them **size** bytes long, and initializes all bits with 0 - * - * @brief Allocate a block of memory for an array of **count** elements, each of them **size** bytes long, and initializes all bits with 0 - * @param count - Number of elements to allocate - * @param size - Size of each element - * @return void* - Pointer to start of the new allocated memory - */ -void* calloc(size_t count, size_t size); - -/** - * Reallocate the given area of memory, which is allocated by malloc(), calloc(), or realloc() previously - * - * @brief Reallocate the given area of memory - * @param ptr - Pointer to the memory area to be reallocated - * @param size - New size of the memory - * @return void* - Pointer to the new reallocated memory - */ -void* realloc(void* ptr, size_t size); - -/** - * - * Deallocates the given area of memory which is previously allocated by malloc(), calloc(), or realloc() - * @brief Deallocates the given area of memory - * - * @param ptr - Pointer to the memory to be deallocated - */ -void free(void* ptr); - -} - -/// @}memorycppapi diff --git a/contracts/eosiolib/multi_index.hpp b/contracts/eosiolib/multi_index.hpp deleted file mode 100644 index cba34f103a0..00000000000 --- a/contracts/eosiolib/multi_index.hpp +++ /dev/null @@ -1,2183 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -namespace eosio { - -using boost::multi_index::const_mem_fun; - -#define WRAP_SECONDARY_SIMPLE_TYPE(IDX, TYPE)\ -template<>\ -struct secondary_index_db_functions {\ - static int32_t db_idx_next( int32_t iterator, uint64_t* primary ) { return db_##IDX##_next( iterator, primary ); }\ - static int32_t db_idx_previous( int32_t iterator, uint64_t* primary ) { return db_##IDX##_previous( iterator, primary ); }\ - static void db_idx_remove( int32_t iterator ) { db_##IDX##_remove( iterator ); }\ - static int32_t db_idx_end( uint64_t code, uint64_t scope, uint64_t table ) { return db_##IDX##_end( code, scope, table ); }\ - static int32_t db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\ - return db_##IDX##_store( scope, table, payer, id, &secondary );\ - }\ - static void db_idx_update( int32_t iterator, uint64_t payer, const TYPE& secondary ) {\ - db_##IDX##_update( iterator, payer, &secondary );\ - }\ - static int32_t db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, TYPE& secondary ) {\ - return db_##IDX##_find_primary( code, scope, table, &secondary, primary );\ - }\ - static int32_t db_idx_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_find_secondary( code, scope, table, &secondary, &primary );\ - }\ - static int32_t db_idx_lowerbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_lowerbound( code, scope, table, &secondary, &primary );\ - }\ - static int32_t db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_upperbound( code, scope, table, &secondary, &primary );\ - }\ -}; - -#define WRAP_SECONDARY_ARRAY_TYPE(IDX, TYPE)\ -template<>\ -struct secondary_index_db_functions {\ - static int32_t db_idx_next( int32_t iterator, uint64_t* primary ) { return db_##IDX##_next( iterator, primary ); }\ - static int32_t db_idx_previous( int32_t iterator, uint64_t* primary ) { return db_##IDX##_previous( iterator, primary ); }\ - static void db_idx_remove( int32_t iterator ) { db_##IDX##_remove( iterator ); }\ - static int32_t db_idx_end( uint64_t code, uint64_t scope, uint64_t table ) { return db_##IDX##_end( code, scope, table ); }\ - static int32_t db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\ - return db_##IDX##_store( scope, table, payer, id, secondary.data(), TYPE::num_words() );\ - }\ - static void db_idx_update( int32_t iterator, uint64_t payer, const TYPE& secondary ) {\ - db_##IDX##_update( iterator, payer, secondary.data(), TYPE::num_words() );\ - }\ - static int32_t db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, TYPE& secondary ) {\ - return db_##IDX##_find_primary( code, scope, table, secondary.data(), TYPE::num_words(), primary );\ - }\ - static int32_t db_idx_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_find_secondary( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ - static int32_t db_idx_lowerbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_lowerbound( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ - static int32_t db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_upperbound( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ -}; - -#define MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(TYPE)\ -template<>\ -struct secondary_key_traits {\ - static constexpr TYPE lowest() { return std::numeric_limits::lowest(); }\ -}; - -namespace _multi_index_detail { - - namespace hana = boost::hana; - - template - struct secondary_index_db_functions; - - template - struct secondary_key_traits; - - WRAP_SECONDARY_SIMPLE_TYPE(idx64, uint64_t) - MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(uint64_t) - - WRAP_SECONDARY_SIMPLE_TYPE(idx128, uint128_t) - MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(uint128_t) - - WRAP_SECONDARY_SIMPLE_TYPE(idx_double, double) - MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(double) - - WRAP_SECONDARY_SIMPLE_TYPE(idx_long_double, long double) - MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(long double) - - WRAP_SECONDARY_ARRAY_TYPE(idx256, key256) - template<> - struct secondary_key_traits { - static constexpr key256 lowest() { return key256(); } - }; - -} - -/** - * The indexed_by struct is used to instantiate the indices for the Multi-Index table. In EOSIO, up to 16 secondary indices can be specified. - * @brief The indexed_by struct is used to instantiate the indices for the Multi-Index table. In EOSIO, up to 16 secondary indices can be specified. - * - * @tparam IndexName - is the name of the index. The name must be provided as an EOSIO base32 encoded 64-bit integer and must conform to the EOSIO naming requirements of a maximum of 13 characters, the first twelve from the lowercase characters a-z, digits 0-5, and ".", and if there is a 13th character, it is restricted to lowercase characters a-p and ".". - * @tparam Extractor - is a function call operator that takes a const reference to the table object type and returns either a secondary key type or a reference to a secondary key type. It is recommended to use the `eosio::const_mem_fun` template, which is a type alias to the `boost::multi_index::const_mem_fun`. See the documentation for the Boost `const_mem_fun` key extractor for more details. - * - * Example: - * -* - * @code - * #include - * using namespace eosio; - * class mycontract: eosio::contract { - * struct record { - * uint64_t primary; - * uint128_t secondary; - * uint64_t primary_key() const { return primary; } - * uint64_t get_secondary() const { return secondary; } - * EOSLIB_SERIALIZE( record, (primary)(secondary) ) - * }; - * public: - * mycontract( account_name self ):contract(self){} - * void myaction() { - * auto code = _self; - * auto scope = _self; - * multi_index > > table( code, scope); - * } - * } - * EOSIO_ABI( mycontract, (myaction) ) - * @endcode - */ -template -struct indexed_by { - enum constants { index_name = IndexName }; - typedef Extractor secondary_extractor_type; -}; - -/** - * @defgroup multiindex Multi Index Table - * @brief Defines EOSIO Multi Index Table - * @ingroup databasecpp - * - * - * - * EOSIO Multi-Index API provides a C++ interface to the EOSIO database. It is patterned after Boost Multi Index Container. - * EOSIO Multi-Index table requires exactly a uint64_t primary key. For the table to be able to retrieve the primary key, - * the object stored inside the table is required to have a const member function called primary_key() that returns uint64_t. - * EOSIO Multi-Index table also supports up to 16 secondary indices. The type of the secondary indices could be any of: - * - uint64_t - * - uint128_t - * - uint256_t - * - double - * - long double - * - * @tparam TableName - name of the table - * @tparam T - type of the data stored inside the table - * @tparam Indices - secondary indices for the table, up to 16 indices is supported here - * - * Example: - * - * @code - * #include - * using namespace eosio; - * class mycontract: contract { - * struct record { - * uint64_t primary; - * uint64_t secondary_1; - * uint128_t secondary_2; - * uint256_t secondary_3; - * double secondary_4; - * long double secondary_5; - * uint64_t primary_key() const { return primary; } - * uint64_t get_secondary_1() const { return secondary_1; } - * uint128_t get_secondary_2() const { return secondary_2; } - * uint256_t get_secondary_3() const { return secondary_3; } - * double get_secondary_4() const { return secondary_4; } - * long double get_secondary_5() const { return secondary_5; } - * EOSLIB_SERIALIZE( record, (primary)(secondary_1)(secondary_2)(secondary_3)(secondary_4)(secondary_5) ) - * }; - * public: - * mycontract( account_name self ):contract(self){} - * void myaction() { - * auto code = _self; - * auto scope = _self; - * multi_index >, - * indexed_by< N(bysecondary2), const_mem_fun >, - * indexed_by< N(bysecondary3), const_mem_fun >, - * indexed_by< N(bysecondary4), const_mem_fun >, - * indexed_by< N(bysecondary5), const_mem_fun > - * > table( code, scope); - * } - * } - * EOSIO_ABI( mycontract, (myaction) ) - * @endcode - * @{ - */ - -template -class multi_index -{ - private: - - static_assert( sizeof...(Indices) <= 16, "multi_index only supports a maximum of 16 secondary indices" ); - - constexpr static bool validate_table_name( uint64_t n ) { - // Limit table names to 12 characters so that the last character (4 bits) can be used to distinguish between the secondary indices. - return (n & 0x000000000000000FULL) == 0; - } - - constexpr static size_t max_stack_buffer_size = 512; - - static_assert( validate_table_name(TableName), "multi_index does not support table names with a length greater than 12"); - - uint64_t _code; - uint64_t _scope; - - mutable uint64_t _next_primary_key; - - enum next_primary_key_tags : uint64_t { - no_available_primary_key = static_cast(-2), // Must be the smallest uint64_t value compared to all other tags - unset_next_primary_key = static_cast(-1) - }; - - struct item : public T - { - template - item( const multi_index* idx, Constructor&& c ) - :__idx(idx){ - c(*this); - } - - const multi_index* __idx; - int32_t __primary_itr; - int32_t __iters[sizeof...(Indices)+(sizeof...(Indices)==0)]; - }; - - struct item_ptr - { - item_ptr(std::unique_ptr&& i, uint64_t pk, int32_t pitr) - : _item(std::move(i)), _primary_key(pk), _primary_itr(pitr) {} - - std::unique_ptr _item; - uint64_t _primary_key; - int32_t _primary_itr; - }; - - mutable std::vector _items_vector; - - template - struct index { - public: - typedef Extractor secondary_extractor_type; - typedef typename std::decay::type secondary_key_type; - - constexpr static bool validate_index_name( uint64_t n ) { - return n != 0 && n != N(primary); // Primary is a reserve index name. - } - - static_assert( validate_index_name(IndexName), "invalid index name used in multi_index" ); - - enum constants { - table_name = TableName, - index_name = IndexName, - index_number = Number, - index_table_name = (TableName & 0xFFFFFFFFFFFFFFF0ULL) | (Number & 0x000000000000000FULL) // Assuming no more than 16 secondary indices are allowed - }; - - constexpr static uint64_t name() { return index_table_name; } - constexpr static uint64_t number() { return Number; } - - struct const_iterator : public std::iterator { - public: - friend bool operator == ( const const_iterator& a, const const_iterator& b ) { - return a._item == b._item; - } - friend bool operator != ( const const_iterator& a, const const_iterator& b ) { - return a._item != b._item; - } - - const T& operator*()const { return *static_cast(_item); } - const T* operator->()const { return static_cast(_item); } - - const_iterator operator++(int){ - const_iterator result(*this); - ++(*this); - return result; - } - - const_iterator operator--(int){ - const_iterator result(*this); - --(*this); - return result; - } - - const_iterator& operator++() { - using namespace _multi_index_detail; - - eosio_assert( _item != nullptr, "cannot increment end iterator" ); - - if( _item->__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(_idx->get_code(), _idx->get_scope(), _idx->name(), _item->primary_key(), temp_secondary_key); - auto& mi = const_cast( *_item ); - mi.__iters[Number] = idxitr; - } - - uint64_t next_pk = 0; - auto next_itr = secondary_index_db_functions::db_idx_next( _item->__iters[Number], &next_pk ); - if( next_itr < 0 ) { - _item = nullptr; - return *this; - } - - const T& obj = *_idx->_multidx->find( next_pk ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = next_itr; - _item = &mi; - - return *this; - } - - const_iterator& operator--() { - using namespace _multi_index_detail; - - uint64_t prev_pk = 0; - int32_t prev_itr = -1; - - if( !_item ) { - auto ei = secondary_index_db_functions::db_idx_end(_idx->get_code(), _idx->get_scope(), _idx->name()); - eosio_assert( ei != -1, "cannot decrement end iterator when the index is empty" ); - prev_itr = secondary_index_db_functions::db_idx_previous( ei , &prev_pk ); - eosio_assert( prev_itr >= 0, "cannot decrement end iterator when the index is empty" ); - } else { - if( _item->__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(_idx->get_code(), _idx->get_scope(), _idx->name(), _item->primary_key(), temp_secondary_key); - auto& mi = const_cast( *_item ); - mi.__iters[Number] = idxitr; - } - prev_itr = secondary_index_db_functions::db_idx_previous( _item->__iters[Number], &prev_pk ); - eosio_assert( prev_itr >= 0, "cannot decrement iterator at beginning of index" ); - } - - const T& obj = *_idx->_multidx->find( prev_pk ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = prev_itr; - _item = &mi; - - return *this; - } - - const_iterator():_item(nullptr){} - private: - friend struct index; - const_iterator( const index* idx, const item* i = nullptr ) - : _idx(idx), _item(i) {} - - const index* _idx; - const item* _item; - }; /// struct multi_index::index::const_iterator - - typedef std::reverse_iterator const_reverse_iterator; - - const_iterator cbegin()const { - using namespace _multi_index_detail; - return lower_bound( secondary_key_traits::lowest() ); - } - const_iterator begin()const { return cbegin(); } - - const_iterator cend()const { return const_iterator( this ); } - const_iterator end()const { return cend(); } - - const_reverse_iterator crbegin()const { return std::make_reverse_iterator(cend()); } - const_reverse_iterator rbegin()const { return crbegin(); } - - const_reverse_iterator crend()const { return std::make_reverse_iterator(cbegin()); } - const_reverse_iterator rend()const { return crend(); } - - const_iterator find( secondary_key_type&& secondary )const { - return find( secondary ); - } - - const_iterator find( const secondary_key_type& secondary )const { - auto lb = lower_bound( secondary ); - auto e = cend(); - if( lb == e ) return e; - - if( secondary != secondary_extractor_type()(*lb) ) - return e; - return lb; - } - - const_iterator require_find( secondary_key_type&& secondary, const char* error_msg = "unable to find secondary key" )const { - return require_find( secondary, error_msg ); - } - - const_iterator require_find( const secondary_key_type& secondary, const char* error_msg = "unable to find secondary key" )const { - auto lb = lower_bound( secondary ); - eosio_assert( lb != cend(), error_msg ); - eosio_assert( secondary == secondary_extractor_type()(*lb), error_msg ); - return lb; - } - - const T& get( secondary_key_type&& secondary, const char* error_msg = "unable to find secondary key" )const { - return get( secondary, error_msg ); - } - - // Gets the object with the smallest primary key in the case where the secondary key is not unique. - const T& get( const secondary_key_type& secondary, const char* error_msg = "unable to find secondary key" )const { - auto result = find( secondary ); - eosio_assert( result != cend(), error_msg ); - return *result; - } - - const_iterator lower_bound( secondary_key_type&& secondary )const { - return lower_bound( secondary ); - } - const_iterator lower_bound( const secondary_key_type& secondary )const { - using namespace _multi_index_detail; - - uint64_t primary = 0; - secondary_key_type secondary_copy(secondary); - auto itr = secondary_index_db_functions::db_idx_lowerbound( get_code(), get_scope(), name(), secondary_copy, primary ); - if( itr < 0 ) return cend(); - - const T& obj = *_multidx->find( primary ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = itr; - - return {this, &mi}; - } - - const_iterator upper_bound( secondary_key_type&& secondary )const { - return upper_bound( secondary ); - } - const_iterator upper_bound( const secondary_key_type& secondary )const { - using namespace _multi_index_detail; - - uint64_t primary = 0; - secondary_key_type secondary_copy(secondary); - auto itr = secondary_index_db_functions::db_idx_upperbound( get_code(), get_scope(), name(), secondary_copy, primary ); - if( itr < 0 ) return cend(); - - const T& obj = *_multidx->find( primary ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = itr; - - return {this, &mi}; - } - - const_iterator iterator_to( const T& obj ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio_assert( objitem.__idx == _multidx, "object passed to iterator_to is not in multi_index" ); - - if( objitem.__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(get_code(), get_scope(), name(), objitem.primary_key(), temp_secondary_key); - auto& mi = const_cast( objitem ); - mi.__iters[Number] = idxitr; - } - - return {this, &objitem}; - } - - template - void modify( const_iterator itr, uint64_t payer, Lambda&& updater ) { - eosio_assert( itr != cend(), "cannot pass end iterator to modify" ); - - _multidx->modify( *itr, payer, std::forward(updater) ); - } - - const_iterator erase( const_iterator itr ) { - eosio_assert( itr != cend(), "cannot pass end iterator to erase" ); - - const auto& obj = *itr; - ++itr; - - _multidx->erase(obj); - - return itr; - } - - uint64_t get_code()const { return _multidx->get_code(); } - uint64_t get_scope()const { return _multidx->get_scope(); } - - static auto extract_secondary_key(const T& obj) { return secondary_extractor_type()(obj); } - - private: - friend class multi_index; - - index( typename std::conditional::type midx ) - :_multidx(midx){} - - typename std::conditional::type _multidx; - }; /// struct multi_index::index - - template - struct intc { enum e{ value = I }; operator uint64_t()const{ return I; } }; - - static constexpr auto transform_indices( ) { - using namespace _multi_index_detail; - - typedef decltype( hana::zip_shortest( - hana::make_tuple( intc<0>(), intc<1>(), intc<2>(), intc<3>(), intc<4>(), intc<5>(), - intc<6>(), intc<7>(), intc<8>(), intc<9>(), intc<10>(), intc<11>(), - intc<12>(), intc<13>(), intc<14>(), intc<15>() ), - hana::tuple() ) ) indices_input_type; - - return hana::transform( indices_input_type(), [&]( auto&& idx ){ - typedef typename std::decay(idx))>::type num_type; - typedef typename std::decay(idx))>::type idx_type; - return hana::make_tuple( hana::type_c >, - hana::type_c > ); - - }); - } - - typedef decltype( multi_index::transform_indices() ) indices_type; - - indices_type _indices; - - const item& load_object_by_primary_iterator( int32_t itr )const { - using namespace _multi_index_detail; - - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._primary_itr == itr; - }); - if( itr2 != _items_vector.rend() ) - return *itr2->_item; - - auto size = db_get_i64( itr, nullptr, 0 ); - eosio_assert( size >= 0, "error reading iterator" ); - - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size_t(size) ? malloc(size_t(size)) : alloca(size_t(size)); - - db_get_i64( itr, buffer, uint32_t(size) ); - - datastream ds( (char*)buffer, uint32_t(size) ); - - if ( max_stack_buffer_size < size_t(size) ) { - free(buffer); - } - - auto itm = std::make_unique( this, [&]( auto& i ) { - T& val = static_cast(i); - ds >> val; - - i.__primary_itr = itr; - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<1>(idx))::type index_type; - - i.__iters[ index_type::number() ] = -1; - }); - }); - - const item* ptr = itm.get(); - auto pk = itm->primary_key(); - auto pitr = itm->__primary_itr; - - _items_vector.emplace_back( std::move(itm), pk, pitr ); - - return *ptr; - } /// load_object_by_primary_iterator - - public: - /** - * Constructs an instance of a Multi-Index table. - * @brief Constructs an instance of a Multi-Index table. - * - * @param code - Account that owns table - * @param scope - Scope identifier within the code hierarchy - * - * @pre code and scope member properties are initialized - * @post each secondary index table initialized - * @post Secondary indices are updated to refer to the newly added object. If the secondary index tables do not exist, they are created. - * @post The payer is charged for the storage usage of the new object and, if the table (and secondary index tables) must be created, for the overhead of the table creation. - * - * Notes - * The `eosio::multi_index` template has template parameters ``, where: - * - `TableName` is the name of the table, maximum 12 characters long, characters in the name from the set of lowercase letters, digits 1 to 5, and the "." (period) character; - * - `T` is the object type (i.e., row definition); - * - `Indices` is a list of up to 16 secondary indices. - * - Each must be a default constructable class or struct - * - Each must have a function call operator that takes a const reference to the table object type and returns either a secondary key type or a reference to a secondary key type - * - It is recommended to use the eosio::const_mem_fun template, which is a type alias to the boost::multi_index::const_mem_fun. See the documentation for the Boost const_mem_fun key extractor for more details. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - multi_index( uint64_t code, uint64_t scope ) - :_code(code),_scope(scope),_next_primary_key(unset_next_primary_key) - {} - - /** - * Returns the `code` member property. - * @brief Returns the `code` member property. - * - * @return Account name of the Code that owns the Primary Table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(N(dan), N(dan)); // code, scope - * eosio_assert(addresses.get_code() == N(dan), "Codes don't match."); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - uint64_t get_code()const { return _code; } - - /** - * Returns the `scope` member property. - * @brief Returns the `scope` member property. - * - * @return Scope id of the Scope within the Code of the Current Receiver under which the desired Primary Table instance can be found. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(N(dan), N(dan)); // code, scope - * eosio_assert(addresses.get_code() == N(dan), "Scopes don't match"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - uint64_t get_scope()const { return _scope; } - - struct const_iterator : public std::iterator { - friend bool operator == ( const const_iterator& a, const const_iterator& b ) { - return a._item == b._item; - } - friend bool operator != ( const const_iterator& a, const const_iterator& b ) { - return a._item != b._item; - } - - const T& operator*()const { return *static_cast(_item); } - const T* operator->()const { return static_cast(_item); } - - const_iterator operator++(int) { - const_iterator result(*this); - ++(*this); - return result; - } - - const_iterator operator--(int) { - const_iterator result(*this); - --(*this); - return result; - } - - const_iterator& operator++() { - eosio_assert( _item != nullptr, "cannot increment end iterator" ); - - uint64_t next_pk; - auto next_itr = db_next_i64( _item->__primary_itr, &next_pk ); - if( next_itr < 0 ) - _item = nullptr; - else - _item = &_multidx->load_object_by_primary_iterator( next_itr ); - return *this; - } - const_iterator& operator--() { - uint64_t prev_pk; - int32_t prev_itr = -1; - - if( !_item ) { - auto ei = db_end_i64(_multidx->get_code(), _multidx->get_scope(), TableName); - eosio_assert( ei != -1, "cannot decrement end iterator when the table is empty" ); - prev_itr = db_previous_i64( ei , &prev_pk ); - eosio_assert( prev_itr >= 0, "cannot decrement end iterator when the table is empty" ); - } else { - prev_itr = db_previous_i64( _item->__primary_itr, &prev_pk ); - eosio_assert( prev_itr >= 0, "cannot decrement iterator at beginning of table" ); - } - - _item = &_multidx->load_object_by_primary_iterator( prev_itr ); - return *this; - } - - private: - const_iterator( const multi_index* mi, const item* i = nullptr ) - :_multidx(mi),_item(i){} - - const multi_index* _multidx; - const item* _item; - friend class multi_index; - }; /// struct multi_index::const_iterator - - typedef std::reverse_iterator const_reverse_iterator; - - /** - * Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * @brief Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr == addresses.cbegin(), "Only address is not at front."); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator cbegin()const { - return lower_bound(std::numeric_limits::lowest()); - } - - /** - * Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * @brief Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr == addresses.begin(), "Only address is not at front."); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator begin()const { return cbegin(); } - - /** - * Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * @brief Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr != addresses.cend(), "Address for account doesn't exist"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator cend()const { return const_iterator( this ); } - - /** - * Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * @brief Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr != addresses.end(), "Address for account doesn't exist"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator end()const { return cend(); } - - /** - * Returns a reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * @brief Returns a reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return A reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(brendan); - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.crbegin(); - * eosio_assert(itr->account_name == N(dan), "Incorrect Last Record "); - * itr++; - * eosio_assert(itr->account_name == N(brendan), "Incorrect Second Last Record"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator crbegin()const { return std::make_reverse_iterator(cend()); } - - /** - * Returns a reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * @brief Returns a reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return A reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(brendan); - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.rbegin(); - * eosio_assert(itr->account_name == N(dan), "Incorrect Last Record "); - * itr++; - * eosio_assert(itr->account_name == N(brendan), "Incorrect Second Last Record"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator rbegin()const { return crbegin(); } - - /** - * Returns an iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * @brief Returns an iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(brendan); - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.crend(); - * itr--; - * eosio_assert(itr->account_name == N(brendan), "Incorrect First Record "); - * itr--; - * eosio_assert(itr->account_name == N(dan), "Incorrect Second Record"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator crend()const { return std::make_reverse_iterator(cbegin()); } - - /** - * Returns an iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * @brief Returns an iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(brendan); - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.rend(); - * itr--; - * eosio_assert(itr->account_name == N(brendan), "Incorrect First Record "); - * itr--; - * eosio_assert(itr->account_name == N(dan), "Incorrect Second Record"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator rend()const { return crend(); } - - /** - * Searches for the `object_type` with the lowest primary key that is greater than or equal to a given primary key. - * @brief Searches for the `object_type` with the lowest primary key that is greater than or equal to a given primary key. - * - * @param primary - Primary key that establishes the target value for the lower bound search. - * - * @return An iterator pointing to the `object_type` that has the lowest primary key that is greater than or equal to `primary`. If an object could not be found, it will return the `end` iterator. If the table does not exist** it will return `-1`. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint32_t zip = 0; - * uint64_t primary_key() const { return account_name; } - * uint64_t by_zip() const { return zip; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state)(zip) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address, indexed_by< N(zip), const_mem_fun > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * address.zip = 93446; - * }); - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(brendan); - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.lower_bound(zipnumb); - * eosio_assert(itr->account_name == N(brendan), "Incorrect First Lower Bound Record "); - * itr++; - * eosio_assert(itr->account_name == N(dan), "Incorrect Second Lower Bound Record"); - * itr++; - * eosio_assert(itr == zip_index.end(), "Incorrect End of Iterator"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator lower_bound( uint64_t primary )const { - auto itr = db_lowerbound_i64( _code, _scope, TableName, primary ); - if( itr < 0 ) return end(); - const auto& obj = load_object_by_primary_iterator( itr ); - return {this, &obj}; - } - - /** - * Searches for the `object_type` with the highest primary key that is less than or equal to a given primary key. - * @brief Searches for the `object_type` with the highest primary key that is less than or equal to a given primary key. - * - * @param primary - Primary key that establishes the target value for the upper bound search - * - * @return An iterator pointing to the `object_type` that has the highest primary key that is less than or equal to `primary`. If an object could not be found, it will return the `end` iterator. If the table does not exist** it will return `-1`. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint32_t zip = 0; - * uint64_t liked = 0; - * uint64_t primary_key() const { return account_name; } - * uint64_t by_zip() const { return zip; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state)(zip) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address, indexed_by< N(zip), const_mem_fun > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * address.zip = 93446; - * }); - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(brendan); - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.upper_bound(zipnumb); - * eosio_assert(itr->account_name == N(dan), "Incorrect First Upper Bound Record "); - * itr++; - * eosio_assert(itr == zip_index.end(), "Incorrect End of Iterator"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator upper_bound( uint64_t primary )const { - auto itr = db_upperbound_i64( _code, _scope, TableName, primary ); - if( itr < 0 ) return end(); - const auto& obj = load_object_by_primary_iterator( itr ); - return {this, &obj}; - } - - /** - * Returns an available primary key. - * @brief Returns an available primary key. - * - * @return An available (unused) primary key value. - * - * Notes: - * Intended to be used in tables in which the primary keys of the table are strictly intended to be auto-incrementing, and thus will never be set to custom values by the contract. Violating this expectation could result in the table appearing to be full due to inability to allocate an available primary key. - * Ideally this method would only be used to determine the appropriate primary key to use within new objects added to a table in which the primary keys of the table are strictly intended from the beginning to be autoincrementing and thus will not ever be set to custom arbitrary values by the contract. Violating this agreement could result in the table appearing full when in reality there is plenty of space left. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t key; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return key; } - * EOSLIB_SERIALIZE( address, (key)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.key = addresses.available_primary_key(); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - uint64_t available_primary_key()const { - if( _next_primary_key == unset_next_primary_key ) { - // This is the first time available_primary_key() is called for this multi_index instance. - if( begin() == end() ) { // empty table - _next_primary_key = 0; - } else { - auto itr = --end(); // last row of table sorted by primary key - auto pk = itr->primary_key(); // largest primary key currently in table - if( pk >= no_available_primary_key ) // Reserve the tags - _next_primary_key = no_available_primary_key; - else - _next_primary_key = pk + 1; - } - } - - eosio_assert( _next_primary_key < no_available_primary_key, "next primary key in table is at autoincrement limit"); - return _next_primary_key; - } - - /** - * Returns an appropriately typed Secondary Index. - * @brief Returns an appropriately typed Secondary Index. - * - * @tparam IndexName - the ID of the desired secondary index - * - * @return An index of the appropriate type: Primitive 64-bit unsigned integer key (idx64), Primitive 128-bit unsigned integer key (idx128), 128-bit fixed-size lexicographical key (idx128), 256-bit fixed-size lexicographical key (idx256), Floating point key, Double precision floating point key, Long Double (quadruple) precision floating point key - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint32_t zip = 0; - * uint64_t primary_key() const { return account_name; } - * uint64_t by_zip() const { return zip; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state)(zip) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address, indexed_by< N(zip), const_mem_fun > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * address.zip = 93446; - * }); - * uint32_t zipnumb = 93446; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.find(zipnumb); - * eosio_assert(itr->account_name == N(dan), "Incorrect Record "); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - template - auto get_index() { - using namespace _multi_index_detail; - - auto res = hana::find_if( _indices, []( auto&& in ) { - return std::integral_constant(in))::type>::type::index_name == IndexName>(); - }); - - static_assert( res != hana::nothing, "name provided is not the name of any secondary index within multi_index" ); - - return typename decltype(+hana::at_c<0>(res.value()))::type(this); - } - - /** - * Returns an appropriately typed Secondary Index. - * @brief Returns an appropriately typed Secondary Index. - * - * @tparam IndexName - the ID of the desired secondary index - * - * @return An index of the appropriate type: Primitive 64-bit unsigned integer key (idx64), Primitive 128-bit unsigned integer key (idx128), 128-bit fixed-size lexicographical key (idx128), 256-bit fixed-size lexicographical key (idx256), Floating point key, Double precision floating point key, Long Double (quadruple) precision floating point key - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint32_t zip = 0; - * uint64_t primary_key() const { return account_name; } - * uint64_t by_zip() const { return zip; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state)(zip) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address, indexed_by< N(zip), const_mem_fun > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * address.zip = 93446; - * }); - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(brendan); - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.upper_bound(zipnumb); - * eosio_assert(itr->account_name == N(dan), "Incorrect First Upper Bound Record "); - * itr++; - * eosio_assert(itr == zip_index.end(), "Incorrect End of Iterator"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - template - auto get_index()const { - using namespace _multi_index_detail; - - auto res = hana::find_if( _indices, []( auto&& in ) { - return std::integral_constant(in))::type>::type::index_name == IndexName>(); - }); - - static_assert( res != hana::nothing, "name provided is not the name of any secondary index within multi_index" ); - - return typename decltype(+hana::at_c<1>(res.value()))::type(this); - } - - /** - * Returns an iterator to the given object in a Multi-Index table. - * @brief Returns an iterator to the given object in a Multi-Index table. - * - * @param obj - A reference to the desired object - * - * @return An iterator to the given object - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint32_t zip = 0; - * uint64_t primary_key() const { return account_name; } - * uint64_t by_zip() const { return zip; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state)(zip) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address, indexed_by< N(zip), const_mem_fun > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * address.zip = 93446; - * }); - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = N(brendan); - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * auto user = addresses.get(N(dan)); - * auto itr = address.find(N(dan)); - * eosio_assert(iterator_to(user) == itr, "Invalid iterator"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator iterator_to( const T& obj )const { - const auto& objitem = static_cast(obj); - eosio_assert( objitem.__idx == this, "object passed to iterator_to is not in multi_index" ); - return {this, &objitem}; - } - /** - * Adds a new object (i.e., row) to the table. - * @brief Adds a new object (i.e., row) to the table. - * - * @param payer - Account name of the payer for the Storage usage of the new object - * @param constructor - Lambda function that does an in-place initialization of the object to be created in the table - * - * @pre A multi index table has been instantiated - * @post A new object is created in the Multi-Index table, with a unique primary key (as specified in the object). The object is serialized and written to the table. If the table does not exist, it is created. - * @post Secondary indices are updated to refer to the newly added object. If the secondary index tables do not exist, they are created. - * @post The payer is charged for the storage usage of the new object and, if the table (and secondary index tables) must be created, for the overhead of the table creation. - * - * @return A primary key iterator to the newly created object - * - * Exception - The account is not authorized to write to the table. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - template - const_iterator emplace( uint64_t payer, Lambda&& constructor ) { - using namespace _multi_index_detail; - - eosio_assert( _code == current_receiver(), "cannot create objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto itm = std::make_unique( this, [&]( auto& i ){ - T& obj = static_cast(i); - constructor( obj ); - - size_t size = pack_size( obj ); - - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); - - datastream ds( (char*)buffer, size ); - ds << obj; - - auto pk = obj.primary_key(); - - i.__primary_itr = db_store_i64( _scope, TableName, payer, pk, buffer, size ); - - if ( max_stack_buffer_size < size ) { - free(buffer); - } - - if( pk >= _next_primary_key ) - _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - i.__iters[index_type::number()] = secondary_index_db_functions::db_idx_store( _scope, index_type::name(), payer, obj.primary_key(), index_type::extract_secondary_key(obj) ); - }); - }); - - const item* ptr = itm.get(); - auto pk = itm->primary_key(); - auto pitr = itm->__primary_itr; - - _items_vector.emplace_back( std::move(itm), pk, pitr ); - - return {this, ptr}; - } - - /** - * Modifies an existing object in a table. - * @brief Modifies an existing object in a table. - * - * @param itr - an iterator pointing to the object to be updated - * @param payer - account name of the payer for the Storage usage of the updated row - * @param updater - lambda function that updates the target object - * - * @pre itr points to an existing element - * @pre payer is a valid account that is authorized to execute the action and be billed for storage usage. - * - * @post The modified object is serialized, then replaces the existing object in the table. - * @post Secondary indices are updated; the primary key of the updated object is not changed. - * @post The payer is charged for the storage usage of the updated object. - * @post If payer is the same as the existing payer, payer only pays for the usage difference between existing and updated object (and is refunded if this difference is negative). - * @post If payer is different from the existing payer, the existing payer is refunded for the storage usage of the existing object. - * - * Exceptions: - * If called with an invalid precondition, execution is aborted. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr != addresses.end(), "Address for account not found"); - * addresses.modify( itr, account payer, [&]( auto& address ) { - * address.city = "San Luis Obispo"; - * address.state = "CA"; - * }); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - template - void modify( const_iterator itr, uint64_t payer, Lambda&& updater ) { - eosio_assert( itr != end(), "cannot pass end iterator to modify" ); - - modify( *itr, payer, std::forward(updater) ); - } - - /** - * Modifies an existing object in a table. - * @brief Modifies an existing object in a table. - * - * @param obj - a reference to the object to be updated - * @param payer - account name of the payer for the Storage usage of the updated row - * @param updater - lambda function that updates the target object - * - * @pre obj is an existing object in the table - * @pre payer is a valid account that is authorized to execute the action and be billed for storage usage. - * - * @post The modified object is serialized, then replaces the existing object in the table. - * @post Secondary indices are updated; the primary key of the updated object is not changed. - * @post The payer is charged for the storage usage of the updated object. - * @post If payer is the same as the existing payer, payer only pays for the usage difference between existing and updated object (and is refunded if this difference is negative). - * @post If payer is different from the existing payer, the existing payer is refunded for the storage usage of the existing object. - * - * Exceptions: - * If called with an invalid precondition, execution is aborted. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr != addresses.end(), "Address for account not found"); - * addresses.modify( *itr, payer, [&]( auto& address ) { - * address.city = "San Luis Obispo"; - * address.state = "CA"; - * }); - * eosio_assert(itr->city == "San Luis Obispo", "Address not modified"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - template - void modify( const T& obj, uint64_t payer, Lambda&& updater ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio_assert( objitem.__idx == this, "object passed to modify is not in multi_index" ); - auto& mutableitem = const_cast(objitem); - eosio_assert( _code == current_receiver(), "cannot modify objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto secondary_keys = hana::transform( _indices, [&]( auto&& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - return index_type::extract_secondary_key( obj ); - }); - - auto pk = obj.primary_key(); - - auto& mutableobj = const_cast(obj); // Do not forget the auto& otherwise it would make a copy and thus not update at all. - updater( mutableobj ); - - eosio_assert( pk == obj.primary_key(), "updater cannot change primary key when modifying an object" ); - - size_t size = pack_size( obj ); - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); - - datastream ds( (char*)buffer, size ); - ds << obj; - - db_update_i64( objitem.__primary_itr, payer, buffer, size ); - - if ( max_stack_buffer_size < size ) { - free( buffer ); - } - - if( pk >= _next_primary_key ) - _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - auto secondary = index_type::extract_secondary_key( obj ); - if( memcmp( &hana::at_c(secondary_keys), &secondary, sizeof(secondary) ) != 0 ) { - auto indexitr = mutableitem.__iters[index_type::number()]; - - if( indexitr < 0 ) { - typename index_type::secondary_key_type temp_secondary_key; - indexitr = mutableitem.__iters[index_type::number()] - = secondary_index_db_functions::db_idx_find_primary( _code, _scope, index_type::name(), pk, temp_secondary_key ); - } - - secondary_index_db_functions::db_idx_update( indexitr, payer, secondary ); - } - }); - } - - /** - * Retrieves an existing object from a table using its primary key. - * @brief Retrieves an existing object from a table using its primary key. - * - * @param primary - Primary key value of the object - * @return A constant reference to the object containing the specified primary key. - * - * Exception - No object matches the given key - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto user = addresses.get(N(dan)); - * eosio_assert(user.first_name == "Daniel", "Couldn't get him."); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const T& get( uint64_t primary, const char* error_msg = "unable to find key" )const { - auto result = find( primary ); - eosio_assert( result != cend(), error_msg ); - return *result; - } - - /** - * Search for an existing object in a table using its primary key. - * @brief Search for an existing object in a table using its primary key. - * - * @param primary - Primary key value of the object - * @return An iterator to the found object which has a primary key equal to `primary` OR the `end` iterator of the referenced table if an object with primary key `primary` is not found. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr != addresses.end(), "Couldn't get him."); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator find( uint64_t primary )const { - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == primary; - }); - if( itr2 != _items_vector.rend() ) - return iterator_to(*(itr2->_item)); - - auto itr = db_find_i64( _code, _scope, TableName, primary ); - if( itr < 0 ) return end(); - - const item& i = load_object_by_primary_iterator( itr ); - return iterator_to(static_cast(i)); - } - - /** - * Search for an existing object in a table using its primary key. - * @brief Search for an existing object in a table using its primary key. - * - * @param primary - Primary key value of the object - * @param error_msg - error message if an object with primary key `primary` is not found. - * @return An iterator to the found object which has a primary key equal to `primary` OR throws an exception if an object with primary key `primary` is not found. - */ - - const_iterator require_find( uint64_t primary, const char* error_msg = "unable to find key" )const { - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == primary; - }); - if( itr2 != _items_vector.rend() ) - return iterator_to(*(itr2->_item)); - - auto itr = db_find_i64( _code, _scope, TableName, primary ); - eosio_assert( itr >= 0, error_msg ); - - const item& i = load_object_by_primary_iterator( itr ); - return iterator_to(static_cast(i)); - } - - /** - * Remove an existing object from a table using its primary key. - * @brief Remove an existing object from a table using its primary key. - * - * @param itr - An iterator pointing to the object to be removed - * - * @pre itr points to an existing element - * @post The object is removed from the table and all associated storage is reclaimed. - * @post Secondary indices associated with the table are updated. - * @post The existing payer for storage usage of the object is refunded for the table and secondary indices usage of the removed object, and if the table and indices are removed, for the associated overhead. - * - * @return For the signature with `const_iterator`, returns a pointer to the object following the removed object. - * - * Exceptions: - * The object to be removed is not in the table. - * The action is not authorized to modify the table. - * The given iterator is invalid. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr != addresses.end(), "Address for account not found"); - * addresses.erase( itr ); - * eosio_assert(itr != addresses.end(), "Address not erased properly"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator erase( const_iterator itr ) { - eosio_assert( itr != end(), "cannot pass end iterator to erase" ); - - const auto& obj = *itr; - ++itr; - - erase(obj); - - return itr; - } - - /** - * Remove an existing object from a table using its primary key. - * @brief Remove an existing object from a table using its primary key. - * - * @param obj - Object to be removed - * - * @pre obj is an existing object in the table - * @post The object is removed from the table and all associated storage is reclaimed. - * @post Secondary indices associated with the table are updated. - * @post The existing payer for storage usage of the object is refunded for the table and secondary indices usage of the removed object, and if the table and indices are removed, for the associated overhead. - * - * Exceptions: - * The object to be removed is not in the table. - * The action is not authorized to modify the table. - * The given iterator is invalid. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * EOSLIB_SERIALIZE( address, (account_name)(first_name)(last_name)(street)(city)(state) ) - * }; - * public: - * addressbook(account_name self):contract(self) {} - * typedef eosio::multi_index< N(address), address > address_index; - * void myaction() { - * address_index addresses(_self, _self); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = N(dan); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * auto itr = addresses.find(N(dan)); - * eosio_assert(itr != addresses.end(), "Record is not found"); - * addresses.erase(*itr); - * itr = addresses.find(N(dan)); - * eosio_assert(itr == addresses.end(), "Record is not deleted"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - void erase( const T& obj ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio_assert( objitem.__idx == this, "object passed to erase is not in multi_index" ); - eosio_assert( _code == current_receiver(), "cannot erase objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto pk = objitem.primary_key(); - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == pk; - }); - - eosio_assert( itr2 != _items_vector.rend(), "attempt to remove object that was not in multi_index" ); - - _items_vector.erase(--(itr2.base())); - - db_remove_i64( objitem.__primary_itr ); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - auto i = objitem.__iters[index_type::number()]; - if( i < 0 ) { - typename index_type::secondary_key_type secondary; - i = secondary_index_db_functions::db_idx_find_primary( _code, _scope, index_type::name(), objitem.primary_key(), secondary ); - } - if( i >= 0 ) - secondary_index_db_functions::db_idx_remove( i ); - }); - } - -}; - /// @} -} /// eosio diff --git a/contracts/eosiolib/optional.hpp b/contracts/eosiolib/optional.hpp deleted file mode 100644 index fb3a404658f..00000000000 --- a/contracts/eosiolib/optional.hpp +++ /dev/null @@ -1,535 +0,0 @@ -#pragma once - -#include - -namespace eosio { - /** - * @defgroup optionaltype Optional Type - * @brief Defines otional type which is similar to boost::optional - * @ingroup types - * @{ - */ - - /** - * Provides stack-based nullable value similar to boost::optional - * - * @brief Provides stack-based nullable value similar to boost::optional - */ - template - class optional { - public: - typedef T value_type; - typedef typename std::aligned_storage::type storage_type; - - /** - * Default constructor - * - * @brief Construct a new optional object - */ - optional():_valid(false){} - - /** - * Destructor - * - * @brief Destroy the optional object - */ - ~optional(){ reset(); } - - /** - * Construct a new optional object from another optional object - * - * @brief Construct a new optional object - */ - optional( optional& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( *o ); - _valid = o._valid; - } - - /** - * Copy constructor - * - * @brief Construct a new optional object - */ - optional( const optional& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( *o ); - _valid = o._valid; - } - - /** - * Move constructor - * - * @brief Construct a new optional object - */ - optional( optional&& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( std::move(*o) ); - _valid = o._valid; - o.reset(); - } - - /** - * Construct a new optional object from another type of optional object - * - * @brief Construct a new optional object from another type of optional object - */ - template - optional( const optional& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( *o ); - _valid = o._valid; - } - - /** - * Construct a new optional object from another type of optional object - * - * @brief Construct a new optional object from another type of optional object - */ - template - optional( optional& o ) - :_valid(false) - { - if( o._valid ) - { - new (ptr()) T( *o ); - } - _valid = o._valid; - } - - /** - * Construct a new optional object from another type of optional object - * - * @brief Construct a new optional object from another type of optional object - */ - template - optional( optional&& o ) - :_valid(false) - { - if( o._valid ) new (ptr()) T( std::move(*o) ); - _valid = o._valid; - o.reset(); - } - - /** - * Construct a new optional object from another object - * - * @brief Construct a new optional object from another object - */ - template - optional( U&& u ) - :_valid(true) - { - new ((char*)ptr()) T( std::forward(u) ); - } - - /** - * Construct a new optional object from another object - * - * @brief Construct a new optional object from another object - */ - template - optional& operator=( U&& u ) - { - reset(); - new (ptr()) T( std::forward(u) ); - _valid = true; - return *this; - } - - /** - * Construct the contained value in place - * - * @brief Construct the contained value in place - * @tparam Args - Type of the contained value - * @param args - The value to be assigned as contained value - */ - template - void emplace(Args&& ... args) { - if (_valid) { - reset(); - } - - new ((char*)ptr()) T( std::forward(args)... ); - _valid = true; - } - - /** - * Assignment Operator - * - * @brief Assignment Operator - * @tparam U - Type of the contained value of the optional object to be assigned from - * @param o - The other optional object to be assigned from - * @return optional& - The reference to this object - */ - template - optional& operator=( optional& o ) { - if (this != &o) { - if( _valid && o._valid ) { - ref() = *o; - } else if( !_valid && o._valid ) { - new (ptr()) T( *o ); - _valid = true; - } else if (_valid) { - reset(); - } - } - return *this; - } - - /** - * Assignment Operator - * - * @brief Assignment Operator - * @tparam U - Type of the contained value of the optional object to be assigned from - * @param o - The other optional object to be assigned from - * @return optional& - The reference to this object - */ - template - optional& operator=( const optional& o ) { - if (this != &o) { - if( _valid && o._valid ) { - ref() = *o; - } else if( !_valid && o._valid ) { - new (ptr()) T( *o ); - _valid = true; - } else if (_valid) { - reset(); - } - } - return *this; - } - - /** - * Assignment Operator - * - * @brief Assignment Operator - * @param o - The other optional object to be assigned from - * @return optional& - The reference to this object - */ - optional& operator=( optional& o ) { - if (this != &o) { - if( _valid && o._valid ) { - ref() = *o; - } else if( !_valid && o._valid ) { - new (ptr()) T( *o ); - _valid = true; - } else if (_valid) { - reset(); - } - } - return *this; - } - - /** - * Assignment Operator - * - * @brief Assignment Operator - * @param o - The other optional object to be assigned from - * @return optional& - The reference to this object - */ - optional& operator=( const optional& o ) { - if (this != &o) { - if( _valid && o._valid ) { - ref() = *o; - } else if( !_valid && o._valid ) { - new (ptr()) T( *o ); - _valid = true; - } else if (_valid) { - reset(); - } - } - return *this; - } - - /** - * Assignment Operator - * - * @brief Assignment Operator - * @tparam U - Type of the contained value of the optional object to be assigned from - * @param o - The other optional object to be assigned from - * @return optional& - The reference to this object - */ - template - optional& operator=( optional&& o ) - { - if (this != &o) - { - if( _valid && o._valid ) - { - ref() = std::move(*o); - o.reset(); - } else if ( !_valid && o._valid ) { - *this = std::move(*o); - } else if (_valid) { - reset(); - } - } - return *this; - } - - /** - * Assignment Operator - * - * @brief Assignment Operator - * @param o - The other optional object to be assigned from - * @return optional& - The reference to this object - */ - optional& operator=( optional&& o ) - { - if (this != &o) - { - if( _valid && o._valid ) - { - ref() = std::move(*o); - o.reset(); - } else if ( !_valid && o._valid ) { - *this = std::move(*o); - } else if (_valid) { - reset(); - } - } - return *this; - } - - /** - * Check if this optional has valid contained value - * - * @brief Check if this optional has valid contained value - * @return true - if this optional has valid contained value - * @return false - otherwise - */ - bool valid()const { return _valid; } - - /** - * Logical Negation operator - * - * @brief Logical Negation Operator - * @return true - if this optional has invalid contained value - * @return false - otherwise - */ - bool operator!()const { return !_valid; } - - /** - * Similar to valid(). However, this operation is not safe and can result in unintential - * casts and comparisons, use valid() or !! - * - * @brief Check if this optional has valid contained value - * @return true - if this optional has valid contained value - * @return false - otherwise - */ - explicit operator bool()const { return _valid; } - - /** - * Get contained value of this optional - * - * @brief Pointer Dereference operator - * @return T& - Contained value - */ - T& operator*() { eosio_assert(_valid, "dereference of empty optional"); return ref(); } - - /** - * Get contained value of this optional - * - * @brief Pointer Dereference operator - * @return T& - Contained value - */ - const T& operator*()const { eosio_assert(_valid, "dereference of empty optional"); return ref(); } - - /** - * Get pointer to the contained value - * - * @brief Member Access Through Pointer Operator - * @return T& - The pointer to the contained value - */ - T* operator->() - { - eosio_assert(_valid, "dereference of empty optional"); - return ptr(); - } - - /** - * Get pointer to the contained value - * - * @brief Member Access Through Pointer Operator - * @return T& - The pointer to the contained value - */ - const T* operator->()const - { - eosio_assert(_valid, "dereference of empty optional"); - return ptr(); - } - - /** - * Assignment Operator with nullptr - * - * @brief Assignment Operator with nullptr - * @return optional& - The reference to this object - */ - optional& operator=(std::nullptr_t) - { - reset(); - return *this; - } - - /** - * Call the destructor fot he contained value and mark this optional as valid - * - * @brief Reset the optional object - */ - void reset() - { - if( _valid ) { - ref().~T(); // cal destructor - } - _valid = false; - } - - /** - * Check if a contained value is less than b contained value - * - * @brief Less than operator - * @param a - First object to compare - * @param b - Second object to compare - * @return true - if a contained value is less than b contained value - * @return false - otherwise - */ - friend bool operator < ( const optional a, optional b ) - { - if( a.valid() && b.valid() ) return *a < *b; - return a.valid() < b.valid(); - } - - /** - * Check if a contained value is equal to b contained value - * - * @brief Equality operator - * @param a - First object to compare - * @param b - Second object to compare - * @return true - if contained value is equal to b contained value - * @return false - otherwise - */ - friend bool operator == ( const optional a, optional b ) - { - if( a.valid() && b.valid() ) return *a == *b; - return a.valid() == b.valid(); - } - - /** - * Serialize an optional object - * - * @brief Serialize an optional object - * @param ds - The stream to write - * @param op - The value to serialize - * @tparam Stream - Type of datastream - * @return eosio::datastream& - Reference to the datastream - */ - template - friend inline eosio::datastream& operator>> (eosio::datastream& ds, optional& op) - { - char valid = 0; - ds >> valid; - if (valid) { - op._valid = true; - ds >> *op; - } - return ds; - } - - /** - * Deserialize an optional object - * - * @brief Deserialize an optional object - * @param ds - The stream to read - * @param op - The destination for deserialized value - * @tparam Stream - Type of datastream - * @return eosio::datastream& - Reference to the datastream - */ - template - friend inline eosio::datastream& operator<< (eosio::datastream& ds, const optional& op) - { - char valid = op._valid; - ds << valid; - if (valid) ds << *op; - return ds; - } - - private: - template friend class optional; - T& ref() { return *ptr(); } - const T& ref()const { return *ptr(); } - T* ptr() { return reinterpret_cast(&_value); } - const T* ptr()const { return reinterpret_cast(&_value); } - - bool _valid; - storage_type _value; - - }; - - /** - * Check equality between two optional object that shares same type of contained value - * - * @brief Equality Operator - * @tparam T - Type of contained value of the optional objects - * @param left - First object to be compared - * @param right - Second object to be compared - * @return true - if both optional objects are equal - * @return false - */ - template - bool operator == ( const optional& left, const optional& right ) { - return (!left == !right) || (!!left && *left == *right); - } - - /** - * Check equality between an optional object with another object - * - * @brief Equality Operator - * @tparam T - Type of contained value of the optional object - * @tparam U - Type of the other object to be compared - * @param left - First object to be compared - * @param u - Second object to be compared - * @return true - if the optional objects contained value is equal with the compared object - * @return false - */ - template - bool operator == ( const optional& left, const U& u ) { - return !!left && *left == u; - } - - /** - * Check inequality between two optional object that shares same type of contained value - * - * @brief Inquality Operator - * @tparam T - Type of contained value of the optional objects - * @param left - First object to be compared - * @param right - Second object to be compared - * @return true - if both optional objects are unequal - * @return false - */ - template - bool operator != ( const optional& left, const optional& right ) { - return (!left != !right) || (!!left && *left != *right); - } - - /** - * Check inequality between an optional object with another object - * - * @brief Inqquality Operator - * @tparam T - Type of contained value of the optional object - * @tparam U - Type of the other object to be compared - * @param left - First object to be compared - * @param u - Second object to be compared - * @return true - if the optional objects contained value is unequal with the compared object - * @return false - */ - template - bool operator != ( const optional& left, const U& u ) { - return !left || *left != u; - } -///@} optional -} // namespace eosio diff --git a/contracts/eosiolib/permission.h b/contracts/eosiolib/permission.h deleted file mode 100644 index 743b499bca8..00000000000 --- a/contracts/eosiolib/permission.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include - -extern "C" { - /** - * @brief Checks if a transaction is authorized by a provided set of keys and permissions - * - * @param trx_data - pointer to the start of the serialized transaction - * @param trx_size - size (in bytes) of the serialized transaction - * @param pubkeys_data - pointer to the start of the serialized vector of provided public keys - * @param pubkeys_size - size (in bytes) of serialized vector of provided public keys (can be 0 if no public keys are to be provided) - * @param perms_data - pointer to the start of the serialized vector of provided permissions (empty permission name acts as wildcard) - * @param perms_size - size (in bytes) of the serialized vector of provided permissions - * - * @return 1 if the transaction is authorized, 0 otherwise - */ - int32_t - check_transaction_authorization( const char* trx_data, uint32_t trx_size, - const char* pubkeys_data, uint32_t pubkeys_size, - const char* perms_data, uint32_t perms_size - ); - - /** - * @brief Checks if a permission is authorized by a provided delay and a provided set of keys and permissions - * - * @param account - the account owner of the permission - * @param permission - the name of the permission to check for authorization - * @param pubkeys_data - pointer to the start of the serialized vector of provided public keys - * @param pubkeys_size - size (in bytes) of serialized vector of provided public keys (can be 0 if no public keys are to be provided) - * @param perms_data - pointer to the start of the serialized vector of provided permissions (empty permission name acts as wildcard) - * @param perms_size - size (in bytes) of the serialized vector of provided permissions - * @param delay_us - the provided delay in microseconds (cannot exceed INT64_MAX) - * - * @return 1 if the permission is authorized, 0 otherwise - */ - int32_t - check_permission_authorization( account_name account, - permission_name permission, - const char* pubkeys_data, uint32_t pubkeys_size, - const char* perms_data, uint32_t perms_size, - uint64_t delay_us - ); - - /** - * @brief Returns the last used time of a permission - * - * @param account - the account owner of the permission - * @param permission - the name of the permission - * - * @return the last used time (in microseconds since Unix epoch) of the permission - */ - int64_t get_permission_last_used( account_name account, permission_name permission ); - - - /** - * @brief Returns the creation time of an account - * - * @param account - the account - * - * @return the creation time (in microseconds since Unix epoch) of the account - */ - int64_t get_account_creation_time( account_name account ); - -} diff --git a/contracts/eosiolib/permission.hpp b/contracts/eosiolib/permission.hpp deleted file mode 100644 index 668fa79bff9..00000000000 --- a/contracts/eosiolib/permission.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include - -#include -#include - -namespace eosio { - - /** - * @brief Checks if a transaction is authorized by a provided set of keys and permissions - * - * @param trx - the transaction for which to check authorizations - * @param provided_permissions - the set of permissions which have authorized the transaction (empty permission name acts as wildcard) - * @param provided_keys - the set of public keys which have authorized the transaction - * - * @return whether the transaction was authorized by provided keys and permissions - */ - bool - check_transaction_authorization( const transaction& trx, - const std::set& provided_permissions , - const std::set& provided_keys = std::set() - ) - { - bytes packed_trx = pack(trx); - - bytes packed_keys; - auto nkeys = provided_keys.size(); - if( nkeys > 0 ) { - packed_keys = pack(provided_keys); - } - - bytes packed_perms; - auto nperms = provided_permissions.size(); - if( nperms > 0 ) { - packed_perms = pack(provided_permissions); - } - - auto res = ::check_transaction_authorization( packed_trx.data(), - packed_trx.size(), - (nkeys > 0) ? packed_keys.data() : (const char*)0, - (nkeys > 0) ? packed_keys.size() : 0, - (nperms > 0) ? packed_perms.data() : (const char*)0, - (nperms > 0) ? packed_perms.size() : 0 - ); - - return (res > 0); - } - - /** - * @brief Checks if a permission is authorized by a provided delay and a provided set of keys and permissions - * - * @param account - the account owner of the permission - * @param permission - the permission name to check for authorization - * @param provided_keys - the set of public keys which have authorized the transaction - * @param provided_permissions - the set of permissions which have authorized the transaction (empty permission name acts as wildcard) - * @param provided_delay_us - the provided delay in microseconds (cannot exceed INT64_MAX) - * - * @return whether the permission was authorized by provided delay, keys, and permissions - */ - bool - check_permission_authorization( account_name account, - permission_name permission, - const std::set& provided_keys, - const std::set& provided_permissions = std::set(), - uint64_t provided_delay_us = static_cast(std::numeric_limits::max()) - ) - { - bytes packed_keys; - auto nkeys = provided_keys.size(); - if( nkeys > 0 ) { - packed_keys = pack(provided_keys); - } - - bytes packed_perms; - auto nperms = provided_permissions.size(); - if( nperms > 0 ) { - packed_perms = pack(provided_permissions); - } - - auto res = ::check_permission_authorization( account, - permission, - (nkeys > 0) ? packed_keys.data() : (const char*)0, - (nkeys > 0) ? packed_keys.size() : 0, - (nperms > 0) ? packed_perms.data() : (const char*)0, - (nperms > 0) ? packed_perms.size() : 0, - provided_delay_us - ); - - return (res > 0); - } - -} diff --git a/contracts/eosiolib/print.h b/contracts/eosiolib/print.h deleted file mode 100644 index ab7dfcc8ade..00000000000 --- a/contracts/eosiolib/print.h +++ /dev/null @@ -1,168 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - /** - * @defgroup consoleapi Console API - * @brief Defines APIs to log/print text messages - * @ingroup contractdev - * - */ - - /** - * @defgroup consolecapi Console C API - * @brief Defnes %C API to log/print text messages - * @ingroup consoleapi - * @{ - */ - - /** - * Prints string - * @brief Prints string - * @param cstr - a null terminated string - * - * Example: -* - * @code - * prints("Hello World!"); // Output: Hello World! - * @endcode - */ - void prints( const char* cstr ); - - /** - * Prints string up to given length - * @brief Prints string - * @param cstr - pointer to string - * @param len - len of string to be printed - * - * Example: -* - * @code - * prints_l("Hello World!", 5); // Output: Hello - * @endcode - */ - void prints_l( const char* cstr, uint32_t len); - - /** - * Prints value as a 64 bit signed integer - * @brief Prints value as a 64 bit signed integer - * @param value of 64 bit signed integer to be printed - * - * Example: -* - * @code - * printi(-1e+18); // Output: -1000000000000000000 - * @endcode - */ - void printi( int64_t value ); - - /** - * Prints value as a 64 bit unsigned integer - * @brief Prints value as a 64 bit unsigned integer - * @param value of 64 bit unsigned integer to be printed - * - * Example: -* - * @code - * printui(1e+18); // Output: 1000000000000000000 - * @endcode - */ - void printui( uint64_t value ); - - /** - * Prints value as a 128 bit signed integer - * @brief Prints value as a 128 bit signed integer - * @param value is a pointer to the 128 bit signed integer to be printed - * - * Example: -* - * @code - * int128_t large_int(-87654323456); - * printi128(&large_int); // Output: -87654323456 - * @endcode - */ - void printi128( const int128_t* value ); - - /** - * Prints value as a 128 bit unsigned integer - * @brief Prints value as a 128 bit unsigned integer - * @param value is a pointer to the 128 bit unsigned integer to be printed - * - * Example: -* - * @code - * uint128_t large_int(87654323456); - * printui128(&large_int); // Output: 87654323456 - * @endcode - */ - void printui128( const uint128_t* value ); - - /** - * Prints value as single-precision floating point number - * @brief Prints value as single-precision floating point number (i.e. float) - * @param value of float to be printed - * - * Example: -* - * @code - * float value = 5.0 / 10.0; - * printsf(value); // Output: 0.5 - * @endcode - */ - void printsf(float value); - - /** - * Prints value as double-precision floating point number - * @brief Prints value as double-precision floating point number (i.e. double) - * @param value of double to be printed - * - * Example: -* - * @code - * double value = 5.0 / 10.0; - * printdf(value); // Output: 0.5 - * @endcode - */ - void printdf(double value); - - /** - * Prints value as quadruple-precision floating point number - * @brief Prints value as quadruple-precision floating point number (i.e. long double) - * @param value is a pointer to the long double to be printed - * - * Example: -* - * @code - * long double value = 5.0 / 10.0; - * printqf(value); // Output: 0.5 - * @endcode - */ - void printqf(const long double* value); - - /** - * Prints a 64 bit names as base32 encoded string - * @brief Prints a 64 bit names as base32 encoded string - * @param name - 64 bit name to be printed - * - * Example: - * @code - * printn(N(abcde)); // Output: abcde - * @endcode - */ - void printn( uint64_t name ); - - /** - */ - void printhex( const void* data, uint32_t datalen ); - - /// @} -#ifdef __cplusplus -} -#endif diff --git a/contracts/eosiolib/print.hpp b/contracts/eosiolib/print.hpp deleted file mode 100644 index 84bdf263aa3..00000000000 --- a/contracts/eosiolib/print.hpp +++ /dev/null @@ -1,321 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include -#include -#include -#include -#include - -namespace eosio { - - static_assert( sizeof(long) == sizeof(int), "unexpected size difference" ); - - /** - * Prints string - * - * @brief Prints string - * @param ptr - a null terminated string - */ - inline void print( const char* ptr ) { - prints(ptr); - } - - inline void print( const std::string& s) { - prints_l( s.c_str(), s.size() ); - } - - inline void print( std::string& s) { - prints_l( s.c_str(), s.size() ); - } - - inline void print( const char c ) { - prints_l( &c, 1 ); - } - - /** - * Prints signed integer - * - * @brief Prints signed integer as a 64 bit signed integer - * @param num to be printed - */ - inline void print( int num ) { - printi(num); - } - - /** - * Prints 32 bit signed integer - * - * @brief Prints 32 bit signed integer as a 64 bit signed integer - * @param num to be printed - */ - inline void print( int32_t num ) { - printi(num); - } - - /** - * Prints 64 bit signed integer - * - * @brief Prints 64 bit signed integer as a 64 bit signed integer - * @param num to be printed - */ - inline void print( int64_t num ) { - printi(num); - } - - - /** - * Prints unsigned integer - * - * @brief Prints unsigned integer as a 64 bit unsigned integer - * @param num to be printed - */ - inline void print( unsigned int num ) { - printui(num); - } - - /** - * Prints 32 bit unsigned integer - * - * @brief Prints 32 bit unsigned integer as a 64 bit unsigned integer - * @param num to be printed - */ - inline void print( uint32_t num ) { - printui(num); - } - - /** - * Prints 64 bit unsigned integer - * - * @brief Prints 64 bit unsigned integer as a 64 bit unsigned integer - * @param num to be printed - */ - inline void print( uint64_t num ) { - printui(num); - } - - /** - * Prints 128 bit signed integer - * - * @brief Prints 128 bit signed integer - * @param num to be printed - */ - inline void print( int128_t num ) { - printi128(&num); - } - - /** - * Prints 128 bit unsigned integer - * - * @brief Prints 128 bit unsigned integer - * @param num to be printed - */ - inline void print( uint128_t num ) { - printui128(&num); - } - - - /** - * Prints single-precision floating point number - * - * @brief Prints single-precision floating point number (i.e. float) - * @param num to be printed - */ - inline void print( float num ) { printsf( num ); } - - /** - * Prints double-precision floating point number - * - * @brief Prints double-precision floating point number (i.e. double) - * @param num to be printed - */ - inline void print( double num ) { printdf( num ); } - - /** - * Prints quadruple-precision floating point number - * - * @brief Prints quadruple-precision floating point number (i.e. long double) - * @param num to be printed - */ - inline void print( long double num ) { printqf( &num ); } - - - /** - * Prints fixed_key as a hexidecimal string - * - * @brief Prints fixed_key as a hexidecimal string - * @param val to be printed - */ - template - inline void print( const fixed_key& val ) { - auto arr = val.extract_as_byte_array(); - prints("0x"); - printhex(static_cast(arr.data()), arr.size()); - } - - /** - * Prints fixed_key as a hexidecimal string - * - * @brief Prints fixed_key as a hexidecimal string - * @param val to be printed - */ - template - inline void print( fixed_key& val ) { - print(static_cast&>(val)); - } - - /** - * Prints a 64 bit names as base32 encoded string - * - * @brief Prints a 64 bit names as base32 encoded string - * @param name 64 bit name to be printed - */ - inline void print( name name ) { - printn(name.value); - } - - /** - * Prints bool - * - * @brief Prints bool - * @param val to be printed - */ - inline void print( bool val ) { - prints(val?"true":"false"); - } - - - /** - * Prints class object - * - * @brief Prints class object - * @param t to be printed - * @pre T must implements print() function - */ - template - inline void print( T&& t ) { - t.print(); - } - - /** - * Prints null terminated string - * - * @brief Prints null terminated string - * @param s null terminated string to be printed - */ - inline void print_f( const char* s ) { - prints(s); - } - - /** - * @defgroup consolecppapi Console C++ API - * @ingroup consoleapi - * @brief Defines C++ wrapper to log/print text messages - * - * This API uses C++ variadic templates and type detection to - * make it easy to print any native type. You can even overload - * the `print()` method for your own custom types. - * - * **Example:** - * ``` - * print( "hello world, this is a number: ", 5 ); - * ``` - * - * @section override Overriding Print for your Types - * - * There are two ways to overload print: - * 1. implement void print( const T& ) - * 2. implement T::print()const - * - * @{ - */ - - - /** - * Prints formatted string. It behaves similar to C printf/ - * - * @brief Prints formatted string - * @tparam Arg - Type of the value used to replace the format specifier - * @tparam Args - Type of the value used to replace the format specifier - * @param s - Null terminated string with to be printed (it can contains format specifier) - * @param val - The value used to replace the format specifier - * @param rest - The values used to replace the format specifier - * - * Example: - * @code - * print_f("Number of apples: %", 10); - * @endcode - */ - template - inline void print_f( const char* s, Arg val, Args... rest ) { - while ( *s != '\0' ) { - if ( *s == '%' ) { - print( val ); - print_f( s+1, rest... ); - return; - } - prints_l( s, 1 ); - s++; - } - } - - /** - * Print out value / list of values - * @brief Print out value / list of values - * @param a - The value to be printed - * @param args - The other values to be printed - * - * Example: -* - * @code - * const char *s = "Hello World!"; - * uint64_t unsigned_64_bit_int = 1e+18; - * uint128_t unsigned_128_bit_int (87654323456); - * uint64_t string_as_unsigned_64_bit = N(abcde); - * print(s , unsigned_64_bit_int, unsigned_128_bit_int, string_as_unsigned_64_bit); - * // Ouput: Hello World!100000000000000000087654323456abcde - * @endcode - */ - template - void print( Arg&& a, Args&&... args ) { - print(std::forward(a)); - print(std::forward(args)...); - } - - /** - * Simulate C++ style streams - */ - class iostream {}; - - /** - * Overload c++ iostream - * @brief Overload c++ iostream - * @param out - Output strem - * @param v - The value to be printed - * @return iostream& - Reference to the input output stream - * - * Example: -* - * @code - * const char *s = "Hello World!"; - * uint64_t unsigned_64_bit_int = 1e+18; - * uint128_t unsigned_128_bit_int (87654323456); - * uint64_t string_as_unsigned_64_bit = N(abcde); - * std::out << s << " " << unsigned_64_bit_int << " " << unsigned_128_bit_int << " " << string_as_unsigned_64_bit; - * // Output: Hello World! 1000000000000000000 87654323456 abcde - * @endcode - */ - template - inline iostream& operator<<( iostream& out, const T& v ) { - print( v ); - return out; - } - - static iostream cout; - - /// @} consolecppapi - - -} diff --git a/contracts/eosiolib/privileged.h b/contracts/eosiolib/privileged.h deleted file mode 100644 index 8943a09db23..00000000000 --- a/contracts/eosiolib/privileged.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * @defgroup privilegedapi Privileged API - * @ingroup systemapi - * @brief Defines an API for accessing configuration of the chain that can only be done by privileged accounts - */ - - /** - * @defgroup privilegedcapi Privileged C API - * @ingroup privilegedapi - * @brief Defines %C Privileged API - * - * @{ - */ - - /** - * @brief Get the resource limits of an account - * Get the resource limits of an account - * @param account - name of the account whose resource limit to get - * @param ram_bytes - pointer to `int64_t` to hold retrieved ram limit in absolute bytes - * @param net_weight - pointer to `int64_t` to hold net limit - * @param cpu_weight - pointer to `int64_t` to hold cpu limit - */ - void get_resource_limits( account_name account, int64_t* ram_bytes, int64_t* net_weight, int64_t* cpu_weight ); - - /** - * @brief Set the resource limits of an account - * Set the resource limits of an account - * @param account - name of the account whose resource limit to be set - * @param ram_bytes - ram limit in absolute bytes - * @param net_weight - fractionally proportionate net limit of available resources based on (weight / total_weight_of_all_accounts) - * @param cpu_weight - fractionally proportionate cpu limit of available resources based on (weight / total_weight_of_all_accounts) - */ - void set_resource_limits( account_name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ); - - /** - * Proposes a schedule change, once the block that contains the proposal becomes irreversible, the schedule is promoted to "pending" automatically. Once the block that promotes the schedule is irreversible, the schedule will become "active" - * @param producer_data - packed data of produce_keys in the appropriate producer schedule order - * @param producer_data_size - size of the data buffer - * - * @return -1 if proposing a new producer schedule was unsuccessful, otherwise returns the version of the new proposed schedule - */ - int64_t set_proposed_producers( char *producer_data, uint32_t producer_data_size ); - - /** - * @brief Set new active producers - * Set new active producers. Producers will only be activated once the block which starts the next round is irrreversible - * @param producer_data - pointer to producer schedule packed as bytes - * @param producer_data_size - size of the packed producer schedule - * @pre `producer_data` is a valid pointer to a range of memory at least `producer_data_size` bytes long that contains serialized produced schedule data - */ - void set_active_producers( char *producer_data, uint32_t producer_data_size ); - /** - * @brief Check if an account is privileged - * Check if an account is privileged - * @param account - name of the account to be checked - * @return true if the account is privileged - * @return false if the account is not privileged - */ - bool is_privileged( account_name account ); - - /** - * @brief Set the privileged status of an account - * Set the privileged status of an account - * @param account - name of the account whose privileged account to be set - * @param is_priv - privileged status - */ - void set_privileged( account_name account, bool is_priv ); - - /** - * @brief Set the blockchain parameters - * Set the blockchain parameters - * @param data - pointer to blockchain parameters packed as bytes - * @param datalen - size of the packed blockchain parameters - * @pre `data` is a valid pointer to a range of memory at least `datalen` bytes long that contains packed blockchain params data - */ - void set_blockchain_parameters_packed(char* data, uint32_t datalen); - - /** - * @brief Retrieve the blolckchain parameters - * Retrieve the blolckchain parameters - * @param data - output buffer of the blockchain parameters, only retrieved if sufficent size to hold packed data. - * @param datalen - size of the data buffer, 0 to report required size. - * @return size of the blockchain parameters - * @pre `data` is a valid pointer to a range of memory at least `datalen` bytes long - * @post `data` is filled with packed blockchain parameters - */ - uint32_t get_blockchain_parameters_packed(char* data, uint32_t datalen); - - /** - * @brief Activate new feature - * Activate new feature - * @param f - name (identifier) of the feature to be activated - */ - void activate_feature( int64_t f ); - - ///@ } privilegedcapi -#ifdef __cplusplus -} -#endif diff --git a/contracts/eosiolib/privileged.hpp b/contracts/eosiolib/privileged.hpp deleted file mode 100644 index 3091acf8b3b..00000000000 --- a/contracts/eosiolib/privileged.hpp +++ /dev/null @@ -1,162 +0,0 @@ -#pragma once -#include "privileged.h" -#include "serialize.hpp" -#include "types.h" - -namespace eosio { - - /** - * @defgroup privilegedcppapi Privileged C++ API - * @ingroup privilegedapi - * @brief Defines C++ Privileged API - * - * @{ - */ - - /** - * Tunable blockchain configuration that can be changed via consensus - * - * @brief Tunable blockchain configuration that can be changed via consensus - */ - struct blockchain_parameters { - - uint64_t max_block_net_usage; - - uint32_t target_block_net_usage_pct; - - uint32_t max_transaction_net_usage; - - /** - * The base amount of net usage billed for a transaction to cover incidentals - * @brief The base amount of net usage billed for a transaction to cover incidentals - */ - uint32_t base_per_transaction_net_usage; - - uint32_t net_usage_leeway; - - uint32_t context_free_discount_net_usage_num; - - uint32_t context_free_discount_net_usage_den; - - uint32_t max_block_cpu_usage; - - uint32_t target_block_cpu_usage_pct; - - uint32_t max_transaction_cpu_usage; - - uint32_t min_transaction_cpu_usage; - - - /** - * The numerator for the discount on cpu usage for CFA's - * - * @brief The numerator for the discount on cpu usage for CFA's - */ - uint64_t context_free_discount_cpu_usage_num; - - /** - * The denominator for the discount on cpu usage for CFA's - * - * @brief The denominator for the discount on cpu usage for CFA's - - */ - uint64_t context_free_discount_cpu_usage_den; - - /** - * Maximum lifetime of a transacton - * - * @brief Maximum lifetime of a transacton - */ - uint32_t max_transaction_lifetime; - - uint32_t deferred_trx_expiration_window; - - uint32_t max_transaction_delay; - - /** - * Maximum size of inline action - * - * @brief Maximum size of inline action - */ - uint32_t max_inline_action_size; - - /** - * Maximum depth of inline action - * - * @brief Maximum depth of inline action - */ - uint16_t max_inline_action_depth; - - /** - * Maximum authority depth - * - * @brief Maximum authority depth - */ - uint16_t max_authority_depth; - - - EOSLIB_SERIALIZE( blockchain_parameters, - (max_block_net_usage)(target_block_net_usage_pct) - (max_transaction_net_usage)(base_per_transaction_net_usage)(net_usage_leeway) - (context_free_discount_net_usage_num)(context_free_discount_net_usage_den) - - (max_block_cpu_usage)(target_block_cpu_usage_pct) - (max_transaction_cpu_usage)(min_transaction_cpu_usage) - - (max_transaction_lifetime)(deferred_trx_expiration_window)(max_transaction_delay) - (max_inline_action_size)(max_inline_action_depth)(max_authority_depth) - ) - }; - - /** - * @brief Set the blockchain parameters - * Set the blockchain parameters - * @param params - New blockchain parameters to set - */ - void set_blockchain_parameters(const eosio::blockchain_parameters& params); - - /** - * @brief Retrieve the blolckchain parameters - * Retrieve the blolckchain parameters - * @param params - It will be replaced with the retrieved blockchain params - */ - void get_blockchain_parameters(eosio::blockchain_parameters& params); - - ///@} priviledgedcppapi - - /** - * @defgroup producertype Producer Type - * @ingroup types - * @brief Defines producer type - * - * @{ - */ - - /** - * Maps producer with its signing key, used for producer schedule - * - * @brief Maps producer with its signing key - */ - struct producer_key { - - /** - * Name of the producer - * - * @brief Name of the producer - */ - account_name producer_name; - - /** - * Block signing key used by this producer - * - * @brief Block signing key used by this producer - */ - public_key block_signing_key; - - friend bool operator < ( const producer_key& a, const producer_key& b ) { - return a.producer_name < b.producer_name; - } - - EOSLIB_SERIALIZE( producer_key, (producer_name)(block_signing_key) ) - }; -} diff --git a/contracts/eosiolib/producer_schedule.hpp b/contracts/eosiolib/producer_schedule.hpp deleted file mode 100644 index 8fd2a26c973..00000000000 --- a/contracts/eosiolib/producer_schedule.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include - -#include - -namespace eosio { - - /** - * Defines both the order, account name, and signing keys of the active set of producers. - * - * @brief Defines both the order, account name, and signing keys of the active set of producers. - */ - struct producer_schedule { - /** - * Version number of the schedule. It is sequentially incrementing version number - * - * @brief Version number of the schedule - */ - uint32_t version; - - /** - * List of producers for this schedule, including its signing key - * - * @brief List of producers for this schedule, including its signing key - */ - std::vector producers; - }; - - /// @} producertype -} /// namespace eosio diff --git a/contracts/eosiolib/public_key.hpp b/contracts/eosiolib/public_key.hpp deleted file mode 100644 index e7061ef74c9..00000000000 --- a/contracts/eosiolib/public_key.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include -#include - -namespace eosio { - - /** - * @defgroup publickeytype Public Key Type - * @ingroup types - * @brief Specifies public key type - * - * @{ - */ - - /** - * EOSIO Public Key - * @brief EOSIO Public Key - */ - struct public_key { - /** - * Type of the public key, could be either K1 or R1 - * @brief Type of the public key - */ - unsigned_int type; - - /** - * Bytes of the public key - * - * @brief Bytes of the public key - */ - std::array data; - - friend bool operator == ( const public_key& a, const public_key& b ) { - return std::tie(a.type,a.data) == std::tie(b.type,b.data); - } - friend bool operator != ( const public_key& a, const public_key& b ) { - return std::tie(a.type,a.data) != std::tie(b.type,b.data); - } - EOSLIB_SERIALIZE( public_key, (type)(data) ) - }; - -} - -/// @} publickeytype diff --git a/contracts/eosiolib/reflect.hpp b/contracts/eosiolib/reflect.hpp deleted file mode 100644 index bea480ffc6e..00000000000 --- a/contracts/eosiolib/reflect.hpp +++ /dev/null @@ -1,186 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -namespace eosio { - template - struct reflector { - typedef std::false_type is_reflected; - typedef std::false_type is_enum; - }; - -} /// eosio - - - -#define EOSLIB_REFLECT_VISIT_BASE(r, visitor, base) \ - eosio::reflector::visit( visitor ); - -#define EOSLIB_REFLECT_VISIT2_BASE(r, visitor, base) \ - eosio::reflector::visit( t, forward(visitor) ); - - -#define EOSLIB_REFLECT_VISIT_MEMBER( r, visitor, elem ) \ -{ typedef decltype((static_cast(nullptr))->elem) member_type; \ - visitor( &type::elem ); \ -} - -#define EOSLIB_REFLECT_VISIT2_MEMBER( r, visitor, elem ) \ -{ typedef decltype((static_cast(nullptr))->elem) member_type; \ - visitor( t.elem ); \ -} - - -#define EOSLIB_REFLECT_BASE_MEMBER_COUNT( r, OP, elem ) \ - OP eosio::reflector::total_member_count - -#define EOSLIB_REFLECT_MEMBER_COUNT( r, OP, elem ) \ - OP 1 - -#define EOSLIB_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ -template\ -static inline void visit( Visitor&& v ) { \ - BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_VISIT_BASE, v, INHERITS ) \ - BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_VISIT_MEMBER, v, MEMBERS ) \ -} \ -template\ -static inline void visit( const type& t, Visitor&& v ) { \ - BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_VISIT2_BASE, v, INHERITS ) \ - BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_VISIT2_MEMBER, v, MEMBERS ) \ -} \ -template\ -static inline void visit( type& t, Visitor&& v ) { \ - BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_VISIT2_BASE, v, INHERITS ) \ - BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_VISIT2_MEMBER, v, MEMBERS ) \ -} - -#define EOSLIB_REFLECT_DERIVED_IMPL_EXT( TYPE, INHERITS, MEMBERS ) \ -template\ -void eosio::reflector::visit( Visitor&& v ) { \ - BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_VISIT_BASE, v, INHERITS ) \ - BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_VISIT_MEMBER, v, MEMBERS ) \ -} - - -/** - * @addtogroup serializecpp - * @{ - */ - -/** - * Perform class reflection - * - * @brief Specializes eosio::reflector for TYPE - * @param TYPE - the class template to be reflected - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - * - * @see EOSLIB_REFLECT_DERIVED - */ -#define EOSLIB_REFLECT( TYPE, MEMBERS ) \ - EOSLIB_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) - -/** - * Perform class template reflection - * - * @brief Perform class template reflection - * @param TEMPLATE_ARGS - a sequence of template args. (args1)(args2)(args3) - * @param TYPE - the class template to be reflected - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - */ -#define EOSLIB_REFLECT_TEMPLATE( TEMPLATE_ARGS, TYPE, MEMBERS ) \ - EOSLIB_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) - -/** - * Perform class reflection on empty class - * - * @brief Perform class reflection on empty class - * @param TYPE - the class to be reflected - */ -#define EOSLIB_REFLECT_EMPTY( TYPE ) \ - EOSLIB_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, BOOST_PP_SEQ_NIL ) - -/** - * Perform forward declaration of class reflection - * - * @brief Perform forward declaration of class reflection - * @param TYPE - the class to be reflected - */ -#define EOSLIB_REFLECT_FWD( TYPE ) \ -namespace eosio { \ - template<> struct reflector {\ - typedef TYPE type; \ - typedef eosio::true_type is_reflected; \ - enum member_count_enum { \ - local_member_count = BOOST_PP_SEQ_SIZE(MEMBERS), \ - total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ - }; \ - template static void visit( Visitor&& v ); \ - template static void visit( const type& t, Visitor&& v ); \ - template static void visit( type& t, Visitor&& v ); \ - }; } - -///@} - -#define EOSLIB_REFLECT_DERIVED_IMPL( TYPE, MEMBERS ) \ - EOSLIB_REFLECT_IMPL_DERIVED_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) - -#define EOSLIB_REFLECT_IMPL( TYPE, MEMBERS ) \ - EOSLIB_REFLECT_DERIVED_IMPL_EXT( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) - - -/** - * @addtogroup serializecpp - * @{ - */ - -/** - * Perform class reflection where TYPE inherits other reflected classes - * - * @brief Specializes eosio::reflector for TYPE where - * type inherits other reflected classes - * - * @param TYPE - the class to be reflected - * @param INHERITS - a sequence of base class names (basea)(baseb)(basec) - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - */ -#define EOSLIB_REFLECT_DERIVED( TYPE, INHERITS, MEMBERS ) \ -namespace eosio { \ -template<> struct reflector {\ - typedef TYPE type; \ - typedef eosio::true_type is_reflected; \ - typedef eosio::false_type is_enum; \ - enum member_count_enum { \ - local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_COUNT, +, MEMBERS ),\ - total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ - }; \ - EOSLIB_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ -}; } - -/** - * Perform class template reflection where TYPE inherits other reflected classes - * - * @brief Perform class template reflection where TYPE inherits other reflected classes - * - * @param TEMPLATE_ARGS - a sequence of template args. (args1)(args2)(args3) - * @param TYPE - the class to be reflected - * @param INHERITS - a sequence of base class names (basea)(baseb)(basec) - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - */ -#define EOSLIB_REFLECT_DERIVED_TEMPLATE( TEMPLATE_ARGS, TYPE, INHERITS, MEMBERS ) \ -namespace eosio { \ -template struct reflector {\ - typedef TYPE type; \ - typedef eosio::true_type is_defined; \ - typedef eosio::false_type is_enum; \ - enum member_count_enum { \ - local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_COUNT, +, MEMBERS ),\ - total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ - }; \ - EOSLIB_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ -}; } - - -///@} diff --git a/contracts/eosiolib/rpc.dox b/contracts/eosiolib/rpc.dox deleted file mode 100644 index 047250276eb..00000000000 --- a/contracts/eosiolib/rpc.dox +++ /dev/null @@ -1,544 +0,0 @@ -/** -@defgroup eosiorpc RPC Interface -@brief Describes how to interface with eosd over HTTP RPC - -@section tableofcontent Table Of Contents -- [Configuration](#configuration) -- [Chain API](#chainrpc) - - [get_info](#v1chaingetinfo) - - [get_block](#v1chaingetblock) - - [get_account](#v1chaingetaccount) - - [get_code](#v1chaingetcode) - - [get_table_rows](#v1chaingettablerows) - - [abi_json_to_bin](#v1chainabijsontobin) - - [abi_bin_to_json](#v1chainabibintojson) - - [push_transaction](#v1chainpushtransaction) - - [push_transactions](#v1chainpushtransactions) - - [get_required_keys](#v1chaingetrequiredkeys) -- [Wallet API](#walletrpc) - - [wallet_create](#v1walletcreate) - - [wallet_open](#v1walletopen) - - [wallet_lock](#v1walletlock) - - [wallet_lock_all](#v1walletlockall) - - [wallet_import_key](#v1walletimportkey) - - [wallet_list](#v1walletlist) - - [wallet_list_keys](#v1walletlistkeys) - - [wallet_get_public_keys](#v1walletgetpublickeys) - - [wallet_set_timeout](#v1walletsettimeout) - - [wallet_sign_trx](#v1walletsigntrx) - -@section configuration Configuration - -`eosd` uses a REST RPC interface where plugins can register their own endpoints with the API server. This page -will explain how to use some of the APIs to get information about the blockchain and send transactions. - -Before you can query `eosd` you must first enable the necessary API plugin(s). Depending on which API you want to enable, add the following line to your `eosd`'s `config.ini`: -``` -plugin = eosio::chain_api_plugin // Enable Chain API -plugin = eosio::wallet_api_plugin // Enable Wallet API -``` -Alternatively, for Wallet API, you can also have the wallet functionality separate from `eosd`, by running `eos-walletd` separately. - -For the following guide, we will assume that we have `eosd` running on `127.0.0.1:8888` (Chain API Plugin enabled, Wallet API Plugin disabled) and `eos-walletd` running on `127.0.0.1:8889`. - -=== - -@section chainrpc Chain API - - -@subsection v1chaingetinfo get_info - -Get latest information related to a node - -@subsubsection examplegetinfo Example get_info Usage - -``` -curl http://127.0.0.1:8888/v1/chain/get_info -``` - -@subsubsection examplegetinforesult Example get_info Result - -``` -{ - "server_version": "b2eb1667", - "head_block_num": 259590, - "last_irreversible_block_num": 259573, - "head_block_id": "0003f60677f3707f0704f16177bf5f007ebd45eb6efbb749fb1c468747f72046", - "head_block_time": "2017-12-10T17:05:36", - "head_block_producer": "initp", - "recent_slots": "1111111111111111111111111111111111111111111111111111111111111111", - "participation_rate": "1.00000000000000000" -} -``` - -@subsection v1chaingetblock get_block - -Get information related to a block. - -@subsubsection examplegetblock Example get_block Usage -``` -$ curl http://127.0.0.1:8888/v1/chain/get_block -X POST -d '{"block_num_or_id":5}' -$ curl http://127.0.0.1:8888/v1/chain/get_block -X POST -d '{"block_num_or_id":0000000445a9f27898383fd7de32835d5d6a978cc14ce40d9f327b5329de796b}' -``` - -@subsubsection examplegetblockresult Example get_block Result -``` -{ - "previous": "0000000445a9f27898383fd7de32835d5d6a978cc14ce40d9f327b5329de796b", - "timestamp": "2017-07-18T20:16:36", - "transaction_merkle_root": "0000000000000000000000000000000000000000000000000000000000000000", - "producer": "initf", - "producer_changes": [ ], - "producer_signature": "204cb94b3186c3b4a7f88be4e9db9f8af2ffdb7ef0f27a065c8177a5fcfacf876f684e59c39fb009903c0c59220b147bb07f1144df1c65d26c57b534a76dd29073", - "cycles": [ ], - "id":"000000050c0175cbf218a70131ddc3c3fab8b6e954edef77e0bfe7c36b599b1d", - "block_num":5, - "ref_block_prefix":27728114 -} -``` - - -@subsection v1chaingetaccount get_account - -Get information related to an account. - -@subsubsection examplegetaccount Example get_account Usage -``` -$ curl http://127.0.0.1:8888/v1/chain/get_account -X POST -d '{"account_name":"inita"}' -``` - -@subsubsection examplegetaccountresult Example get_account Result -``` -{ - "name": "inita", - "eos_balance": "999998.9574 EOS", - "staked_balance": "0.0000 EOS", - "unstaking_balance": "0.0000 EOS", - "last_unstaking_time": "2106-02-07T06:28:15", - "permissions": [ - { - "name": "active", - "parent": "owner", - "required_auth": { - "threshold": 1, - "keys": [ - { - "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "weight": 1 - } - ], - "accounts": [] - } - }, - { - "name": "owner", - "parent": "owner", - "required_auth": { - "threshold": 1, - "keys": [ - { - "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", - "weight": 1 - } - ], - "accounts": [] - } - } - ] -} -``` - - -@subsection v1chaingetcode get_code - -Fetch smart contract code. - -@subsubsection examplegetcode Example get_code Usage -``` -$ curl http://127.0.0.1:8888/v1/chain/get_code -X POST -d '{"account_name":"currency"}' -``` - -@subsubsection examplegetcoderesult Example get_code Result -``` -{ - "name":"currency", - "code_hash":"a1c8c84b4700c09c8edb83522237439e33cf011a4d7ace51075998bd002e04c9", - "wast":"(module\n (type $0 (func (param i64 i64 i32) (result i32)))\n ...truncated", - "abi": { - "types": [{ - "new_type_name": "account_name", - "type": "name" - } - ], - "structs": [{ - "name": "transfer", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"to", "type":"account_name"}, - {"name":"quantity", "type":"uint64"} - ] - },{ - "name": "account", - "base": "", - "fields": [ - {"name":"key", "type":"name"}, - {"name":"balance", "type":"uint64"} - ] - } - ], - "actions": [{ - "name": "transfer", - "type": "transfer" - } - ], - "tables": [{ - "name": "account", - "type": "account", - "index_type": "i64", - "key_names" : ["key"], - "key_types" : ["name"] - } - ] -} -``` - - -@subsection v1chaingettablerows get_table_rows - -Fetch smart contract data from an account. - -@subsubsection examplegettablerows get_table_rows Usage -``` -$ curl http://127.0.0.1:8888/v1/chain/get_table_rows -X POST -d '{"scope":"inita", "code":"currency", "table":"account", "json": true}' -$ curl http://127.0.0.1:8888/v1/chain/get_table_rows -X POST -d '{"scope":"inita", "code":"currency", "table":"account", "json": true, "lower_bound":0, "upper_bound":-1, "limit":10}' -``` - -@subsubsection examplegettablerowsresult Example get_table_rows Result -``` -{ - "rows": [ - { - "account": "account", - "balance": 1000 - } - ], - "more": false -} -``` - - -@subsection v1chaingeabijsontobin abi_json_to_bin - -Serialize json to binary hex. The resulting binary hex is usually used for the data field in [push_transaction](#v1chainpushtransaction). - -@subsubsection exampleabijsontobin Example abi_json_to_bin Usage -``` -$ curl http://127.0.0.1:8888/v1/chain/abi_json_to_bin -X POST -d '{"code":"currency", "action":"transfer", "args":{"from":"initb", "to":"initc", "quantity":1000}}' -``` - -@subsubsection exampleabijsontobinresult Example abi_json_to_bin Result -``` -{ - "binargs": "000000008093dd74000000000094dd74e803000000000000", - "required_scope": [], - "required_auth": [] -} -``` - - -@subsection v1chaingeabibintojson abi_bin_to_json - -Serialize back binary hex to json. - -@subsubsection exampleabibintojson Example abi_bin_to_json Usage -``` -$ curl http://127.0.0.1:8888/v1/chain/abi_bin_to_json -X POST -d '{"code":"currency", "action":"transfer", "binargs":"000000008093dd74000000000094dd74e803000000000000"}' -``` - -@subsubsection exampleabibintojsonresult Example abi_bin_to_json Result -``` -{ - "args": { - "from": "initb", - "to": "initc", - "quantity": 1000 - }, - "required_scope": [], - "required_auth": [] -} -``` - - -@subsection v1chainpushtransaction push_transaction - -This method expects a transaction in JSON format and will attempt to apply it to the blockchain, - -Success Response -

-On success it will return HTTP 200 and the transaction ID. -

- -``` - -{ - 'transaction_id' : "..." -} - - -``` - -Just because the transaction is pushed locally does not mean that the transaction has been incorporated into a block. - - -Error Response -

-If an error occurs it will return either HTTP 400 (Invalid arguments) or 500 (Internal Server Error) -

- -``` - -HTTP/1.1 500 Internal Server Error -Content-Length: 1466 - -...error message... - -``` - -@subsubsection examplepushtrx Example push_transaction Usage -This example assumes a transfer operation. The `ref_block_num` and `ref_block_prefix` here are provided as a result of `/v1/chain/get_block` of the last_irreversible_block. -You also need to use /v1/wallet/sign_transaction to get the right signature. -``` -curl http://localhost:8888/v1/chain/push_transaction -X POST -d '{"ref_block_num":"100","ref_block_prefix":"137469861","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"actions":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}' -``` - - -@subsection v1chainpushtransactions push_transactions - -This method push multiple transactions at once. - -@subsubsection examplepushtrxs Example push_transactions Usage -``` -curl http://localhost:8888/v1/chain/push_transaction -X POST -d '[{"ref_block_num":"101","ref_block_prefix":"4159312339","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"actions":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}, {"ref_block_num":"101","ref_block_prefix":"4159312339","expiration":"2017-09-25T06:28:49","scope":["inita","initc"],"actions":[{"code":"currency","type":"transfer","recipients":["inita","initc"],"authorization":[{"account":"inita","permission":"active"}],"data":"000000008040934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}]' -``` - - -@subsection v1chaingetrequiredkeys get_required_keys - -Get required keys to sign a transaction from list of your keys. - -@subsubsection examplegetrequiredkeys Example get_required_keys Usage -``` -curl http://localhost:8888/v1/chain/get_required_keys -X POST -d '{"transaction": {"ref_block_num":"100","ref_block_prefix":"137469861","expiration":"2017-09-25T06:28:49","scope":["initb","initc"],"actions":[{"code":"currency","type":"transfer","recipients":["initb","initc"],"authorization":[{"account":"initb","permission":"active"}],"data":"000000000041934b000000008041934be803000000000000"}],"signatures":[],"authorizations":[]}, "available_keys":["EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq","EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA","EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"]}' -``` - -@subsubsection examplegetrequiredkeysresult Example get_required_keys Result -``` -{ - "required_keys": [ - "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" - ] -} -``` - -@section walletrpc Wallet API - -@subsection v1walletcreate wallet_create - -Create a new wallet with the given name - -@subsubsection examplewalletcreate Example wallet_create Usage -``` -$ curl http://localhost:8888/v1/wallet/create -X POST -d '"default"' -``` - -@subsubsection examplewalletcreateresult Example wallet_create Result -This command will return the password that can be used to unlock the wallet in the future -``` -PW5KFWYKqvt63d4iNvedfDEPVZL227D3RQ1zpVFzuUwhMAJmRAYyX -``` - -@subsection v1walletcreatekey wallet_create_key - -Creates a key within the specified wallet, wallet must be opened and unlocked. -Param are: 1.name of the wallet to create key in; 2. type of key to create, currently we support two values: K1 and R1 - -@subsubsection examplewalletcreatekey Example wallet_create_key Usage -``` -$ curl http://localhost:8888/v1/wallet/create_key -X POST -d '["default","K1"]' -``` - -@subsubsection examplewalletcreatekeyresult Example wallet_create_key Result -This command will return the public key of the created key -``` -EOS6GZE1xeo6jX2AtP2Z6WTcxawQMH7cyYMNpG6Q3q7s514zyRhgo -``` - -@subsection v1walletopen wallet_open - -Open an existing wallet of the given name - -@subsubsection examplewalletopen Example wallet_open Usage -``` -$ curl http://localhost:8888/v1/wallet/open -X POST -d '"default"' -``` - -@subsubsection examplewalletopenresult Example wallet_open Result -``` -{} -``` - - -@subsection v1walletlock wallet_lock - -Lock a wallet of the given name - -@subsubsection examplewalletlock Example wallet_lock Usage -``` -$ curl http://localhost:8888/v1/wallet/lock -X POST -d '"default"' -``` - -@subsubsection examplewalletlockresult Example wallet_lock Result -``` -{} -``` - - -@subsection v1walletlockall wallet_lock_all - -Lock all wallets - -@subsubsection examplewalletlockall Example wallet_lock_all Usage -``` -$ curl http://localhost:8888/v1/wallet/lock_all -``` - -@subsubsection examplewalletlockallresult Example wallet_lock_all Result -``` -{} -``` - -@subsection v1walletunlock wallet_unlock - -Unlock a wallet with the given name and password - -@subsubsection examplewalletunlock Example wallet_unlock Usage -``` -$ curl http://localhost:8888/v1/wallet/unlock -X POST -d '["default", "PW5KFWYKqvt63d4iNvedfDEPVZL227D3RQ1zpVFzuUwhMAJmRAYyX"]' -``` - -@subsubsection examplewalletunlockresult Example wallet_unlock Result -``` -{} -``` - -@subsection v1walletimport wallet_import_key - -Import a private key to the wallet of the given name - -@subsubsection examplewalletimport Example wallet_import_key Usage -``` -$ curl http://localhost:8888/v1/wallet/import_key -X POST -d '["default","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]' -``` - -@subsubsection examplewalletimportresult Example wallet_import_key Result -``` -{} -``` - -@subsection v1walletlist wallet_list - -List all wallets - -@subsubsection examplewalletlist Example wallet_list Usage -``` -$ curl http://localhost:8888/v1/wallet/list_wallets -``` - -@subsubsection examplewalletlistresult Example wallet_list Result -``` -["default *"] -``` - -@subsection v1walletlistkeys wallet_list_keys - -List all key pairs across all wallets - -@subsubsection examplewalletlistkeys Example wallet_list_keys Usage -``` -$ curl http://localhost:8888/v1/wallet/list_keys -``` - -@subsubsection examplewalletlistkeysresult Example wallet_list_keys Result -``` -[["EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"]] -``` - -@subsection v1walletgetpublickeys wallet_get_public_keys - -List all public keys across all wallets - -@subsubsection examplewalletgetpublickeys Example wallet_get_public_keys Usage -``` -$ curl http://localhost:8888/v1/wallet/get_public_keys -``` - -@subsubsection examplewallegetpublickeysresult Example wallet_get_public_keys Result -``` -["EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"] -``` - -@subsection v1walletsettimeout wallet_set_timeout - -Set wallet auto lock timeout (in seconds) - -@subsubsection examplewalletsettimeout Example wallet_set_timeout Usage -``` -$ curl http://localhost:8888/v1/wallet/set_timeout -X POST -d '10' -``` - -@subsubsection examplewalletsettimeoutresult Example wallet_set_timeout Result -``` -{} -``` - -@subsection v1walletsigntrx wallet_sign_trx - -Sign transaction given an array of transaction, require public keys, and chain id - -@subsubsection examplewalletsigntrx Example wallet_sign_trx Usage -``` -$ curl http://localhost:8888/v1/wallet/sign_transaction -X POST -d '[{"ref_block_num":21453,"ref_block_prefix":3165644999,"expiration":"2017-12-08T10:28:49","scope":["initb","initc"],"read_scope":[],"messages":[{"code":"currency","type":"transfer","authorization":[{"account":"initb","permission":"active"}],"data":"000000008093dd74000000000094dd74e803000000000000"}],"signatures":[]}, ["EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"], ""]' -``` - -@subsubsection examplewalletsigntrxresult Example wallet_sign_trx Result -``` -{ - "ref_block_num": 21453, - "ref_block_prefix": 3165644999, - "expiration": "2017-12-08T10:28:49", - "scope": [ - "initb", - "initc" - ], - "read_scope": [], - "messages": [ - { - "code": "currency", - "type": "transfer", - "authorization": [ - { - "account": "initb", - "permission": "active" - } - ], - "data": "000000008093dd74000000000094dd74e803000000000000" - } - ], - "signatures": [ - "1f393cc5ce6a6951fb53b11812345bcf14ffd978b07be386fd639eaf440bca7dca16b14833ec661ca0703d15e55a2a599a36d55ce78c4539433f6ce8bcee0158c3" - ] -} -``` - -*/ diff --git a/contracts/eosiolib/serialize.hpp b/contracts/eosiolib/serialize.hpp deleted file mode 100644 index eff10d3cc60..00000000000 --- a/contracts/eosiolib/serialize.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include -#include -#include - -#define EOSLIB_REFLECT_MEMBER_OP( r, OP, elem ) \ - OP t.elem - -/** - * @defgroup serialize Serialize API - * @brief Defines functions to serialize and deserialize object - * @ingroup contractdev - */ - -/** - * @defgroup serializecpp Serialize C++ API - * @brief Defines C++ API to serialize and deserialize object - * @ingroup serialize - * @{ - */ - -/** - * Defines serialization and deserialization for a class - * - * @brief Defines serialization and deserialization for a class - * - * @param TYPE - the class to have its serialization and deserialization defined - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - */ -#define EOSLIB_SERIALIZE( TYPE, MEMBERS ) \ - template \ - friend DataStream& operator << ( DataStream& ds, const TYPE& t ){ \ - return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, <<, MEMBERS );\ - }\ - template \ - friend DataStream& operator >> ( DataStream& ds, TYPE& t ){ \ - return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, >>, MEMBERS );\ - } - -/** - * Defines serialization and deserialization for a class which inherits from other classes that - * have their serialization and deserialization defined - * - * @brief Defines serialization and deserialization for a class which inherits from other classes that - * have their serialization and deserialization defined - * - * @param TYPE - the class to have its serialization and deserialization defined - * @param BASE - a sequence of base class names (basea)(baseb)(basec) - * @param MEMBERS - a sequence of member names. (field1)(field2)(field3) - */ -#define EOSLIB_SERIALIZE_DERIVED( TYPE, BASE, MEMBERS ) \ - template \ - friend DataStream& operator << ( DataStream& ds, const TYPE& t ){ \ - ds << static_cast(t); \ - return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, <<, MEMBERS );\ - }\ - template \ - friend DataStream& operator >> ( DataStream& ds, TYPE& t ){ \ - ds >> static_cast(t); \ - return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, >>, MEMBERS );\ - } -///@} serializecpp diff --git a/contracts/eosiolib/singleton.hpp b/contracts/eosiolib/singleton.hpp deleted file mode 100644 index 48e75126ed9..00000000000 --- a/contracts/eosiolib/singleton.hpp +++ /dev/null @@ -1,150 +0,0 @@ -#pragma once -#include -#include - -namespace eosio { - - /** - * @defgroup singleton Singleton Table - * @brief Defines EOSIO Singleton Table - * @ingroup databasecpp - * @{ - */ - - /** - * This wrapper uses a single table to store named objects various types. - * - * @tparam SingletonName - the name of this singleton variable - * @tparam T - the type of the singleton - */ - template - class singleton - { - /** - * Primary key of the data inside singleton table - * - * @brief Primary key of the data singleton table - */ - constexpr static uint64_t pk_value = SingletonName; - - /** - * Structure of data inside the singleton table - * - * @brief Structure of data inside the singleton table - */ - struct row { - /** - * Value to be stored inside the singleton table - * - * @brief Value to be stored inside the singleton table - */ - T value; - - /** - * Get primary key of the data - * - * @brief Get primary key of the data - * @return uint64_t - Primary Key - */ - uint64_t primary_key() const { return pk_value; } - - EOSLIB_SERIALIZE( row, (value) ) - }; - - typedef eosio::multi_index table; - - public: - - /** - * Construct a new singleton object given the table's owner and the scope - * - * @brief Construct a new singleton object - * @param code - The table's owner - * @param scope - The scope of the table - */ - singleton( account_name code, scope_name scope ) : _t( code, scope ) {} - - /** - * Check if the singleton table exists - * - * @brief Check if the singleton table exists - * @return true - if exists - * @return false - otherwise - */ - bool exists() { - return _t.find( pk_value ) != _t.end(); - } - - /** - * Get the value stored inside the singleton table. Will throw an exception if it doesn't exist - * - * @brief Get the value stored inside the singleton table - * @return T - The value stored - */ - T get() { - auto itr = _t.find( pk_value ); - eosio_assert( itr != _t.end(), "singleton does not exist" ); - return itr->value; - } - - /** - * Get the value stored inside the singleton table. If it doesn't exist, it will return the specified default value - * - * @brief Get the value stored inside the singleton table or return the specified default value if it doesn't exist - * @param def - The default value to be returned in case the data doesn't exist - * @return T - The value stored - */ - T get_or_default( const T& def = T() ) { - auto itr = _t.find( pk_value ); - return itr != _t.end() ? itr->value : def; - } - - /** - * Get the value stored inside the singleton table. If it doesn't exist, it will create a new one with the specified default value - * - * @brief Get the value stored inside the singleton table or create a new one with the specified default value if it doesn't exist - * @param bill_to_account - The account to bill for the newly created data if the data doesn't exist - * @param def - The default value to be created in case the data doesn't exist - * @return T - The value stored - */ - T get_or_create( account_name bill_to_account, const T& def = T() ) { - auto itr = _t.find( pk_value ); - return itr != _t.end() ? itr->value - : _t.emplace(bill_to_account, [&](row& r) { r.value = def; })->value; - } - - /** - * Set new value to the singleton table - * - * @brief Set new value to the singleton table - * - * @param value - New value to be set - * @param bill_to_account - Account to pay for the new value - */ - void set( const T& value, account_name bill_to_account ) { - auto itr = _t.find( pk_value ); - if( itr != _t.end() ) { - _t.modify(itr, bill_to_account, [&](row& r) { r.value = value; }); - } else { - _t.emplace(bill_to_account, [&](row& r) { r.value = value; }); - } - } - - /** - * Remove the only data inside singleton table - * - * @brief Remove the only data inside singleton table - */ - void remove( ) { - auto itr = _t.find( pk_value ); - if( itr != _t.end() ) { - _t.erase(itr); - } - } - - private: - table _t; - }; - -/// @} singleton -} /// namespace eosio diff --git a/contracts/eosiolib/stdlib.hpp b/contracts/eosiolib/stdlib.hpp deleted file mode 100644 index 7fd8f86d525..00000000000 --- a/contracts/eosiolib/stdlib.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include -#include -#include diff --git a/contracts/eosiolib/symbol.hpp b/contracts/eosiolib/symbol.hpp deleted file mode 100644 index 8e63a0f18e5..00000000000 --- a/contracts/eosiolib/symbol.hpp +++ /dev/null @@ -1,227 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace eosio { - - /** - * @defgroup symbolapi Symbol API - * @brief Defines API for managing symbols - * @ingroup contractdev - */ - - /** - * @defgroup symbolcppapi Symbol CPP API - * @brief Defines %CPP API for managing symbols - * @ingroup symbolapi - * @{ - */ - - /** - * Converts string to uint64_t representation of symbol - * - * @param precision - precision of symbol - * @param str - the string representation of the symbol - */ - static constexpr uint64_t string_to_symbol( uint8_t precision, const char* str ) { - uint32_t len = 0; - while( str[len] ) ++len; - - uint64_t result = 0; - for( uint32_t i = 0; i < len; ++i ) { - if( str[i] < 'A' || str[i] > 'Z' ) { - /// ERRORS? - } else { - result |= (uint64_t(str[i]) << (8*(1+i))); - } - } - - result |= uint64_t(precision); - return result; - } - - /** - * Macro for converting string to char representation of symbol - * - * @param precision - precision of symbol - * @param str - the string representation of the symbol - */ - #define S(P,X) ::eosio::string_to_symbol(P,#X) - - /** - * uint64_t representation of a symbol name - */ - typedef uint64_t symbol_name; - - /** - * Checks if provided symbol name is valid. - * - * @param sym - symbol name of type symbol_name - * @return true - if symbol is valid - */ - static constexpr bool is_valid_symbol( symbol_name sym ) { - sym >>= 8; - for( int i = 0; i < 7; ++i ) { - char c = (char)(sym & 0xff); - if( !('A' <= c && c <= 'Z') ) return false; - sym >>= 8; - if( !(sym & 0xff) ) { - do { - sym >>= 8; - if( (sym & 0xff) ) return false; - ++i; - } while( i < 7 ); - } - } - return true; - } - - /** - * Returns the character length of the provided symbol - * - * @param sym - symbol to retrieve length for (uint64_t) - * @return length - character length of the provided symbol - */ - static constexpr uint32_t symbol_name_length( symbol_name sym ) { - sym >>= 8; /// skip precision - uint32_t length = 0; - while( sym & 0xff && length <= 7) { - ++length; - sym >>= 8; - } - - return length; - } - - /** - * \struct Stores information about a symbol - * - * @brief Stores information about a symbol - */ - struct symbol_type { - /** - * The symbol name - */ - symbol_name value; - - symbol_type() { } - - /** - * What is the type of the symbol - */ - symbol_type(symbol_name s): value(s) { } - - /** - * Is this symbol valid - */ - bool is_valid()const { return is_valid_symbol( value ); } - - /** - * This symbol's precision - */ - uint64_t precision()const { return value & 0xff; } - - /** - * Returns uint64_t representation of symbol name - */ - uint64_t name()const { return value >> 8; } - - /** - * The length of this symbol - */ - uint32_t name_length()const { return symbol_name_length( value ); } - - /** - * - */ - operator symbol_name()const { return value; } - - /** - * %Print the symbol - * - * @brief %Print the symbol - */ - void print(bool show_precision=true)const { - if( show_precision ){ - ::eosio::print(precision()); - prints(","); - } - - auto sym = value; - sym >>= 8; - for( int i = 0; i < 7; ++i ) { - char c = (char)(sym & 0xff); - if( !c ) return; - prints_l(&c, 1 ); - sym >>= 8; - } - } - - EOSLIB_SERIALIZE( symbol_type, (value) ) - }; - - /** - * \struct Extended asset which stores the information of the owner of the symbol - * - */ - struct extended_symbol : public symbol_type - { - /** - * The owner of the symbol - * - * @brief The owner of the symbol - */ - account_name contract; - - extended_symbol( symbol_name sym = 0, account_name acc = 0 ):symbol_type{sym},contract(acc){} - - /** - * %Print the extended symbol - * - * @brief %Print the extended symbol - */ - void print()const { - symbol_type::print(); - prints("@"); - printn( contract ); - } - - - /** - * Equivalency operator. Returns true if a == b (are the same) - * - * @brief Subtraction operator - * @param a - The extended asset to be subtracted - * @param b - The extended asset used to subtract - * @return boolean - true if both provided symbols are the same - */ - friend bool operator == ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.value, a.contract ) == std::tie( b.value, b.contract ); - } - - /** - * Inverted equivalency operator. Returns true if a != b (are different) - * - * @brief Subtraction operator - * @param a - The extended asset to be subtracted - * @param b - The extended asset used to subtract - * @return boolean - true if both provided symbols are the same - */ - friend bool operator != ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.value, a.contract ) != std::tie( b.value, b.contract ); - } - - friend bool operator < ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.value, a.contract ) < std::tie( b.value, b.contract ); - } - - EOSLIB_SERIALIZE( extended_symbol, (value)(contract) ) - }; - - // }@ symbolapi - -} /// namespace eosio diff --git a/contracts/eosiolib/system.h b/contracts/eosiolib/system.h deleted file mode 100644 index b7d3e614107..00000000000 --- a/contracts/eosiolib/system.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include - -extern "C" { - - /** - * @defgroup systemapi System API - * @ingroup contractdev - * @brief Defines API for interacting with system level intrinsics - * - */ - - /** - * @defgroup systemcapi System C API - * @ingroup systemapi - * @brief Defines API for interacting with system level intrinsics - * - * @{ - */ - - /** - * Aborts processing of this action and unwinds all pending changes if the test condition is true - * @brief Aborts processing of this action and unwinds all pending changes - * @param test - 0 to abort, 1 to ignore - * - * Example: -* - * @code - * eosio_assert(1 == 2, "One is not equal to two."); - * eosio_assert(1 == 1, "One is not equal to one."); - * @endcode - * - * @param msg - a null terminated string explaining the reason for failure - */ - void eosio_assert( uint32_t test, const char* msg ); - - /** - * Aborts processing of this action and unwinds all pending changes if the test condition is true - * @brief Aborts processing of this action and unwinds all pending changes - * @param test - 0 to abort, 1 to ignore - * @param msg - a pointer to the start of string explaining the reason for failure - * @param msg_len - length of the string - */ - void eosio_assert_message( uint32_t test, const char* msg, uint32_t msg_len ); - - /** - * Aborts processing of this action and unwinds all pending changes if the test condition is true - * @brief Aborts processing of this action and unwinds all pending changes - * @param test - 0 to abort, 1 to ignore - * @param code - the error code - */ - void eosio_assert_code( uint32_t test, uint64_t code ); - - /** - * This method will abort execution of wasm without failing the contract. This is used to bypass all cleanup / destructors that would normally be called. - * @brief Aborts execution of wasm without failing the contract - * @param code - the exit code - * Example: -* - * @code - * eosio_exit(0); - * eosio_exit(1); - * eosio_exit(2); - * eosio_exit(3); - * @endcode - */ - [[noreturn]] void eosio_exit( int32_t code ); - - - /** - * Returns the time in microseconds from 1970 of the current block - * @brief Get time of the current block (i.e. the block including this action) - * @return time in microseconds from 1970 of the current block - */ - uint64_t current_time(); - - /** - * Returns the time in seconds from 1970 of the block including this action - * @brief Get time (rounded down to the nearest second) of the current block (i.e. the block including this action) - * @return time in seconds from 1970 of the current block - */ - uint32_t now() { - return (uint32_t)( current_time() / 1000000 ); - } - ///@ } systemcapi - - -} diff --git a/contracts/eosiolib/time.hpp b/contracts/eosiolib/time.hpp deleted file mode 100644 index ff9d0e47757..00000000000 --- a/contracts/eosiolib/time.hpp +++ /dev/null @@ -1,179 +0,0 @@ -#pragma once -#include -#include -#include - -namespace eosio { - class microseconds { - public: - explicit microseconds( int64_t c = 0) :_count(c){} - static microseconds maximum() { return microseconds(0x7fffffffffffffffll); } - friend microseconds operator + (const microseconds& l, const microseconds& r ) { return microseconds(l._count+r._count); } - friend microseconds operator - (const microseconds& l, const microseconds& r ) { return microseconds(l._count-r._count); } - - - bool operator==(const microseconds& c)const { return _count == c._count; } - bool operator!=(const microseconds& c)const { return _count != c._count; } - friend bool operator>(const microseconds& a, const microseconds& b){ return a._count > b._count; } - friend bool operator>=(const microseconds& a, const microseconds& b){ return a._count >= b._count; } - friend bool operator<(const microseconds& a, const microseconds& b){ return a._count < b._count; } - friend bool operator<=(const microseconds& a, const microseconds& b){ return a._count <= b._count; } - microseconds& operator+=(const microseconds& c) { _count += c._count; return *this; } - microseconds& operator-=(const microseconds& c) { _count -= c._count; return *this; } - int64_t count()const { return _count; } - int64_t to_seconds()const { return _count/1000000; } - - int64_t _count; - EOSLIB_SERIALIZE( microseconds, (_count) ) - private: - friend class time_point; - }; - - inline microseconds seconds( int64_t s ) { return microseconds( s * 1000000 ); } - inline microseconds milliseconds( int64_t s ) { return microseconds( s * 1000 ); } - inline microseconds minutes(int64_t m) { return seconds(60*m); } - inline microseconds hours(int64_t h) { return minutes(60*h); } - inline microseconds days(int64_t d) { return hours(24*d); } - - class time_point { - public: - explicit time_point( microseconds e = microseconds() ) :elapsed(e){} - operator std::string()const; - static time_point from_iso_string( const std::string& s ); - const microseconds& time_since_epoch()const { return elapsed; } - uint32_t sec_since_epoch()const { return uint32_t(elapsed.count() / 1000000); } - bool operator > ( const time_point& t )const { return elapsed._count > t.elapsed._count; } - bool operator >=( const time_point& t )const { return elapsed._count >=t.elapsed._count; } - bool operator < ( const time_point& t )const { return elapsed._count < t.elapsed._count; } - bool operator <=( const time_point& t )const { return elapsed._count <=t.elapsed._count; } - bool operator ==( const time_point& t )const { return elapsed._count ==t.elapsed._count; } - bool operator !=( const time_point& t )const { return elapsed._count !=t.elapsed._count; } - time_point& operator += ( const microseconds& m) { elapsed+=m; return *this; } - time_point& operator -= ( const microseconds& m) { elapsed-=m; return *this; } - time_point operator + (const microseconds& m) const { return time_point(elapsed+m); } - time_point operator + (const time_point& m) const { return time_point(elapsed+m.elapsed); } - time_point operator - (const microseconds& m) const { return time_point(elapsed-m); } - microseconds operator - (const time_point& m) const { return microseconds(elapsed.count() - m.elapsed.count()); } - microseconds elapsed; - EOSLIB_SERIALIZE( time_point, (elapsed) ) - }; - - /** - * A lower resolution time_point accurate only to seconds from 1970 - */ - class time_point_sec - { - public: - time_point_sec() - :utc_seconds(0){} - - explicit time_point_sec(uint32_t seconds ) - :utc_seconds(seconds){} - - time_point_sec( const time_point& t ) - :utc_seconds( uint32_t(t.time_since_epoch().count() / 1000000ll) ){} - - static time_point_sec maximum() { return time_point_sec(0xffffffff); } - static time_point_sec min() { return time_point_sec(0); } - - operator time_point()const { return time_point( eosio::seconds( utc_seconds) ); } - uint32_t sec_since_epoch()const { return utc_seconds; } - - time_point_sec operator = ( const eosio::time_point& t ) - { - utc_seconds = uint32_t(t.time_since_epoch().count() / 1000000ll); - return *this; - } - friend bool operator < ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds < b.utc_seconds; } - friend bool operator > ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds > b.utc_seconds; } - friend bool operator <= ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds <= b.utc_seconds; } - friend bool operator >= ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds >= b.utc_seconds; } - friend bool operator == ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds == b.utc_seconds; } - friend bool operator != ( const time_point_sec& a, const time_point_sec& b ) { return a.utc_seconds != b.utc_seconds; } - time_point_sec& operator += ( uint32_t m ) { utc_seconds+=m; return *this; } - time_point_sec& operator += ( microseconds m ) { utc_seconds+=m.to_seconds(); return *this; } - time_point_sec& operator += ( time_point_sec m ) { utc_seconds+=m.utc_seconds; return *this; } - time_point_sec& operator -= ( uint32_t m ) { utc_seconds-=m; return *this; } - time_point_sec& operator -= ( microseconds m ) { utc_seconds-=m.to_seconds(); return *this; } - time_point_sec& operator -= ( time_point_sec m ) { utc_seconds-=m.utc_seconds; return *this; } - time_point_sec operator +( uint32_t offset )const { return time_point_sec(utc_seconds + offset); } - time_point_sec operator -( uint32_t offset )const { return time_point_sec(utc_seconds - offset); } - - friend time_point operator + ( const time_point_sec& t, const microseconds& m ) { return time_point(t) + m; } - friend time_point operator - ( const time_point_sec& t, const microseconds& m ) { return time_point(t) - m; } - friend microseconds operator - ( const time_point_sec& t, const time_point_sec& m ) { return time_point(t) - time_point(m); } - friend microseconds operator - ( const time_point& t, const time_point_sec& m ) { return time_point(t) - time_point(m); } - uint32_t utc_seconds; - - EOSLIB_SERIALIZE( time_point_sec, (utc_seconds) ) - }; - - /** - * This class is used in the block headers to represent the block time - * It is a parameterised class that takes an Epoch in milliseconds and - * and an interval in milliseconds and computes the number of slots. - **/ - class block_timestamp { - public: - explicit block_timestamp( uint32_t s=0 ) :slot(s){} - - block_timestamp(const time_point& t) { - set_time_point(t); - } - - block_timestamp(const time_point_sec& t) { - set_time_point(t); - } - - static block_timestamp maximum() { return block_timestamp( 0xffff ); } - static block_timestamp min() { return block_timestamp(0); } - - block_timestamp next() const { - eosio_assert( std::numeric_limits::max() - slot >= 1, "block timestamp overflow" ); - auto result = block_timestamp(*this); - result.slot += 1; - return result; - } - - time_point to_time_point() const { - return (time_point)(*this); - } - - operator time_point() const { - int64_t msec = slot * (int64_t)block_interval_ms; - msec += block_timestamp_epoch; - return time_point(milliseconds(msec)); - } - - void operator = (const time_point& t ) { - set_time_point(t); - } - - bool operator > ( const block_timestamp& t )const { return slot > t.slot; } - bool operator >=( const block_timestamp& t )const { return slot >= t.slot; } - bool operator < ( const block_timestamp& t )const { return slot < t.slot; } - bool operator <=( const block_timestamp& t )const { return slot <= t.slot; } - bool operator ==( const block_timestamp& t )const { return slot == t.slot; } - bool operator !=( const block_timestamp& t )const { return slot != t.slot; } - uint32_t slot; - static constexpr int32_t block_interval_ms = 500; - static constexpr int64_t block_timestamp_epoch = 946684800000ll; // epoch is year 2000 - - EOSLIB_SERIALIZE( block_timestamp, (slot) ) - private: - - - void set_time_point(const time_point& t) { - int64_t micro_since_epoch = t.time_since_epoch().count(); - int64_t msec_since_epoch = micro_since_epoch / 1000; - slot = uint32_t(( msec_since_epoch - block_timestamp_epoch ) / int64_t(block_interval_ms)); - } - - void set_time_point(const time_point_sec& t) { - int64_t sec_since_epoch = t.sec_since_epoch(); - slot = uint32_t((sec_since_epoch * 1000 - block_timestamp_epoch) / block_interval_ms); - } - }; // block_timestamp - typedef block_timestamp block_timestamp_type; - -} // namespace eosio diff --git a/contracts/eosiolib/transaction.h b/contracts/eosiolib/transaction.h deleted file mode 100644 index fa51c114126..00000000000 --- a/contracts/eosiolib/transaction.h +++ /dev/null @@ -1,158 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include - -extern "C" { - /** - * @defgroup transactionapi Transaction API - * @ingroup contractdev - * @brief Defines API for sending transactions and inline actions - * - * - * Deferred transactions will not be processed until a future block. They - * can therefore have no effect on the success or failure of their parent - * transaction so long as they appear well formed. If any other condition - * causes the parent transaction to be marked as failing, then the deferred - * transaction will never be processed. - * - * Deferred transactions must adhere to the permissions available to the - * parent transaction or, in the future, delegated to the contract account - * for future use. - * - * An inline message allows one contract to send another contract a message - * which is processed immediately after the current message's processing - * ends such that the success or failure of the parent transaction is - * dependent on the success of the message. If an inline message fails in - * processing then the whole tree of transactions and actions rooted in the - * block will be marked as failing and none of effects on the database will - * persist. - * - * Inline actions and Deferred transactions must adhere to the permissions - * available to the parent transaction or, in the future, delegated to the - * contract account for future use. - */ - - /** - * @defgroup transactioncapi Transaction C API - * @ingroup transactionapi - * @brief Defines API for sending transactions - * - * @{ - */ - - /** - * Sends a deferred transaction. - * - * @brief Sends a deferred transaction. - * @param sender_id - ID of sender - * @param payer - Account paying for RAM - * @param serialized_transaction - Pointer of serialized transaction to be deferred - * @param size - Size to reserve - * @param replace_existing - f this is `0` then if the provided sender_id is already in use by an in-flight transaction from this contract, which will be a failing assert. If `1` then transaction will atomically cancel/replace the inflight transaction - */ - void send_deferred(const uint128_t& sender_id, account_name payer, const char *serialized_transaction, size_t size, uint32_t replace_existing = 0); - - /** - * Cancels a deferred transaction. - * - * @brief Cancels a deferred transaction. - * @param sender_id - The id of the sender - * - * @pre The deferred transaction ID exists. - * @pre The deferred transaction ID has not yet been published. - * @post Deferred transaction canceled. - * - * @return 1 if transaction was canceled, 0 if transaction was not found - * - * Example: - * - * @code - * id = 0xffffffffffffffff - * cancel_deferred( id ); - * @endcode - */ - int cancel_deferred(const uint128_t& sender_id); - - /** - * Access a copy of the currently executing transaction. - * - * @brief Access a copy of the currently executing transaction. - * @param buffer - a buffer to write the current transaction to - * @param size - the size of the buffer, 0 to return required size - * @return the size of the transaction written to the buffer, or number of bytes that can be copied if size==0 passed - */ - size_t read_transaction(char *buffer, size_t size); - - /** - * Gets the size of the currently executing transaction. - * - * @brief Gets the size of the currently executing transaction. - * @return size of the currently executing transaction - */ - size_t transaction_size(); - - /** - * Gets the block number used for TAPOS on the currently executing transaction. - * - * @brief Gets the block number used for TAPOS on the currently executing transaction. - * @return block number used for TAPOS on the currently executing transaction - * Example: - * @code - * int tbn = tapos_block_num(); - * @endcode - */ - int tapos_block_num(); - - /** - * Gets the block prefix used for TAPOS on the currently executing transaction. - * - * @brief Gets the block prefix used for TAPOS on the currently executing transaction. - * @return block prefix used for TAPOS on the currently executing transaction - * Example: - * @code - * int tbp = tapos_block_prefix(); - * @endcode - */ - int tapos_block_prefix(); - - /** - * Gets the expiration of the currently executing transaction. - * - * @brief Gets the expiration of the currently executing transaction. - * @return expiration of the currently executing transaction - * Example: - * @code - * time tm = expiration(); - * eosio_print(tm); - * @endcode - */ - time expiration(); - - /** - * Retrieves the indicated action from the active transaction. - * - * @brief Retrieves the indicated action from the active transaction. - * @param type - 0 for context free action, 1 for action - * @param index - the index of the requested action - * @param buff - output packed buff of the action - * @param size - amount of buff read, pass 0 to have size returned - * @return the size of the action, -1 on failure - */ - int get_action( uint32_t type, uint32_t index, char* buff, size_t size ); - - /** - * Retrieve the signed_transaction.context_free_data[index]. - * - * @brief Retrieve the signed_transaction.context_free_data[index]. - * @param index - the index of the context_free_data entry to retrieve - * @param buff - output buff of the context_free_data entry - * @param size - amount of context_free_data[index] to retrieve into buff, 0 to report required size - * @return size copied, or context_free_data[index].size() if 0 passed for size, or -1 if index not valid - */ - int get_context_free_data( uint32_t index, char* buff, size_t size ); - - ///@ } transactioncapi -} diff --git a/contracts/eosiolib/transaction.hpp b/contracts/eosiolib/transaction.hpp deleted file mode 100644 index 2b5e1f1fb2a..00000000000 --- a/contracts/eosiolib/transaction.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace eosio { - - /** - * @defgroup transactioncppapi Transaction C++ API - * @ingroup transactionapi - * @brief Type-safe C++ wrappers for transaction C API - * - * @note There are some methods from the @ref transactioncapi that can be used directly from C++ - * - * @{ - */ - - class transaction_header { - public: - transaction_header( time_point_sec exp = time_point_sec(now() + 60) ) - :expiration(exp) - {} - - time_point_sec expiration; - uint16_t ref_block_num; - uint32_t ref_block_prefix; - unsigned_int net_usage_words = 0UL; /// number of 8 byte words this transaction can serialize into after compressions - uint8_t max_cpu_usage_ms = 0UL; /// number of CPU usage units to bill transaction for - unsigned_int delay_sec = 0UL; /// number of CPU usage units to bill transaction for - - EOSLIB_SERIALIZE( transaction_header, (expiration)(ref_block_num)(ref_block_prefix)(net_usage_words)(max_cpu_usage_ms)(delay_sec) ) - }; - - class transaction : public transaction_header { - public: - transaction(time_point_sec exp = time_point_sec(now() + 60)) : transaction_header( exp ) {} - - void send(const uint128_t& sender_id, account_name payer, bool replace_existing = false) const { - auto serialize = pack(*this); - send_deferred(sender_id, payer, serialize.data(), serialize.size(), replace_existing); - } - - vector context_free_actions; - vector actions; - extensions_type transaction_extensions; - - EOSLIB_SERIALIZE_DERIVED( transaction, transaction_header, (context_free_actions)(actions)(transaction_extensions) ) - }; - - /** - * - * - * - * - */ - struct onerror { - uint128_t sender_id; - bytes sent_trx; - - static onerror from_current_action() { - return unpack_action_data(); - } - - transaction unpack_sent_trx() const { - return unpack(sent_trx); - } - - EOSLIB_SERIALIZE( onerror, (sender_id)(sent_trx) ) - }; - - /** - * Retrieve the indicated action from the active transaction. - * @param type - 0 for context free action, 1 for action - * @param index - the index of the requested action - * @return the indicated action - */ - inline action get_action( uint32_t type, uint32_t index ) { - constexpr size_t max_stack_buffer_size = 512; - int s = ::get_action( type, index, nullptr, 0 ); - eosio_assert( s > 0, "get_action size failed" ); - size_t size = static_cast(s); - char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); - auto size2 = ::get_action( type, index, buffer, size ); - eosio_assert( size == static_cast(size2), "get_action failed" ); - return eosio::unpack( buffer, size ); - } - - ///@} transactioncpp api - -} // namespace eos diff --git a/contracts/eosiolib/types.h b/contracts/eosiolib/types.h deleted file mode 100644 index 1611df2aad2..00000000000 --- a/contracts/eosiolib/types.h +++ /dev/null @@ -1,123 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup types Builtin Types - * @ingroup contractdev - * @brief Specifies builtin types, typedefs and aliases - * - * @{ - */ - -/** - * @brief Name of an account - * @details Name of an account - */ -typedef uint64_t account_name; - -/** - * @brief Name of a permission - * @details Name of a permission - */ -typedef uint64_t permission_name; - -/** - * @brief Name of a table - * @details Name of a table - */ -typedef uint64_t table_name; - -/** - * @brief Time - * @details Time - */ -typedef uint32_t time; - -/** - * @brief Name of a scope - * @details Name of a scope - */ -typedef uint64_t scope_name; - -/** - * @brief Name of an action - * @details Name of an action - */ -typedef uint64_t action_name; - -/** - * @brief Macro to align/overalign a type to ensure calls to intrinsics with pointers/references are properly aligned - * @details Macro to align/overalign a type to ensure calls to intrinsics with pointers/references are properly aligned - */ - -typedef uint16_t weight_type; - -/* macro to align/overalign a type to ensure calls to intrinsics with pointers/references are properly aligned */ -#define ALIGNED(X) __attribute__ ((aligned (16))) X - -/** - * @brief EOSIO Public Key - * @details EOSIO Public Key. It is 34 bytes. - */ -struct public_key { - char data[34]; -}; - -/** - * @brief EOSIO Signature - * @details EOSIO Signature. It is 66 bytes. - */ -struct signature { - uint8_t data[66]; -}; - -/** - * @brief 256-bit hash - * @details 256-bit hash - */ -struct ALIGNED(checksum256) { - uint8_t hash[32]; -}; - -/** - * @brief 160-bit hash - * @details 160-bit hash - */ -struct ALIGNED(checksum160) { - uint8_t hash[20]; -}; - -/** - * @brief 512-bit hash - * @details 512-bit hash - */ -struct ALIGNED(checksum512) { - uint8_t hash[64]; -}; - -/** - * @brief Type of EOSIO Transaction Id - * @details Type of EOSIO Transaction Id. It is 256-bit hash - */ -typedef struct checksum256 transaction_id_type; -typedef struct checksum256 block_id_type; - -struct account_permission { - account_name account; - permission_name permission; -}; - -#ifdef __cplusplus -} /// extern "C" -#endif -/// @} diff --git a/contracts/eosiolib/types.hpp b/contracts/eosiolib/types.hpp deleted file mode 100644 index f1e7c10dcd1..00000000000 --- a/contracts/eosiolib/types.hpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include -#include -#include -#include - -namespace eosio { - - typedef std::vector>> extensions_type; - - /** - * Converts a base32 symbol into its binary representation, used by string_to_name() - * - * @brief Converts a base32 symbol into its binary representation, used by string_to_name() - * @param c - Character to be converted - * @return constexpr char - Converted character - * @ingroup types - */ - static constexpr char char_to_symbol( char c ) { - if( c >= 'a' && c <= 'z' ) - return (c - 'a') + 6; - if( c >= '1' && c <= '5' ) - return (c - '1') + 1; - return 0; - } - - - /** - * Converts a base32 string to a uint64_t. This is a constexpr so that - * this method can be used in template arguments as well. - * - * @brief Converts a base32 string to a uint64_t. - * @param str - String representation of the name - * @return constexpr uint64_t - 64-bit unsigned integer representation of the name - * @ingroup types - */ - static constexpr uint64_t string_to_name( const char* str ) { - - uint32_t len = 0; - while( str[len] ) ++len; - - uint64_t value = 0; - - for( uint32_t i = 0; i <= 12; ++i ) { - uint64_t c = 0; - if( i < len && i <= 12 ) c = uint64_t(char_to_symbol( str[i] )); - - if( i < 12 ) { - c &= 0x1f; - c <<= 64-5*(i+1); - } - else { - c &= 0x0f; - } - - value |= c; - } - - return value; - } - - /** - * Used to generate a compile time uint64_t from the base32 encoded string interpretation of X - * - * @brief Used to generate a compile time uint64_t from the base32 encoded string interpretation of X - * @param X - String representation of the name - * @return constexpr uint64_t - 64-bit unsigned integer representation of the name - * @ingroup types - */ - #define N(X) ::eosio::string_to_name(#X) - - - static constexpr uint64_t name_suffix( uint64_t n ) { - uint32_t remaining_bits_after_last_actual_dot = 0; - uint32_t tmp = 0; - for( int32_t remaining_bits = 59; remaining_bits >= 4; remaining_bits -= 5 ) { // Note: remaining_bits must remain signed integer - // Get characters one-by-one in name in order from left to right (not including the 13th character) - auto c = (n >> remaining_bits) & 0x1Full; - if( !c ) { // if this character is a dot - tmp = static_cast(remaining_bits); - } else { // if this character is not a dot - remaining_bits_after_last_actual_dot = tmp; - } - } - - uint64_t thirteenth_character = n & 0x0Full; - if( thirteenth_character ) { // if 13th character is not a dot - remaining_bits_after_last_actual_dot = tmp; - } - - if( remaining_bits_after_last_actual_dot == 0 ) // there is no actual dot in the name other than potentially leading dots - return n; - - // At this point remaining_bits_after_last_actual_dot has to be within the range of 4 to 59 (and restricted to increments of 5). - - // Mask for remaining bits corresponding to characters after last actual dot, except for 4 least significant bits (corresponds to 13th character). - uint64_t mask = (1ull << remaining_bits_after_last_actual_dot) - 16; - uint32_t shift = 64 - remaining_bits_after_last_actual_dot; - - return ( ((n & mask) << shift) + (thirteenth_character << (shift-1)) ); - } - - /** - * Wraps a uint64_t to ensure it is only passed to methods that expect a Name and - * that no mathematical operations occur. It also enables specialization of print - * so that it is printed as a base32 string. - * - * @brief wraps a uint64_t to ensure it is only passed to methods that expect a Name - * @ingroup types - */ - struct name { - /** - * Conversion Operator to convert name to uint64_t - * - * @brief Conversion Operator - * @return uint64_t - Converted result - */ - operator uint64_t()const { return value; } - - // keep in sync with name::operator string() in eosio source code definition for name - std::string to_string() const { - static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz"; - - std::string str(13,'.'); - - uint64_t tmp = value; - for( uint32_t i = 0; i <= 12; ++i ) { - char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)]; - str[12-i] = c; - tmp >>= (i == 0 ? 4 : 5); - } - - trim_right_dots( str ); - return str; - } - - /** - * Equality Operator for name - * - * @brief Equality Operator for name - * @param a - First data to be compared - * @param b - Second data to be compared - * @return true - if equal - * @return false - if unequal - */ - friend bool operator==( const name& a, const name& b ) { return a.value == b.value; } - - /** - * Internal Representation of the account name - * - * @brief Internal Representation of the account name - */ - account_name value = 0; - - private: - static void trim_right_dots(std::string& str ) { - const auto last = str.find_last_not_of('.'); - if (last != std::string::npos) - str = str.substr(0, last + 1); - } - }; - -} // namespace eosio - -namespace std { - /** - * Provide less for checksum256 - * @brief Provide less for checksum256 - */ - template<> - struct less : binary_function { - bool operator()( const checksum256& lhs, const checksum256& rhs ) const { - return memcmp(&lhs, &rhs, sizeof(lhs)) < 0; - } - }; - -} // namespace std - -/** - * Equality Operator for checksum256 - * - * @brief Equality Operator for checksum256 - * @param lhs - First data to be compared - * @param rhs - Second data to be compared - * @return true - if equal - * @return false - if unequal - */ -bool operator==(const checksum256& lhs, const checksum256& rhs) { - return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; -} - -/** - * Equality Operator for checksum160 - * - * @brief Equality Operator for checksum256 - * @param lhs - First data to be compared - * @param rhs - Second data to be compared - * @return true - if equal - * @return false - if unequal - */ -bool operator==(const checksum160& lhs, const checksum160& rhs) { - return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; -} - -/** - * Equality Operator for checksum160 - * - * @brief Equality Operator for checksum256 - * @param lhs - First data to be compared - * @param rhs - Second data to be compared - * @return true - if unequal - * @return false - if equal - */ -bool operator!=(const checksum160& lhs, const checksum160& rhs) { - return memcmp(&lhs, &rhs, sizeof(lhs)) != 0; -} diff --git a/contracts/eosiolib/varint.hpp b/contracts/eosiolib/varint.hpp deleted file mode 100644 index dcc444f20d6..00000000000 --- a/contracts/eosiolib/varint.hpp +++ /dev/null @@ -1,484 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - - -/** - * @defgroup varint Variable Length Integer Type - * @brief Defines variable length integer type which provides more efficient serialization - * @ingroup types - * @{/ - */ - -/** - * Variable Length Unsigned Integer. This provides more efficient serialization of 32-bit unsigned int. - * It serialuzes a 32-bit unsigned integer in as few bytes as possible - * `varuint32` is unsigned and uses [VLQ or Base-128 encoding](https://en.wikipedia.org/wiki/Variable-length_quantity) - * - * @brief Variable Length Unsigned Integer - */ -struct unsigned_int { - /** - * Construct a new unsigned int object - * - * @brief Construct a new unsigned int object - * @param v - Source - */ - unsigned_int( uint32_t v = 0 ):value(v){} - - /** - * Construct a new unsigned int object from a type that is convertible to uint32_t - * - * @brief Construct a new unsigned int object - * @tparam T - Type of the source - * @param v - Source - * @pre T must be convertible to uint32_t - */ - template - unsigned_int( T v ):value(v){} - - //operator uint32_t()const { return value; } - //operator uint64_t()const { return value; } - - /** - * Convert unsigned_int as T - * @brief Conversion Operator - * @tparam T - Target type of conversion - * @return T - Converted target - */ - template - operator T()const { return static_cast(value); } - - /** - * Assign 32-bit unsigned integer - * - * @brief Assignment operator - * @param v - Soruce - * @return unsigned_int& - Reference to this object - */ - unsigned_int& operator=( uint32_t v ) { value = v; return *this; } - - /** - * Contained value - * - * @brief Contained value - */ - uint32_t value; - - /** - * Check equality between a unsigned_int object and 32-bit unsigned integer - * - * @brief Equality Operator - * @param i - unsigned_int object to compare - * @param v - 32-bit unsigned integer to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const unsigned_int& i, const uint32_t& v ) { return i.value == v; } - - /** - * Check equality between 32-bit unsigned integer and a unsigned_int object - * - * @brief Equality Operator - * @param i - 32-bit unsigned integer to compare - * @param v - unsigned_int object to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const uint32_t& i, const unsigned_int& v ) { return i == v.value; } - - /** - * Check equality between two unsigned_int objects - * - * @brief Equality Operator - * @param i - First unsigned_int object to compare - * @param v - Second unsigned_int object to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const unsigned_int& i, const unsigned_int& v ) { return i.value == v.value; } - - /** - * Check inequality between a unsigned_int object and 32-bit unsigned integer - * - * @brief Inequality Operator - * @param i - unsigned_int object to compare - * @param v - 32-bit unsigned integer to compare - * @return true - if inequal - * @return false - otherwise - */ - friend bool operator!=( const unsigned_int& i, const uint32_t& v ) { return i.value != v; } - - /** - * Check inequality between 32-bit unsigned integer and a unsigned_int object - * - * @brief Equality Operator - * @param i - 32-bit unsigned integer to compare - * @param v - unsigned_int object to compare - * @return true - if unequal - * @return false - otherwise - */ - friend bool operator!=( const uint32_t& i, const unsigned_int& v ) { return i != v.value; } - - /** - * Check inequality between two unsigned_int objects - * - * @brief Inequality Operator - * @param i - First unsigned_int object to compare - * @param v - Second unsigned_int object to compare - * @return true - if inequal - * @return false - otherwise - */ - friend bool operator!=( const unsigned_int& i, const unsigned_int& v ) { return i.value != v.value; } - - /** - * Check if the given unsigned_int object is less than the given 32-bit unsigned integer - * - * @brief Less than Operator - * @param i - unsigned_int object to compare - * @param v - 32-bit unsigned integer to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const unsigned_int& i, const uint32_t& v ) { return i.value < v; } - - /** - * Check if the given 32-bit unsigned integer is less than the given unsigned_int object - * - * @brief Less than Operator - * @param i - 32-bit unsigned integer to compare - * @param v - unsigned_int object to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const uint32_t& i, const unsigned_int& v ) { return i < v.value; } - - /** - * Check if the first given unsigned_int is less than the second given unsigned_int object - * - * @brief Less than Operator - * @param i - First unsigned_int object to compare - * @param v - Second unsigned_int object to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const unsigned_int& i, const unsigned_int& v ) { return i.value < v.value; } - - /** - * Check if the given unsigned_int object is greater or equal to the given 32-bit unsigned integer - * - * @brief Greater or Equal to Operator - * @param i - unsigned_int object to compare - * @param v - 32-bit unsigned integer to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const unsigned_int& i, const uint32_t& v ) { return i.value >= v; } - - /** - * Check if the given 32-bit unsigned integer is greater or equal to the given unsigned_int object - * - * @brief Greater or Equal to Operator - * @param i - 32-bit unsigned integer to compare - * @param v - unsigned_int object to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const uint32_t& i, const unsigned_int& v ) { return i >= v.value; } - - /** - * Check if the first given unsigned_int is greater or equal to the second given unsigned_int object - * - * @brief Greater or Equal to Operator - * @param i - First unsigned_int object to compare - * @param v - Second unsigned_int object to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const unsigned_int& i, const unsigned_int& v ) { return i.value >= v.value; } - - /** - * Serialize an unsigned_int object with as few bytes as possible - * - * @brief Serialize an unsigned_int object with as few bytes as possible - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ - template - friend DataStream& operator << ( DataStream& ds, const unsigned_int& v ){ - uint64_t val = v.value; - do { - uint8_t b = uint8_t(val) & 0x7f; - val >>= 7; - b |= ((val > 0) << 7); - ds.write((char*)&b,1);//.put(b); - } while( val ); - return ds; - } - - /** - * Deserialize an unsigned_int object - * - * @brief Deserialize an unsigned_int object - * @param ds - The stream to read - * @param vi - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ - template - friend DataStream& operator >> ( DataStream& ds, unsigned_int& vi ){ - uint64_t v = 0; char b = 0; uint8_t by = 0; - do { - ds.get(b); - v |= uint32_t(uint8_t(b) & 0x7f) << by; - by += 7; - } while( uint8_t(b) & 0x80 ); - vi.value = static_cast(v); - return ds; - } -}; - -/** - * Variable Length Signed Integer. This provides more efficient serialization of 32-bit signed int. - * It serializes a 32-bit signed integer in as few bytes as possible. - * `varint32' is signed and uses [Zig-Zag encoding](https://developers.google.com/protocol-buffers/docs/encoding#signed-integers) - * - * @brief Variable Length Signed Integer - */ -struct signed_int { - /** - * Construct a new signed int object - * - * @brief Construct a new signed int object - * @param v - Source - */ - signed_int( int32_t v = 0 ):value(v){} - - /** - * Convert signed_int to primitive 32-bit signed integer - * @brief Conversion operator - * - * @return int32_t - The converted result - */ - operator int32_t()const { return value; } - - - /** - * Assign an object that is convertible to int32_t - * - * @brief Assignment operator - * @tparam T - Type of the assignment object - * @param v - Source - * @return unsigned_int& - Reference to this object - */ - template - signed_int& operator=( const T& v ) { value = v; return *this; } - - /** - * Increment operator - * - * @brief Increment operator - * @return signed_int - New signed_int with value incremented from the current object's value - */ - signed_int operator++(int) { return value++; } - - /** - * Increment operator - * - * @brief Increment operator - * @return signed_int - Reference to current object - */ - signed_int& operator++(){ ++value; return *this; } - - /** - * Contained value - * - * @brief Contained value - */ - int32_t value; - - /** - * Check equality between a signed_int object and 32-bit integer - * - * @brief Equality Operator - * @param i - signed_int object to compare - * @param v - 32-bit integer to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const signed_int& i, const int32_t& v ) { return i.value == v; } - - /** - * Check equality between 32-bit integer and a signed_int object - * - * @brief Equality Operator - * @param i - 32-bit integer to compare - * @param v - signed_int object to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const int32_t& i, const signed_int& v ) { return i == v.value; } - - /** - * Check equality between two signed_int objects - * - * @brief Equality Operator - * @param i - First signed_int object to compare - * @param v - Second signed_int object to compare - * @return true - if equal - * @return false - otherwise - */ - friend bool operator==( const signed_int& i, const signed_int& v ) { return i.value == v.value; } - - - /** - * Check inequality between a signed_int object and 32-bit integer - * - * @brief Inequality Operator - * @param i - signed_int object to compare - * @param v - 32-bit integer to compare - * @return true - if inequal - * @return false - otherwise - */ - friend bool operator!=( const signed_int& i, const int32_t& v ) { return i.value != v; } - - /** - * Check inequality between 32-bit integer and a signed_int object - * - * @brief Equality Operator - * @param i - 32-bit integer to compare - * @param v - signed_int object to compare - * @return true - if unequal - * @return false - otherwise - */ - friend bool operator!=( const int32_t& i, const signed_int& v ) { return i != v.value; } - - /** - * Check inequality between two signed_int objects - * - * @brief Inequality Operator - * @param i - First signed_int object to compare - * @param v - Second signed_int object to compare - * @return true - if inequal - * @return false - otherwise - */ - friend bool operator!=( const signed_int& i, const signed_int& v ) { return i.value != v.value; } - - /** - * Check if the given signed_int object is less than the given 32-bit integer - * - * @brief Less than Operator - * @param i - signed_int object to compare - * @param v - 32-bit integer to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const signed_int& i, const int32_t& v ) { return i.value < v; } - - /** - * Check if the given 32-bit integer is less than the given signed_int object - * - * @brief Less than Operator - * @param i - 32-bit integer to compare - * @param v - signed_int object to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const int32_t& i, const signed_int& v ) { return i < v.value; } - - /** - * Check if the first given signed_int is less than the second given signed_int object - * - * @brief Less than Operator - * @param i - First signed_int object to compare - * @param v - Second signed_int object to compare - * @return true - if i less than v - * @return false - otherwise - */ - friend bool operator<( const signed_int& i, const signed_int& v ) { return i.value < v.value; } - - - /** - * Check if the given signed_int object is greater or equal to the given 32-bit integer - * - * @brief Greater or Equal to Operator - * @param i - signed_int object to compare - * @param v - 32-bit integer to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const signed_int& i, const int32_t& v ) { return i.value >= v; } - - /** - * Check if the given 32-bit integer is greater or equal to the given signed_int object - * - * @brief Greater or Equal to Operator - * @param i - 32-bit integer to compare - * @param v - signed_int object to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const int32_t& i, const signed_int& v ) { return i >= v.value; } - - /** - * Check if the first given signed_int is greater or equal to the second given signed_int object - * - * @brief Greater or Equal to Operator - * @param i - First signed_int object to compare - * @param v - Second signed_int object to compare - * @return true - if i is greater or equal to v - * @return false - otherwise - */ - friend bool operator>=( const signed_int& i, const signed_int& v ) { return i.value >= v.value; } - - - /** - * Serialize an signed_int object with as few bytes as possible - * - * @brief Serialize an signed_int object with as few bytes as possible - * @param ds - The stream to write - * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ - template - friend DataStream& operator << ( DataStream& ds, const signed_int& v ){ - uint32_t val = uint32_t((v.value<<1) ^ (v.value>>31)); - do { - uint8_t b = uint8_t(val) & 0x7f; - val >>= 7; - b |= ((val > 0) << 7); - ds.write((char*)&b,1);//.put(b); - } while( val ); - return ds; - } - - /** - * Deserialize an signed_int object - * - * @brief Deserialize an signed_int object - * @param ds - The stream to read - * @param vi - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream - */ - template - friend DataStream& operator >> ( DataStream& ds, signed_int& vi ){ - uint32_t v = 0; char b = 0; int by = 0; - do { - ds.get(b); - v |= uint32_t(uint8_t(b) & 0x7f) << by; - by += 7; - } while( uint8_t(b) & 0x80 ); - vi.value = ((v>>1) ^ (v>>31)) + (v&0x01); - vi.value = v&0x01 ? vi.value : -vi.value; - vi.value = -vi.value; - return ds; - } -}; - -/// @} diff --git a/contracts/eosiolib/vector.hpp b/contracts/eosiolib/vector.hpp deleted file mode 100644 index a6aa811d222..00000000000 --- a/contracts/eosiolib/vector.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include -#include -#include - -namespace eosio { - - using std::vector; - - typedef std::vector bytes; - -} /// namespace eosio diff --git a/contracts/hello/CMakeLists.txt b/contracts/hello/CMakeLists.txt deleted file mode 100644 index 5cd15332331..00000000000 --- a/contracts/hello/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET hello - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc libc++ eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/hello/hello.abi b/contracts/hello/hello.abi deleted file mode 100644 index 4ab98040edf..00000000000 --- a/contracts/hello/hello.abi +++ /dev/null @@ -1,65 +0,0 @@ -{ - "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-05-23T20:27:36", - "version": "eosio::abi/1.0", - "types": [], - "structs": [{ - "name": "hi", - "base": "", - "fields": [{ - "name": "user", - "type": "name" - } - ] - } - ], - "actions": [{ - "name": "hi", - "type": "hi", - "ricardian_contract": "# CONTRACT FOR hello::hi## ACTION NAME: hi\n### Parameters### Parameters\nInput parameters:Input parameters:\n\n* `user` (string to include in the output)* `user` (string to include in the output)\n\nImplied parameters: Implied parameters: \n\n* `account_name` (name of the party invoking and signing the contract)* `account_name` (name of the party invoking and signing the contract)\n\n### Intent### Intent\nINTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.INTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.\n\n### Term### Term\nTERM. This Contract expires at the conclusion of code execution.TERM. This Contract expires at the conclusion of code execution.\n" - } - ], - "tables": [], - "ricardian_clauses": [{ - "id": "Warranty", - "body": "WARRANTY. The invoker of the contract action shall uphold its Obligations under this Contract in a timely and workmanlike manner, using knowledge and recommendations for performing the services which meet generally acceptable standards set forth by EOS.IO Blockchain Block Producers.\n\n" - },{ - "id": "Default", - "body": "DEFAULT. The occurrence of any of the following shall constitute a material default under this Contract: \n\n" - },{ - "id": "Remedies", - "body": "REMEDIES. In addition to any and all other rights a party may have available according to law, if a party defaults by failing to substantially perform any provision, term or condition of this Contract, the other party may terminate the Contract by providing written notice to the defaulting party. This notice shall describe with sufficient detail the nature of the default. The party receiving such notice shall promptly be removed from being a Block Producer and this Contract shall be automatically terminated. \n \n" - },{ - "id": "Force Majeure", - "body": "FORCE MAJEURE. If performance of this Contract or any obligation under this Contract is prevented, restricted, or interfered with by causes beyond either party's reasonable control (\"Force Majeure\"), and if the party unable to carry out its obligations gives the other party prompt written notice of such event, then the obligations of the party invoking this provision shall be suspended to the extent necessary by such event. The term Force Majeure shall include, without limitation, acts of God, fire, explosion, vandalism, storm or other similar occurrence, orders or acts of military or civil authority, or by national emergencies, insurrections, riots, or wars, or strikes, lock-outs, work stoppages, or supplier failures. The excused party shall use reasonable efforts under the circumstances to avoid or remove such causes of non-performance and shall proceed to perform with reasonable dispatch whenever such causes are removed or ceased. An act or omission shall be deemed within the reasonable control of a party if committed, omitted, or caused by such party, or its employees, officers, agents, or affiliates. \n \n" - },{ - "id": "Dispute Resolution", - "body": "DISPUTE RESOLUTION. Any controversies or disputes arising out of or relating to this Contract will be resolved by binding arbitration under the default rules set forth by the EOS.IO Blockchain. The arbitrator's award will be final, and judgment may be entered upon it by any court having proper jurisdiction. \n \n" - },{ - "id": "Entire Agreement", - "body": "ENTIRE AGREEMENT. This Contract contains the entire agreement of the parties, and there are no other promises or conditions in any other agreement whether oral or written concerning the subject matter of this Contract. This Contract supersedes any prior written or oral agreements between the parties. \n\n" - },{ - "id": "Severability", - "body": "SEVERABILITY. If any provision of this Contract will be held to be invalid or unenforceable for any reason, the remaining provisions will continue to be valid and enforceable. If a court finds that any provision of this Contract is invalid or unenforceable, but that by limiting such provision it would become valid and enforceable, then such provision will be deemed to be written, construed, and enforced as so limited. \n\n" - },{ - "id": "Amendment", - "body": "AMENDMENT. This Contract may be modified or amended in writing by mutual agreement between the parties, if the writing is signed by the party obligated under the amendment. \n\n" - },{ - "id": "Governing Law", - "body": "GOVERNING LAW. This Contract shall be construed in accordance with the Maxims of Equity. \n\n" - },{ - "id": "Notice", - "body": "NOTICE. Any notice or communication required or permitted under this Contract shall be sufficiently given if delivered to a verifiable email address or to such other email address as one party may have publicly furnished in writing, or published on a broadcast contract provided by this blockchain for purposes of providing notices of this type. \n" - },{ - "id": "Waiver of Contractual Right", - "body": "WAIVER OF CONTRACTUAL RIGHT. The failure of either party to enforce any provision of this Contract shall not be construed as a waiver or limitation of that party's right to subsequently enforce and compel strict compliance with every provision of this Contract. \n\n" - },{ - "id": "Arbitrator's Fees to Prevailing Party", - "body": "ARBITRATOR'S FEES TO PREVAILING PARTY. In any action arising hereunder or any separate action pertaining to the validity of this Agreement, both sides shall pay half the initial cost of arbitration, and the prevailing party shall be awarded reasonable arbitrator's fees and costs.\n \n" - },{ - "id": "Construction and Interpretation", - "body": "CONSTRUCTION AND INTERPRETATION. The rule requiring construction or interpretation against the drafter is waived. The document shall be deemed as if it were drafted by both parties in a mutual effort. \n \n" - } - ], - "error_messages": [], - "abi_extensions": [] -} \ No newline at end of file diff --git a/contracts/hello/hello.cpp b/contracts/hello/hello.cpp deleted file mode 100644 index 7c52afa9b60..00000000000 --- a/contracts/hello/hello.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -using namespace eosio; - -class hello : public eosio::contract { - public: - using contract::contract; - - /// @abi action - void hi( account_name user ) { - print( "Hello, ", name{user} ); - } -}; - -EOSIO_ABI( hello, (hi) ) diff --git a/contracts/hello/hello.hi_rc.md b/contracts/hello/hello.hi_rc.md deleted file mode 100644 index 0d4ebd3ae8b..00000000000 --- a/contracts/hello/hello.hi_rc.md +++ /dev/null @@ -1,18 +0,0 @@ -# CONTRACT FOR hello::hi - -## ACTION NAME: hi - -### Parameters -Input parameters: - -* `user` (string to include in the output) - -Implied parameters: - -* `account_name` (name of the party invoking and signing the contract) - -### Intent -INTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect. - -### Term -TERM. This Contract expires at the conclusion of code execution. diff --git a/contracts/hello/hello_rc.md b/contracts/hello/hello_rc.md deleted file mode 100644 index 4ca04401a20..00000000000 --- a/contracts/hello/hello_rc.md +++ /dev/null @@ -1,40 +0,0 @@ -### CLAUSE NAME: Warranty -WARRANTY. The invoker of the contract action shall uphold its Obligations under this Contract in a timely and workmanlike manner, using knowledge and recommendations for performing the services which meet generally acceptable standards set forth by EOS.IO Blockchain Block Producers. - -### CLAUSE NAME: Default -DEFAULT. The occurrence of any of the following shall constitute a material default under this Contract: - -### CLAUSE NAME: Remedies -REMEDIES. In addition to any and all other rights a party may have available according to law, if a party defaults by failing to substantially perform any provision, term or condition of this Contract, the other party may terminate the Contract by providing written notice to the defaulting party. This notice shall describe with sufficient detail the nature of the default. The party receiving such notice shall promptly be removed from being a Block Producer and this Contract shall be automatically terminated. - -### CLAUSE NAME: Force Majeure -FORCE MAJEURE. If performance of this Contract or any obligation under this Contract is prevented, restricted, or interfered with by causes beyond either party's reasonable control ("Force Majeure"), and if the party unable to carry out its obligations gives the other party prompt written notice of such event, then the obligations of the party invoking this provision shall be suspended to the extent necessary by such event. The term Force Majeure shall include, without limitation, acts of God, fire, explosion, vandalism, storm or other similar occurrence, orders or acts of military or civil authority, or by national emergencies, insurrections, riots, or wars, or strikes, lock-outs, work stoppages, or supplier failures. The excused party shall use reasonable efforts under the circumstances to avoid or remove such causes of non-performance and shall proceed to perform with reasonable dispatch whenever such causes are removed or ceased. An act or omission shall be deemed within the reasonable control of a party if committed, omitted, or caused by such party, or its employees, officers, agents, or affiliates. - -### CLAUSE NAME: Dispute Resolution -DISPUTE RESOLUTION. Any controversies or disputes arising out of or relating to this Contract will be resolved by binding arbitration under the default rules set forth by the EOS.IO Blockchain. The arbitrator's award will be final, and judgment may be entered upon it by any court having proper jurisdiction. - -### CLAUSE NAME: Entire Agreement -ENTIRE AGREEMENT. This Contract contains the entire agreement of the parties, and there are no other promises or conditions in any other agreement whether oral or written concerning the subject matter of this Contract. This Contract supersedes any prior written or oral agreements between the parties. - -### CLAUSE NAME: Severability -SEVERABILITY. If any provision of this Contract will be held to be invalid or unenforceable for any reason, the remaining provisions will continue to be valid and enforceable. If a court finds that any provision of this Contract is invalid or unenforceable, but that by limiting such provision it would become valid and enforceable, then such provision will be deemed to be written, construed, and enforced as so limited. - -### CLAUSE NAME: Amendment -AMENDMENT. This Contract may be modified or amended in writing by mutual agreement between the parties, if the writing is signed by the party obligated under the amendment. - -### CLAUSE NAME: Governing Law -GOVERNING LAW. This Contract shall be construed in accordance with the Maxims of Equity. - -### CLAUSE NAME: Notice -NOTICE. Any notice or communication required or permitted under this Contract shall be sufficiently given if delivered to a verifiable email address or to such other email address as one party may have publicly furnished in writing, or published on a broadcast contract provided by this blockchain for purposes of providing notices of this type. -### CLAUSE NAME: Waiver of Contractual Right -WAIVER OF CONTRACTUAL RIGHT. The failure of either party to enforce any provision of this Contract shall not be construed as a waiver or limitation of that party's right to subsequently enforce and compel strict compliance with every provision of this Contract. - -### CLAUSE NAME: Arbitrator's Fees to Prevailing Party -ARBITRATOR'S FEES TO PREVAILING PARTY. In any action arising hereunder or any separate action pertaining to the validity of this Agreement, both sides shall pay half the initial cost of arbitration, and the prevailing party shall be awarded reasonable arbitrator's fees and costs. - -### CLAUSE NAME: Construction and Interpretation -CONSTRUCTION AND INTERPRETATION. The rule requiring construction or interpretation against the drafter is waived. The document shall be deemed as if it were drafted by both parties in a mutual effort. - -### CLAUSE NAME: In Witness Whereof -IN WITNESS WHEREOF, the parties hereto have caused this Agreement to be executed by themselves or their duly authorized representatives as of the date of execution, and authorized as proven by the cryptographic signature on the transaction that invokes this contract. diff --git a/contracts/identity/CMakeLists.txt b/contracts/identity/CMakeLists.txt deleted file mode 100644 index 230adcda29c..00000000000 --- a/contracts/identity/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_library(TARGET identity_common - SOURCE_FILES common.cpp - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) - -add_wast_executable(TARGET identity - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES identity_common libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) - -add_wast_library(TARGET identity_interface - SOURCE_FILES interface.cpp - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES identity_common libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) - -add_subdirectory(test) diff --git a/contracts/identity/common.cpp b/contracts/identity/common.cpp deleted file mode 100644 index 68e48bc6adb..00000000000 --- a/contracts/identity/common.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "common.hpp" - -#include - -namespace identity { - - bool identity_base::is_trusted_by( account_name trusted, account_name by ) { - trust_table t( _self, by ); - return t.find( trusted ) != t.end(); - } - - bool identity_base::is_trusted( account_name acnt ) { - account_name active_producers[21]; - auto active_prod_size = get_active_producers( active_producers, sizeof(active_producers) ); - auto count = active_prod_size / sizeof(account_name); - for( size_t i = 0; i < count; ++i ) { - if( active_producers[i] == acnt ) - return true; - } - for( size_t i = 0; i < count; ++i ) { - if( is_trusted_by( acnt, active_producers[i] ) ) - return true; - } - return false; - } - -} diff --git a/contracts/identity/common.hpp b/contracts/identity/common.hpp deleted file mode 100644 index 48d8cf39f9e..00000000000 --- a/contracts/identity/common.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include - -namespace identity { - - typedef uint64_t identity_name; - typedef uint64_t property_name; - typedef uint64_t property_type_name; - - struct certvalue { - property_name property; ///< name of property, base32 encoded i64 - std::string type; ///< defines type serialized in data - std::vector data; ///< - std::string memo; ///< meta data documenting basis of certification - uint8_t confidence = 1; ///< used to define liability for lies, - /// 0 to delete - - EOSLIB_SERIALIZE( certvalue, (property)(type)(data)(memo)(confidence) ) - }; - - struct certrow { - uint64_t id; - property_name property; - uint64_t trusted; - account_name certifier; - uint8_t confidence = 0; - std::string type; - std::vector data; - uint64_t primary_key() const { return id; } - /* constexpr */ static eosio::key256 key(uint64_t property, uint64_t trusted, uint64_t certifier) { - /* - key256 key; - key.uint64s[0] = property; - key.uint64s[1] = trusted; - key.uint64s[2] = certifier; - key.uint64s[3] = 0; - */ - return eosio::key256::make_from_word_sequence(property, trusted, certifier); - } - eosio::key256 get_key() const { return key(property, trusted, certifier); } - - EOSLIB_SERIALIZE( certrow , (property)(trusted)(certifier)(confidence)(type)(data)(id) ) - }; - - struct identrow { - uint64_t identity; - account_name creator; - - uint64_t primary_key() const { return identity; } - - EOSLIB_SERIALIZE( identrow , (identity)(creator) ) - }; - - struct trustrow { - account_name account; - - uint64_t primary_key() const { return account; } - - EOSLIB_SERIALIZE( trustrow, (account) ) - }; - - typedef eosio::multi_index > - > certs_table; - typedef eosio::multi_index idents_table; - typedef eosio::singleton accounts_table; - typedef eosio::multi_index trust_table; - - class identity_base { - public: - identity_base( account_name acnt) : _self( acnt ) {} - - bool is_trusted_by( account_name trusted, account_name by ); - - bool is_trusted( account_name acnt ); - - protected: - account_name _self; - }; - -} - diff --git a/contracts/identity/identity.abi b/contracts/identity/identity.abi deleted file mode 100644 index cbb3e2373bf..00000000000 --- a/contracts/identity/identity.abi +++ /dev/null @@ -1,118 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - },{ - "new_type_name": "identity_name", - "type": "name" - },{ - "new_type_name": "property_name", - "type": "name" - } - ], - "structs": [{ - "name": "create", - "base": "", - "fields": [ - {"name":"creator", "type":"account_name"}, - {"name":"identity", "type":"uint64"} - ] - },{ - "name": "certvalue", - "base": "", - "fields": [ - {"name":"property", "type":"name"}, - {"name":"type", "type":"string"}, - {"name":"data", "type":"uint8[]"}, - {"name":"memo", "type":"string"}, - {"name":"confidence", "type":"uint8"} - ] - },{ - "name": "certprop", - "base": "", - "fields": [ - {"name":"bill_storage_to", "type":"account_name"}, - {"name":"certifier", "type":"account_name"}, - {"name":"identity", "type":"uint64"}, - {"name":"value", "type":"certvalue[]"} - ] - },{ - "name": "settrust", - "base": "", - "fields": [ - {"name":"trustor", "type":"account_name"}, - {"name":"trusting", "type":"account_name"}, - {"name":"trust", "type":"uint8"} - ] - },{ - "name": "certrow", - "base": "", - "fields": [ - {"name":"property", "type":"property_name"}, - {"name":"trusted", "type":"uint64"}, - {"name":"certifier", "type":"account_name"}, - {"name":"confidence", "type":"uint8"}, - {"name":"type", "type":"string"}, - {"name":"data", "type":"uint8[]"} - ] - },{ - "name": "identrow", - "base": "", - "fields": [ - {"name":"identity", "type":"uint64"}, - {"name":"creator", "type":"account_name"} - ] - },{ - "name": "accountrow", - "base": "", - "fields": [ - {"name":"identity", "type":"uint64"} - ] - } - ], - "actions": [{ - "name": "create", - "type": "create", - "ricardian_contract": "" - },{ - "name": "certprop", - "type": "certprop", - "ricardian_contract": "" - },{ - "name": "settrust", - "type": "settrust", - "ricardian_contract": "" - } - ], - "tables": [{ - "name": "certs", - "type": "certrow", - "index_type": "i64i64i64", - "key_names" : [ - "property", - "trusted", - "certifier" - ], - " key_types": [ - "uint64", - "uint64", - "uint64" - ] - },{ - "name": "idents", - "type": "identrow", - "index_type": "i64", - "key_names" : [ "identity" ], - "key_types": [ "uint64" ] - },{ - "name": "trust", - "type": "account_name", - "index_type": "i64", - "key_names" : [ "account" ], - "key_types": [ "account_name" ] - } - ], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/identity/identity.cpp b/contracts/identity/identity.cpp deleted file mode 100644 index c33cd66d526..00000000000 --- a/contracts/identity/identity.cpp +++ /dev/null @@ -1,188 +0,0 @@ -#include "common.hpp" - -#include -#include -#include - -namespace identity { - using eosio::action_meta; - using eosio::singleton; - using eosio::key256; - using std::string; - using std::vector; - - /** - * This contract maintains a graph database of certified statements about an - * identity. An identity is separated from the concept of an account because - * the mapping of identity to accounts is subject to community consensus. - * - * Some use cases need a global source of trust, this trust rooted in the voter - * who selects block producers. A block producer's opinion is "trusted" and so - * is the opinion of anyone the block producer marks as "trusted". - * - * When a block producer is voted out the implicit trust in every certification - * they made or those they trusted made is removed. All users are liable for - * making false certifications. - * - * An account needs to claim the identity and a trusted account must certify the - * claim. - * - * Data for an identity is stored: - * - * DeployToAccount / identity / certs / [property, trusted, certifier] => value - * - * Questions database is designed to answer: - * - * 1. has $identity.$unique been certified a "trusted" certifier - * 2. has $identity.$property been certified by $account - * 3. has $identity.$trusted been certified by a "trusted" certifier - * 4. what account has authority to speak on behalf of identity? - * - for each trusted owner certification - * check to see if the account has claimed it - * - * 5. what identity does account have authority to speak on behalf? - * - check what identity the account has self certified owner - * - verify that a trusted certifier has confirmed owner - * - * This database structure enables parallel opeartions on independent identities. - * - * When an account certs a property we check to see if that - */ - class contract : public identity_base { - public: - - using identity_base::identity_base; - - void settrust( const account_name trustor, ///< the account authorizing the trust - const account_name trusting, ///< the account receiving the trust - const uint8_t trust = 0 )/// 0 to remove, -1 to mark untrusted, 1 to mark trusted - { - require_auth( trustor ); - require_recipient( trusting ); - - trust_table table( _self, trustor ); - auto itr = table.find(trusting); - if( itr == table.end() && trust > 0 ) { - table.emplace( trustor, [&](trustrow& row) { - row.account = trusting; - }); - } else if( itr != table.end() && trust == 0 ) { - table.erase(itr); - } - } - - /** - * This action create a new globally unique 64 bit identifier, - * to minimize collisions each account is automatically assigned - * a 32 bit identity prefix based upon hash(account_name) ^ hash(tapos). - * - * With this method no two accounts are likely to be assigned the same - * 32 bit prefix consistantly due to the constantly changing tapos. This prevents - * abuse of 'creator' selection to generate intentional conflicts with other users. - * - * The creator can determine the last 32 bits using an algorithm of their choice. We - * presume the creator's algorithm can avoid collisions with itself. - * - * Even if two accounts get a collision in first 32 bits, a proper creator algorithm - * should generate randomness in last 32 bits that will minimize collisions. In event - * of collision transaction will fail and creator can try again. - * - * A 64 bit identity is used because the key is used frequently and it makes for more - * effecient tables/scopes/etc. - */ - void create( const account_name creator, const uint64_t identity ) { - require_auth( creator ); - idents_table t( _self, _self ); - auto itr = t.find( identity ); - eosio_assert( itr == t.end(), "identity already exists" ); - eosio_assert( identity != 0, "identity=0 is not allowed" ); - t.emplace(creator, [&](identrow& i) { - i.identity = identity; - i.creator = creator; - }); - } - - void certprop( const account_name bill_storage_to, ///< account which is paying for storage - const account_name certifier, - const identity_name identity, - const vector& values ) - { - require_auth( certifier ); - if( bill_storage_to != certifier ) - require_auth( bill_storage_to ); - - idents_table t( _self, _self ); - eosio_assert( t.find( identity ) != t.end(), "identity does not exist" ); - - /// the table exists in the scope of the identity - certs_table certs( _self, identity ); - bool trusted = is_trusted( certifier ); - - for( const auto& value : values ) { - auto idx = certs.template get_index(); - if (value.confidence) { - eosio_assert(value.type.size() <= 32, "certrow::type should be not longer than 32 bytes"); - auto itr = idx.lower_bound( certrow::key(value.property, trusted, certifier) ); - - if (itr != idx.end() && itr->property == value.property && itr->trusted == trusted && itr->certifier == certifier) { - idx.modify(itr, 0, [&](certrow& row) { - row.confidence = value.confidence; - row.type = value.type; - row.data = value.data; - }); - } else { - auto pk = certs.available_primary_key(); - certs.emplace(_self, [&](certrow& row) { - row.id = pk; - row.property = value.property; - row.trusted = trusted; - row.certifier = certifier; - row.confidence = value.confidence; - row.type = value.type; - row.data = value.data; - }); - } - - auto itr_old = idx.lower_bound( certrow::key(value.property, !trusted, certifier) ); - if (itr_old != idx.end() && itr_old->property == value.property && itr_old->trusted == !trusted && itr_old->certifier == certifier) { - idx.erase(itr_old); - } - - //special handling for owner - if (value.property == N(owner)) { - eosio_assert(sizeof(account_name) == value.data.size(), "data size doesn't match account_name size"); - account_name acnt = *reinterpret_cast(value.data.data()); - if (certifier == acnt) { //only self-certitication affects accounts_table - accounts_table( _self, acnt ).set( identity, acnt ); - } - } - } else { - bool removed = false; - auto itr = idx.lower_bound( certrow::key(value.property, trusted, certifier) ); - if (itr != idx.end() && itr->property == value.property && itr->trusted == trusted && itr->certifier == certifier) { - idx.erase(itr); - } else { - removed = true; - } - itr = idx.lower_bound( certrow::key(value.property, !trusted, certifier) ); - if (itr != idx.end() && itr->property == value.property && itr->trusted == !trusted && itr->certifier == certifier) { - idx.erase(itr); - } else { - removed = true; - } - //special handling for owner - if (value.property == N(owner)) { - eosio_assert(sizeof(account_name) == value.data.size(), "data size doesn't match account_name size"); - account_name acnt = *reinterpret_cast(value.data.data()); - if (certifier == acnt) { //only self-certitication affects accounts_table - accounts_table( _self, acnt ).remove(); - } - } - } - } - } - }; - -} /// namespace identity - -EOSIO_ABI( identity::contract, (create)(certprop)(settrust) ); diff --git a/contracts/identity/interface.cpp b/contracts/identity/interface.cpp deleted file mode 100644 index fb633bc52a8..00000000000 --- a/contracts/identity/interface.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "interface.hpp" - -namespace identity { - -identity_name interface::get_claimed_identity( account_name acnt ) { - return accounts_table( _self, acnt ).get_or_default(0); -} - -account_name interface::get_owner_for_identity( uint64_t receiver, identity_name ident ) { - // for each trusted owner certification - // check to see if the certification is still trusted - // check to see if the account has claimed it - certs_table certs( _self, ident ); - auto idx = certs.template get_index(); - auto itr = idx.lower_bound(certrow::key(N(owner), 1, 0)); - account_name owner = 0; - while (itr != idx.end() && itr->property == N(owner) && itr->trusted) { - if (sizeof(account_name) == itr->data.size()) { - account_name account = *reinterpret_cast(itr->data.data()); - if (ident == get_claimed_identity(account)) { - if (is_trusted(itr->certifier) ) { - // the certifier is still trusted - if (!owner || owner == account) { - owner = account; - } else { - //contradiction found: different owners certified for the same identity - return 0; - } - } else if (_self == receiver){ - //the certifier is no longer trusted, need to unset the flag - idx.modify(itr, 0, [&](certrow& r) { - r.trusted = 0; - }); - } else { - // the certifier is no longer trusted, but the code runs in read-only mode - } - } - } else { - // bad row - skip it - } - ++itr; - } - if (owner) { - //owner found, no contradictions among certifications flaged as trusted - return owner; - } - // trusted certification not found - // let's see if any untrusted certifications became trusted - itr = idx.lower_bound(certrow::key(N(owner), 0, 0)); - while (itr != idx.end() && itr->property == N(owner) && !itr->trusted) { - if (sizeof(account_name) == itr->data.size()) { - account_name account = *reinterpret_cast(itr->data.data()); - if (ident == get_claimed_identity(account) && is_trusted(itr->certifier)) { - if (_self == receiver) { - // the certifier became trusted and we have permissions to update the flag - idx.modify(itr, 0, [&](certrow& r) { - r.trusted = 1; - }); - } - if (!owner || owner == account) { - owner = account; - } else { - //contradiction found: different owners certified for the same identity - return 0; - } - } - } else { - // bad row - skip it - } - ++itr; - } - return owner; -} - -identity_name interface::get_identity_for_account( uint64_t receiver, account_name acnt ) { - // check what identity the account has self certified owner - // verify that a trusted certifier has confirmed owner - auto identity = get_claimed_identity(acnt); - return (identity != 0 && acnt == get_owner_for_identity(receiver, identity)) ? identity : 0; -} - -} // namespace identity diff --git a/contracts/identity/interface.hpp b/contracts/identity/interface.hpp deleted file mode 100644 index 5415bbbdb57..00000000000 --- a/contracts/identity/interface.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "common.hpp" - -namespace identity { - - class interface : public identity_base { - public: - using identity_base::identity_base; - - identity_name get_claimed_identity( account_name acnt ); - - account_name get_owner_for_identity( uint64_t receiver, identity_name ident ); - - identity_name get_identity_for_account( uint64_t receiver, account_name acnt ); - }; - -} diff --git a/contracts/identity/test/CMakeLists.txt b/contracts/identity/test/CMakeLists.txt deleted file mode 100644 index 739341339a1..00000000000 --- a/contracts/identity/test/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -set(ABI_FILES "identity_test.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) -add_wast_executable(TARGET identity_test - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES identity_interface identity_common libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/identity/test/identity_test.abi b/contracts/identity/test/identity_test.abi deleted file mode 100644 index a0b450f8ac4..00000000000 --- a/contracts/identity/test/identity_test.abi +++ /dev/null @@ -1,35 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - },{ - "new_type_name": "identity_name", - "type": "name" - } - ], - "structs": [{ - "name": "getowner", - "base": "", - "fields": [ - {"name":"identity", "type":"uint64"} - ] - },{ - "name": "getidentity", - "base": "", - "fields": [ - {"name":"account", "type":"account_name"} - ] - } - ], - "actions": [{ - "name": "getowner", - "type": "getowner" - },{ - "name": "getidentity", - "type": "getidentity" - } - ], - "tables": [ - ] -} diff --git a/contracts/identity/test/identity_test.cpp b/contracts/identity/test/identity_test.cpp deleted file mode 100644 index 4688d4db4db..00000000000 --- a/contracts/identity/test/identity_test.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include -#include - -namespace identity_test { - - using eosio::action_meta; - using eosio::singleton; - using std::string; - using std::vector; - - class contract : public eosio::contract { - public: - static constexpr uint64_t code = N(identitytest); - typedef singleton result_table; - - using eosio::contract::contract; - - void getowner( const uint64_t identity ) { - identity::interface iface( N(identity) ); - account_name owner = iface.get_owner_for_identity(current_receiver(), identity); - result_table( code, 0 ).set( owner, code ); //use scope = 0 for simplicity - } - - void getidentity( const account_name account ) { - identity::interface iface( N(identity) ); - identity::identity_name idnt = iface.get_identity_for_account(current_receiver(), account); - result_table( code, 0 ).set(idnt, code ); //use scope = 0 for simplicity - } - }; - -} /// namespace identity - -EOSIO_ABI( identity_test::contract, (getowner)(getidentity) ); diff --git a/contracts/integration_test/CMakeLists.txt b/contracts/integration_test/CMakeLists.txt deleted file mode 100644 index 6439a566f36..00000000000 --- a/contracts/integration_test/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET integration_test - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc libc++ eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/integration_test/integration_test.abi b/contracts/integration_test/integration_test.abi deleted file mode 100644 index 6f181b255ba..00000000000 --- a/contracts/integration_test/integration_test.abi +++ /dev/null @@ -1,41 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - }], - "structs": [{ - "name": "store", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"to", "type":"account_name"}, - {"name":"num", "type":"uint64"} - ] - },{ - "name": "payload", - "base": "", - "fields": [ - {"name":"key", "type":"uint64"}, - {"name":"data", "type":"uint64[]"} - ] - } - ], - "actions": [{ - "name": "store", - "type": "store", - "ricardian_contract": "" - } - - ], - "tables": [{ - "name": "payloads", - "type": "payload", - "index_type": "i64", - "key_names" : ["key"], - "key_types" : ["uint64"] - } - ], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/integration_test/integration_test.cpp b/contracts/integration_test/integration_test.cpp deleted file mode 100644 index 6b6997903b7..00000000000 --- a/contracts/integration_test/integration_test.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -using namespace eosio; - -struct integration_test : public eosio::contract { - using contract::contract; - - struct payload { - uint64_t key; - vector data; - - uint64_t primary_key()const { return key; } - }; - typedef eosio::multi_index payloads; - - /// @abi action - void store( account_name from, - account_name to, - uint64_t num ) { - require_auth( from ); - eosio_assert( is_account( to ), "to account does not exist"); - eosio_assert( num < std::numeric_limits::max(), "num to large"); - payloads data ( _self, from ); - uint64_t key = 0; - const uint64_t num_keys = 5; - while (data.find( key ) != data.end()) { - key += num_keys; - } - for (size_t i = 0; i < num_keys; ++i) { - data.emplace(from, [&]( auto& g ) { - g.key = key + i; - g.data = vector( static_cast(num), 5); - }); - } - } -}; - -EOSIO_ABI( integration_test, (store) ) diff --git a/contracts/libc++/CMakeLists.txt b/contracts/libc++/CMakeLists.txt deleted file mode 100644 index 6fc747de469..00000000000 --- a/contracts/libc++/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -SET(SRC_FILENAMES algorithm.cpp any.cpp bind.cpp condition_variable.cpp exception.cpp functional.cpp - future.cpp ios.cpp iostream.cpp locale.cpp memory.cpp mutex.cpp new.cpp optional.cpp - regex.cpp shared_mutex.cpp stdexcept.cpp string.cpp strstream.cpp system_error.cpp - thread.cpp typeinfo.cpp utility.cpp valarray.cpp variant.cpp vector.cpp) - -#SET(SRC_FILENAMES exception.cpp) - -SET(SRC_FILES "") -FOREACH(FN ${SRC_FILENAMES}) - LIST(APPEND SRC_FILES "upstream/src/${FN}") -ENDFOREACH(FN) - -add_wast_library(TARGET libc++ - NOWARNINGS - SOURCE_FILES "${SRC_FILES}" - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/libc++/upstream b/contracts/libc++/upstream deleted file mode 160000 index 2880ac42909..00000000000 --- a/contracts/libc++/upstream +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2880ac42909d4bb29687ed079f8bb4405c3b0869 diff --git a/contracts/multi_index_test/CMakeLists.txt b/contracts/multi_index_test/CMakeLists.txt deleted file mode 100644 index 40a4eef16fd..00000000000 --- a/contracts/multi_index_test/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) -add_wast_executable(TARGET multi_index_test - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) - diff --git a/contracts/multi_index_test/multi_index_test.abi b/contracts/multi_index_test/multi_index_test.abi deleted file mode 100644 index 6679fa67b16..00000000000 --- a/contracts/multi_index_test/multi_index_test.abi +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [], - "structs": [{ - "name": "trigger", - "base": "", - "fields": [ - {"name": "what", "type": "uint32" } - ] - } - ], - "actions": [{ - "name": "trigger", - "type": "trigger", - "ricaridian_contract": "" - } - ], - "tables": [], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/multi_index_test/multi_index_test.cpp b/contracts/multi_index_test/multi_index_test.cpp deleted file mode 100644 index 531984f28fe..00000000000 --- a/contracts/multi_index_test/multi_index_test.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include - -using namespace eosio; - -namespace multi_index_test { - -struct limit_order { - uint64_t id; - uint64_t padding = 0; - uint128_t price; - uint64_t expiration; - account_name owner; - - auto primary_key()const { return id; } - uint64_t get_expiration()const { return expiration; } - uint128_t get_price()const { return price; } - - EOSLIB_SERIALIZE( limit_order, (id)(price)(expiration)(owner) ) - }; - - struct test_k256 { - uint64_t id; - key256 val; - - auto primary_key()const { return id; } - key256 get_val()const { return val; } - - EOSLIB_SERIALIZE( test_k256, (id)(val) ) - }; - - class snapshot_test { - public: - - ACTION(N(multitest), trigger) { - trigger(): what(0) {} - trigger(uint32_t w): what(w) {} - - uint32_t what; - - EOSLIB_SERIALIZE(trigger, (what)) - }; - - static void on(const trigger& act) - { - auto payer = act.get_account(); - print("Acting on trigger action.\n"); - switch(act.what) - { - case 0: - { - print("Testing uint128_t secondary index.\n"); - eosio::multi_index >, - indexed_by< N(byprice), const_mem_fun > - > orders( N(multitest), N(multitest) ); - - orders.emplace( payer, [&]( auto& o ) { - o.id = 1; - o.expiration = 300; - o.owner = N(dan); - }); - - auto order2 = orders.emplace( payer, [&]( auto& o ) { - o.id = 2; - o.expiration = 200; - o.owner = N(alice); - }); - - print("Items sorted by primary key:\n"); - for( const auto& item : orders ) { - print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); - } - - auto expidx = orders.get_index(); - - print("Items sorted by expiration:\n"); - for( const auto& item : expidx ) { - print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); - } - - print("Modifying expiration of order with ID=2 to 400.\n"); - orders.modify( order2, payer, [&]( auto& o ) { - o.expiration = 400; - }); - - print("Items sorted by expiration:\n"); - for( const auto& item : expidx ) { - print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); - } - - auto lower = expidx.lower_bound(100); - - print("First order with an expiration of at least 100 has ID=", lower->id, " and expiration=", lower->get_expiration(), "\n"); - - } - break; - case 1: // Test key265 secondary index - { - print("Testing key256 secondary index.\n"); - eosio::multi_index > - > testtable( N(multitest), N(exchange) ); // Code must be same as the receiver? Scope doesn't have to be. - - testtable.emplace( payer, [&]( auto& o ) { - o.id = 1; - o.val = key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 42ULL); - }); - - testtable.emplace( payer, [&]( auto& o ) { - o.id = 2; - o.val = key256::make_from_word_sequence(1ULL, 2ULL, 3ULL, 4ULL); - }); - - testtable.emplace( payer, [&]( auto& o ) { - o.id = 3; - o.val = key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 42ULL); - }); - - auto itr = testtable.find( 2 ); - - print("Items sorted by primary key:\n"); - for( const auto& item : testtable ) { - print(" ID=", item.primary_key(), ", val=", item.val, "\n"); - } - - auto validx = testtable.get_index(); - - auto lower1 = validx.lower_bound(key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 40ULL)); - print("First entry with a val of at least 40 has ID=", lower1->id, ".\n"); - - auto lower2 = validx.lower_bound(key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 50ULL)); - print("First entry with a val of at least 50 has ID=", lower2->id, ".\n"); - - if( testtable.iterator_to(*lower2) == itr ) { - print("Previously found entry is the same as the one found earlier with a primary key value of 2.\n"); - } - - print("Items sorted by val (secondary key):\n"); - for( const auto& item : validx ) { - print(" ID=", item.primary_key(), ", val=", item.val, "\n"); - } - - auto upper = validx.upper_bound(key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 42ULL)); - - print("First entry with a val greater than 42 has ID=", upper->id, ".\n"); - - print("Removed entry with ID=", lower1->id, ".\n"); - validx.erase( lower1 ); - - print("Items sorted by primary key:\n"); - for( const auto& item : testtable ) { - print(" ID=", item.primary_key(), ", val=", item.val, "\n"); - } - - } - break; - default: - eosio_assert(0, "Given what code is not supported."); - break; - } - } - }; - -} /// multi_index_test - -namespace multi_index_test { - extern "C" { - /// The apply method implements the dispatch of events to this contract - void apply( uint64_t /* receiver */, uint64_t code, uint64_t action ) { - require_auth(code); - eosio_assert(eosio::dispatch(code, action), - "Could not dispatch"); - } - } -} diff --git a/contracts/musl/CMakeLists.txt b/contracts/musl/CMakeLists.txt deleted file mode 100644 index d9794c311ed..00000000000 --- a/contracts/musl/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -file(GLOB CRYPT_SOURCES "upstream/src/crypt/*.c") -file(GLOB CTYPE_SOURCES "upstream/src/ctype/*.c") -file(GLOB ENV_SOURCES "upstream/src/env/*.c") -file(GLOB ERRNO_SOURCES "upstream/src/errno/*.c") -file(GLOB EXIT_SOURCES "upstream/src/exit/*.c") -file(GLOB LOCALE_SOURCES "upstream/src/locale/*.c") -file(GLOB MATH_SOURCES "upstream/src/math/*.c") -file(GLOB MBYTE_SOURCES "upstream/src/multibyte/*.c") -file(GLOB MISC_SOURCES "upstream/src/misc/*.c") -file(GLOB SEARCH_SOURCES "upstream/src/search/*.c") -file(GLOB STDIO_SOURCES "upstream/src/stdio/*.c") -file(GLOB STDLIB_SOURCES "upstream/src/stdlib/*.c") -file(GLOB STRING_SOURCES "upstream/src/string/*.c") -file(GLOB TIME_SOURCES "upstream/src/time/*.c") -file(GLOB THREAD_SOURCES "upstream/src/thread/*.c") #only for __lock __unlock -set(INTERNAL_SOURCES upstream/src/internal/floatscan.c upstream/src/internal/intscan.c upstream/src/internal/shgetc.c upstream/src/internal/libc.c) - -add_wast_library(TARGET libc - NOWARNINGS - SOURCE_FILES ${CRYPT_SOURCES} ${CTYPE_SOURCES} ${ENV_SOURCES} ${ERRNO_SOURCES} ${EXIT_SOURCES} ${INTERNAL_SOURCES} ${LOCALE_SOURCES} ${MATH_SOURCES} - ${MBYTE_SOURCES} ${MISC_SOURCES} ${SEARCH_SOURCES} ${STDIO_SOURCES} ${STDLIB_SOURCES} ${STRING_SOURCES} ${TIME_SOURCES} ${THREAD_SOURCES} - INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include - ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/src/internal - ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/arch/eos - ${CMAKE_SOURCE_DIR}/contracts/ - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/musl/upstream b/contracts/musl/upstream deleted file mode 160000 index 8a34536ac97..00000000000 --- a/contracts/musl/upstream +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8a34536ac9764c90c86cc0b62d0cda07449fd5d8 diff --git a/contracts/noop/CMakeLists.txt b/contracts/noop/CMakeLists.txt deleted file mode 100644 index 6aadc90d01b..00000000000 --- a/contracts/noop/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) -add_wast_executable(TARGET noop - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) - diff --git a/contracts/noop/noop.abi b/contracts/noop/noop.abi deleted file mode 100644 index 34f52bd1406..00000000000 --- a/contracts/noop/noop.abi +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - } - ], - "structs": [{ - "name": "anyaction", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"type", "type":"string"}, - {"name":"data", "type":"string"} - ] - } - ], - "actions": [{ - "name":"anyaction", - "type":"anyaction", - "ricardian_contract": "" - } -], - "tables": [], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/noop/noop.cpp b/contracts/noop/noop.cpp deleted file mode 100644 index 6699eca57c9..00000000000 --- a/contracts/noop/noop.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ - -#include - -namespace eosio { - - class noop: public contract { - public: - noop( account_name self ): contract( self ) { } - void anyaction( account_name from, - const std::string& /*type*/, - const std::string& /*data*/ ) - { - require_auth( from ); - } - }; - - EOSIO_ABI( noop, ( anyaction ) ) - -} /// eosio diff --git a/contracts/payloadless/CMakeLists.txt b/contracts/payloadless/CMakeLists.txt deleted file mode 100644 index 16bad40cb27..00000000000 --- a/contracts/payloadless/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET payloadless - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc libc++ eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/payloadless/payloadless.abi b/contracts/payloadless/payloadless.abi deleted file mode 100644 index 1ea79c6f275..00000000000 --- a/contracts/payloadless/payloadless.abi +++ /dev/null @@ -1,59 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-04-19T09:07:16", - "types": [], - "structs": [{ - "name": "doit", - "base": "", - "fields": [] - } - ], - "actions": [{ - "name": "doit", - "type": "doit", - "ricardian_contract": "# CONTRACT FOR payloadless::doit## ACTION NAME: doit\n### Parameters### Parameters\nInput paramters:Input paramters:\n\nImplied parameters: Implied parameters: \n\n### Intent### Intent\nINTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.INTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.\n\n### Term### Term\nTERM. This Contract expires at the conclusion of code execution.TERM. This Contract expires at the conclusion of code execution.\n" - } - ], - "tables": [], - "ricardian_clauses": [{ - "id": "Warranty", - "body": "WARRANTY. The invoker of the contract action shall uphold its Obligations under this Contract in a timely and workmanlike manner, using knowledge and recommendations for performing the services which meet generally acceptable standards set forth by EOS.IO Blockchain Block Producers.\n\n" - },{ - "id": "Default", - "body": "DEFAULT. The occurrence of any of the following shall constitute a material default under this Contract: \n\n" - },{ - "id": "Remedies", - "body": "REMEDIES. In addition to any and all other rights a party may have available according to law, if a party defaults by failing to substantially perform any provision, term or condition of this Contract, the other party may terminate the Contract by providing written notice to the defaulting party. This notice shall describe with sufficient detail the nature of the default. The party receiving such notice shall promptly be removed from being a Block Producer and this Contract shall be automatically terminated. \n \n" - },{ - "id": "Force Majeure", - "body": "FORCE MAJEURE. If performance of this Contract or any obligation under this Contract is prevented, restricted, or interfered with by causes beyond either party's reasonable control (\"Force Majeure\"), and if the party unable to carry out its obligations gives the other party prompt written notice of such event, then the obligations of the party invoking this provision shall be suspended to the extent necessary by such event. The term Force Majeure shall include, without limitation, acts of God, fire, explosion, vandalism, storm or other similar occurrence, orders or acts of military or civil authority, or by national emergencies, insurrections, riots, or wars, or strikes, lock-outs, work stoppages, or supplier failures. The excused party shall use reasonable efforts under the circumstances to avoid or remove such causes of non-performance and shall proceed to perform with reasonable dispatch whenever such causes are removed or ceased. An act or omission shall be deemed within the reasonable control of a party if committed, omitted, or caused by such party, or its employees, officers, agents, or affiliates. \n \n" - },{ - "id": "Dispute Resolution", - "body": "DISPUTE RESOLUTION. Any controversies or disputes arising out of or relating to this Contract will be resolved by binding arbitration under the default rules set forth by the EOS.IO Blockchain. The arbitrator's award will be final, and judgment may be entered upon it by any court having proper jurisdiction. \n \n" - },{ - "id": "Entire Agreement", - "body": "ENTIRE AGREEMENT. This Contract contains the entire agreement of the parties, and there are no other promises or conditions in any other agreement whether oral or written concerning the subject matter of this Contract. This Contract supersedes any prior written or oral agreements between the parties. \n\n" - },{ - "id": "Severability", - "body": "SEVERABILITY. If any provision of this Contract will be held to be invalid or unenforceable for any reason, the remaining provisions will continue to be valid and enforceable. If a court finds that any provision of this Contract is invalid or unenforceable, but that by limiting such provision it would become valid and enforceable, then such provision will be deemed to be written, construed, and enforced as so limited. \n\n" - },{ - "id": "Amendment", - "body": "AMENDMENT. This Contract may be modified or amended in writing by mutual agreement between the parties, if the writing is signed by the party obligated under the amendment. \n\n" - },{ - "id": "Governing Law", - "body": "GOVERNING LAW. This Contract shall be construed in accordance with the Maxims of Equity. \n\n" - },{ - "id": "Notice", - "body": "NOTICE. Any notice or communication required or permitted under this Contract shall be sufficiently given if delivered to a verifiable email address or to such other email address as one party may have publicly furnished in writing, or published on a broadcast contract provided by this blockchain for purposes of providing notices of this type. \n" - },{ - "id": "Waiver of Contractual Right", - "body": "WAIVER OF CONTRACTUAL RIGHT. The failure of either party to enforce any provision of this Contract shall not be construed as a waiver or limitation of that party's right to subsequently enforce and compel strict compliance with every provision of this Contract. \n\n" - },{ - "id": "Arbitrator's Fees to Prevailing Party", - "body": "ARBITRATOR'S FEES TO PREVAILING PARTY. In any action arising hereunder or any separate action pertaining to the validity of this Agreement, both sides shall pay half the initial cost of arbitration, and the prevailing party shall be awarded reasonable arbitrator's fees and costs.\n \n" - },{ - "id": "Construction and Interpretation", - "body": "CONSTRUCTION AND INTERPRETATION. The rule requiring construction or interpretation against the drafter is waived. The document shall be deemed as if it were drafted by both parties in a mutual effort. \n \n" - } - ] -} \ No newline at end of file diff --git a/contracts/payloadless/payloadless.cpp b/contracts/payloadless/payloadless.cpp deleted file mode 100644 index b67c7e23b3a..00000000000 --- a/contracts/payloadless/payloadless.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -using namespace eosio; - -class payloadless : public eosio::contract { - public: - using contract::contract; - - void doit() { - print( "Im a payloadless action" ); - } -}; - -EOSIO_ABI( payloadless, (doit) ) diff --git a/contracts/proxy/CMakeLists.txt b/contracts/proxy/CMakeLists.txt deleted file mode 100644 index ad554e4dd16..00000000000 --- a/contracts/proxy/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET proxy - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" ${Boost_INCLUDE_DIR} - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/proxy/proxy.cpp b/contracts/proxy/proxy.cpp deleted file mode 100644 index 3d243fd4e02..00000000000 --- a/contracts/proxy/proxy.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include -#include -#include - -namespace proxy { - using namespace eosio; - - namespace configs { - - bool get(config &out, const account_name &self) { - auto it = db_find_i64(self, self, N(config), config::key); - if (it != -1) { - auto size = db_get_i64(it, (char*)&out, sizeof(config)); - eosio_assert(size == sizeof(config), "Wrong record size"); - return true; - } else { - return false; - } - } - - void store(const config &in, const account_name &self) { - auto it = db_find_i64(self, self, N(config), config::key); - if (it != -1) { - db_update_i64(it, self, (const char *)&in, sizeof(config)); - } else { - db_store_i64(self, N(config), self, config::key, (const char *)&in, sizeof(config)); - } - } - }; - - template - void apply_transfer(uint64_t receiver, account_name /* code */, const T& transfer) { - config code_config; - const auto self = receiver; - auto get_res = configs::get(code_config, self); - eosio_assert(get_res, "Attempting to use unconfigured proxy"); - if (transfer.from == self) { - eosio_assert(transfer.to == code_config.owner, "proxy may only pay its owner" ); - } else { - eosio_assert(transfer.to == self, "proxy is not involved in this transfer"); - T new_transfer = T(transfer); - new_transfer.from = self; - new_transfer.to = code_config.owner; - - auto id = code_config.next_id++; - configs::store(code_config, self); - - transaction out; - out.actions.emplace_back(permission_level{self, N(active)}, N(eosio.token), N(transfer), new_transfer); - out.delay_sec = code_config.delay; - out.send(id, self); - } - } - - void apply_setowner(uint64_t receiver, set_owner params) { - const auto self = receiver; - require_auth(params.owner); - config code_config; - configs::get(code_config, self); - code_config.owner = params.owner; - code_config.delay = params.delay; - eosio::print("Setting owner to: ", name{params.owner}, " with delay: ", params.delay, "\n"); - configs::store(code_config, self); - } - - template - void apply_onerror(uint64_t receiver, const onerror& error ) { - eosio::print("starting onerror\n"); - const auto self = receiver; - config code_config; - eosio_assert(configs::get(code_config, self), "Attempting use of unconfigured proxy"); - - auto id = code_config.next_id++; - configs::store(code_config, self); - - eosio::print("Resending Transaction: ", error.sender_id, " as ", id, "\n"); - transaction dtrx = error.unpack_sent_trx(); - dtrx.delay_sec = code_config.delay; - dtrx.send(id, self); - } -} - -using namespace proxy; -using namespace eosio; - -extern "C" { - - /// The apply method implements the dispatch of events to this contract - void apply( uint64_t receiver, uint64_t code, uint64_t action ) { - if( code == N(eosio) && action == N(onerror) ) { - apply_onerror( receiver, onerror::from_current_action() ); - } else if( code == N(eosio.token) ) { - if( action == N(transfer) ) { - apply_transfer(receiver, code, unpack_action_data()); - } - } else if( code == receiver ) { - if( action == N(setowner) ) { - apply_setowner(receiver, unpack_action_data()); - } - } - } -} diff --git a/contracts/proxy/proxy.hpp b/contracts/proxy/proxy.hpp deleted file mode 100644 index 924edd24b10..00000000000 --- a/contracts/proxy/proxy.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include - -namespace proxy { - - //@abi action - struct set_owner { - account_name owner; - uint32_t delay; - - EOSLIB_SERIALIZE( set_owner, (owner)(delay) ) - }; - - //@abi table - struct config { - config(){} - constexpr static uint64_t key = N(config); - account_name owner = 0; - uint32_t delay = 0; - uint32_t next_id = 0; - }; - -} /// namespace proxy diff --git a/contracts/skeleton/skeleton.cpp b/contracts/skeleton/skeleton.cpp deleted file mode 100644 index a4ad22e1f1b..00000000000 --- a/contracts/skeleton/skeleton.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include - -using namespace eosio; - -class hello : public eosio::contract { - public: - using contract::contract; - - /// @abi action - void hi( account_name user ) { - print( "Hello, ", name{user} ); - } -}; - -EOSIO_ABI( hello, (hi) ) diff --git a/contracts/skeleton/skeleton.hpp b/contracts/skeleton/skeleton.hpp deleted file mode 100644 index 2b621b6f2ed..00000000000 --- a/contracts/skeleton/skeleton.hpp +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include - - diff --git a/contracts/snapshot_test/CMakeLists.txt b/contracts/snapshot_test/CMakeLists.txt deleted file mode 100644 index 81af479e479..00000000000 --- a/contracts/snapshot_test/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) -add_wast_executable(TARGET snapshot_test - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) - diff --git a/contracts/snapshot_test/snapshot_test.abi b/contracts/snapshot_test/snapshot_test.abi deleted file mode 100644 index 0bddc7293ce..00000000000 --- a/contracts/snapshot_test/snapshot_test.abi +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [], - "structs": [{ - "name": "increment", - "base": "", - "fields": [ - {"name": "value", "type": "uint32" } - ] - } - ], - "actions": [{ - "name": "increment", - "type": "increment", - "ricaridian_contract": "" - } - ], - "tables": [], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/snapshot_test/snapshot_test.cpp b/contracts/snapshot_test/snapshot_test.cpp deleted file mode 100644 index 0ef6939f07e..00000000000 --- a/contracts/snapshot_test/snapshot_test.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include - -using namespace eosio; - -namespace snapshot_test { - - struct main_record { - uint64_t id; - double index_f64 = 0.0; - long double index_f128 = 0.0L; - uint64_t index_i64 = 0ULL; - uint128_t index_i128 = 0ULL; - key256 index_i256 = key256(); - - auto primary_key() const { return id; } - - auto get_index_f64 () const { return index_f64 ; } - auto get_index_f128 () const { return index_f128; } - auto get_index_i64 () const { return index_i64 ; } - auto get_index_i128 () const { return index_i128; } - const key256& get_index_i256 () const { return index_i256; } - - EOSLIB_SERIALIZE( main_record, (id)(index_f64)(index_f128)(index_i64)(index_i128)(index_i256) ) - }; - - struct increment { - increment(): value(0) {} - increment(uint32_t v): value(v) {} - - uint32_t value; - - EOSLIB_SERIALIZE(increment, (value)) - }; - - using multi_index_type = eosio::multi_index>, - indexed_by< N(byff), const_mem_fun>, - indexed_by< N(byi ), const_mem_fun>, - indexed_by< N(byii), const_mem_fun>, - indexed_by< N(byiiii), const_mem_fun> - >; - - static void exec( uint64_t self, uint32_t value ) { - multi_index_type data(self, self); - auto current = data.begin( ); - if( current == data.end() ) { - data.emplace( self, [&]( auto& r ) { - r.id = value; - r.index_f64 = value; - r.index_f128 = value; - r.index_i64 = value; - r.index_i128 = value; - r.index_i256.data()[0] = value; - }); - - } else { - data.modify( current, self, [&]( auto& r ) { - r.index_f64 += value; - r.index_f128 += value; - r.index_i64 += value; - r.index_i128 += value; - r.index_i256.data()[0] += value; - }); - } - } - -} /// multi_index_test - -namespace multi_index_test { - extern "C" { - /// The apply method implements the dispatch of events to this contract - void apply( uint64_t self, uint64_t code, uint64_t action ) { - require_auth(code); - eosio_assert(action == N(increment), "unsupported action"); - snapshot_test::exec(self, unpack_action_data().value); - } - } -} diff --git a/contracts/stltest/CMakeLists.txt b/contracts/stltest/CMakeLists.txt deleted file mode 100644 index 81d615ebbf2..00000000000 --- a/contracts/stltest/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -#file(GLOB ABI_FILES "*.abi") -set(ABI_FILES "stltest.abi") -add_wast_executable(TARGET stltest - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) - -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) diff --git a/contracts/stltest/stltest.abi b/contracts/stltest/stltest.abi deleted file mode 100644 index c341713d412..00000000000 --- a/contracts/stltest/stltest.abi +++ /dev/null @@ -1,47 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "my_account_name", - "type": "name" - } - ], - "structs": [{ - "name": "message", - "base": "", - "fields": [ - {"name":"from", "type":"my_account_name"}, - {"name":"to", "type":"my_account_name"}, - {"name": "message", "type":"string" } - ] - },{ - "name": "messages_count", - "base": "", - "fields": [ - {"name": "user", "type": "my_account_name"}, - {"name": "count", "type": "uint32"} - ] - } - ], - "actions": [{ - "name": "message", - "type": "message", - "ricardian_contract": "" - } - ], - "tables": [{ - "name": "msgsent", - "type": "messages_count", - "index_type": "i64", - "key_names" : ["user"], - "key_types" : ["my_account_name"] - },{ - "name": "msgreceived", - "type": "messages_count", - "index_type": "i64", - "key_names" : ["user"], - "key_types" : ["my_account_name"] - } - ], - "ricardian_clauses": [], - "abi_extensions": [] -} diff --git a/contracts/stltest/stltest.cpp b/contracts/stltest/stltest.cpp deleted file mode 100644 index baf975ff703..00000000000 --- a/contracts/stltest/stltest.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -// include entire libc -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//include entire libstdc++ -#include -#include -#include -#include -#include -//include -#include -#include -//include -#include -//include -#include -#include -#include -#include -#include -#include -//include -#include -//include -//include -#include -#include -#include -#include -#include -#include -#include -//include -#include -#include -#include -#include -#include -#include -//include -#include -//include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//include -#include -#include -#include -#include -//include -#include -#include -#include -#include -#include -#include -#include -#include -//include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -*/ -//include -#include - -using namespace eosio; -/* -namespace std { - extern ios_base __start_std_streams; -} -*/ -namespace stltest { - - struct MSTR { - MSTR() : x(7891) { - prints("ATTENTION! S::S() called\n"); - } - int x; - ~MSTR() { - prints("~MSTR"); - } - }; - - class contract { - public: - static const uint64_t sent_table_name = N(sent); - static const uint64_t received_table_name = N(received); - - struct message { - account_name from; - account_name to; - //string msg; - - static uint64_t get_account() { return N(stltest); } - static uint64_t get_name() { return N(message); } - - template - friend DataStream& operator << ( DataStream& ds, const message& m ){ - return ds << m.from << m.to;// << m.msg; - } - template - friend DataStream& operator >> ( DataStream& ds, message& m ){ - return ds >> m.from >> m.to;// >> m.msg; - } - }; - - static void f(const char* __restrict, ...) { - prints("f() called\n"); - } - - static void on( const message& ) { - /* manual initialization of global variable - new(&std::__start_std_streams)std::ios_base::Init; - */ - /* - std::ostringstream osm; - osm << "abcdef"; - std::string s = osm.str(); - prints_l(s.data(), s.size()); - */ - /* - prints("STD string: "); prints(s.c_str()); - prints("\nEOS string: "); prints_l(s2.get_data(), s2.get_size()); - */ - prints("STL test start\n"); - /* doesn't work with WASM::serializeWithInjection - printf("stdout output\n", 0); - fprintf(stderr, "stderr output\n", 0); - */ - void* ptr = malloc(10); - free(ptr); - f("abc", 10, 20); - - //auto mptr = new MSTR(); - //delete mptr; - - std::array arr; - arr.fill(3); - arr[0] = 0; - - std::vector v; - v.push_back(0); - - std::stack stack; - stack.push('J'); - stack.pop(); - - std::queue q; - q.push(0); - - std::deque dq; - dq.push_front(0.0f); - - std::list l; - l.push_back(0); - - std::string s = "abcdef"; - s.append(1, 'g'); - - std::map m; - m.emplace(0, 1); - m.lower_bound(2); - - std::set st; - st.insert(0); - st.erase(st.begin()); - st.count(0); - - //std::unordered_map hm; - //hm[0] = "abc"; - //std::unordered_set hs; - //hs.insert(0); - - sort(dq.begin(), dq.end()); - find_if(l.begin(), l.end(), [](uint32_t f) { return f < 10; }); - prints("STL test done.\n"); - //std::cout << "STL test done." << std::endl; - } - - static void apply( account_name c, action_name act) { - eosio::dispatch(c,act); - } - }; - -} /// namespace eosio - - -extern "C" { -/// The apply method implements the dispatch of events to this contract -void apply( uint64_t receiver, uint64_t code, uint64_t action ) { - (void)receiver; - stltest::contract::apply( code, action ); -} -} diff --git a/contracts/test.inline/CMakeLists.txt b/contracts/test.inline/CMakeLists.txt deleted file mode 100644 index 9b7d8dcb425..00000000000 --- a/contracts/test.inline/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET test.inline - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/test.inline/test.inline.abi b/contracts/test.inline/test.inline.abi deleted file mode 100644 index 614cfab2474..00000000000 --- a/contracts/test.inline/test.inline.abi +++ /dev/null @@ -1,29 +0,0 @@ -{ - "types": [], - "structs": [ - { - "name": "forward", - "base": "", - "fields": [ - {"name":"reqauth", "type":"account_name"}, - {"name":"forward_code", "type":"account_name"}, - {"name":"forward_auth", "type":"account_name"} - ] - }, - { - "name": "reqauth", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"} - ] - }], - "actions": [{ - "name": "reqauth", - "type": "reqauth" - },{ - "name": "forward", - "type": "forward" - } - ], - "tables": [] -} diff --git a/contracts/test.inline/test.inline.cpp b/contracts/test.inline/test.inline.cpp deleted file mode 100644 index eb6c5ed18c6..00000000000 --- a/contracts/test.inline/test.inline.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include - -EOSIO_ABI( eosio::testinline, (reqauth)(forward) ) diff --git a/contracts/test.inline/test.inline.hpp b/contracts/test.inline/test.inline.hpp deleted file mode 100644 index 96788107914..00000000000 --- a/contracts/test.inline/test.inline.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -namespace eosio { - - class testinline : public contract { - public: - testinline( action_name self ):contract(self){} - - void reqauth( account_name from ) { - require_auth( from ); - } - - void forward( action_name reqauth, account_name forward_code, account_name forward_auth ) { - require_auth( reqauth ); - INLINE_ACTION_SENDER(testinline, reqauth)( forward_code, {forward_auth,N(active)}, {forward_auth} ); - //SEND_INLINE_ACTION( testinline(forward_code), reqauth, {forward_auth,N(active)}, {forward_auth} ); - //eosio::dispatch_inline( N(forward_code), N(reqauth), {{forward_auth, N(active)}}, {forward_auth} ); - } - }; - -} /// namespace eosio diff --git a/contracts/test_api/CMakeLists.txt b/contracts/test_api/CMakeLists.txt deleted file mode 100644 index 1751c9300aa..00000000000 --- a/contracts/test_api/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -#set the MAX_MEMORY to 1MB for these tests; there were lots of memory unit tests that assume such - -add_wast_executable(TARGET test_api - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/test_api/test_api.cpp b/contracts/test_api/test_api.cpp deleted file mode 100644 index ce7b44d6c9f..00000000000 --- a/contracts/test_api/test_api.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include -#include - -#include "test_api.hpp" -#include "test_action.cpp" -#include "test_print.cpp" -#include "test_types.cpp" -#include "test_fixedpoint.cpp" -#include "test_compiler_builtins.cpp" -#include "test_crypto.cpp" -#include "test_chain.cpp" -#include "test_transaction.cpp" -#include "test_checktime.cpp" -#include "test_permission.cpp" -#include "test_datastream.cpp" - -account_name global_receiver; - -extern "C" { - void apply( uint64_t receiver, uint64_t code, uint64_t action ) { - if( code == N(eosio) && action == N(onerror) ) { - auto error = eosio::onerror::from_current_action(); - eosio::print("onerror called\n"); - auto error_trx = error.unpack_sent_trx(); - auto error_action = error_trx.actions.at(0).name; - - // Error handlers for deferred transactions in these tests currently only support the first action - - WASM_TEST_ERROR_HANDLER("test_action", "assert_false", test_transaction, assert_false_error_handler ); - - - return; - } - - if ( action == N(cf_action) ) { - test_action::test_cf_action(); - return; - } - WASM_TEST_HANDLER(test_action, assert_true_cf); - - if (action != WASM_TEST_ACTION("test_transaction", "stateful_api") && action != WASM_TEST_ACTION("test_transaction", "context_free_api")) - require_auth(code); - - //test_types - WASM_TEST_HANDLER(test_types, types_size); - WASM_TEST_HANDLER(test_types, char_to_symbol); - WASM_TEST_HANDLER(test_types, string_to_name); - WASM_TEST_HANDLER(test_types, name_class); - - //test_compiler_builtins - WASM_TEST_HANDLER(test_compiler_builtins, test_multi3); - WASM_TEST_HANDLER(test_compiler_builtins, test_divti3); - WASM_TEST_HANDLER(test_compiler_builtins, test_divti3_by_0); - WASM_TEST_HANDLER(test_compiler_builtins, test_udivti3); - WASM_TEST_HANDLER(test_compiler_builtins, test_udivti3_by_0); - WASM_TEST_HANDLER(test_compiler_builtins, test_modti3); - WASM_TEST_HANDLER(test_compiler_builtins, test_modti3_by_0); - WASM_TEST_HANDLER(test_compiler_builtins, test_umodti3); - WASM_TEST_HANDLER(test_compiler_builtins, test_umodti3_by_0); - WASM_TEST_HANDLER(test_compiler_builtins, test_lshlti3); - WASM_TEST_HANDLER(test_compiler_builtins, test_lshrti3); - WASM_TEST_HANDLER(test_compiler_builtins, test_ashlti3); - WASM_TEST_HANDLER(test_compiler_builtins, test_ashrti3); - - //test_action - WASM_TEST_HANDLER(test_action, read_action_normal); - WASM_TEST_HANDLER(test_action, read_action_to_0); - WASM_TEST_HANDLER(test_action, read_action_to_64k); - WASM_TEST_HANDLER_EX(test_action, require_notice); - WASM_TEST_HANDLER_EX(test_action, require_notice_tests); - WASM_TEST_HANDLER(test_action, require_auth); - WASM_TEST_HANDLER(test_action, assert_false); - WASM_TEST_HANDLER(test_action, assert_true); - WASM_TEST_HANDLER(test_action, test_current_time); - WASM_TEST_HANDLER(test_action, test_abort); - WASM_TEST_HANDLER_EX(test_action, test_current_receiver); - WASM_TEST_HANDLER(test_action, test_publication_time); - WASM_TEST_HANDLER(test_action, test_assert_code); - WASM_TEST_HANDLER_EX(test_action, test_ram_billing_in_notify); - - // test named actions - // We enforce action name matches action data type name, so name mangling will not work for these tests. - if ( action == N(dummy_action) ) { - test_action::test_dummy_action(); - return; - } - //test_print - WASM_TEST_HANDLER(test_print, test_prints); - WASM_TEST_HANDLER(test_print, test_prints_l); - WASM_TEST_HANDLER(test_print, test_printi); - WASM_TEST_HANDLER(test_print, test_printui); - WASM_TEST_HANDLER(test_print, test_printi128); - WASM_TEST_HANDLER(test_print, test_printui128); - WASM_TEST_HANDLER(test_print, test_printn); - WASM_TEST_HANDLER(test_print, test_printsf); - WASM_TEST_HANDLER(test_print, test_printdf); - WASM_TEST_HANDLER(test_print, test_printqf); - - //test crypto - WASM_TEST_HANDLER(test_crypto, test_recover_key); - WASM_TEST_HANDLER(test_crypto, test_recover_key_assert_true); - WASM_TEST_HANDLER(test_crypto, test_recover_key_assert_false); - WASM_TEST_HANDLER(test_crypto, test_sha1); - WASM_TEST_HANDLER(test_crypto, test_sha256); - WASM_TEST_HANDLER(test_crypto, test_sha512); - WASM_TEST_HANDLER(test_crypto, test_ripemd160); - WASM_TEST_HANDLER(test_crypto, sha1_no_data); - WASM_TEST_HANDLER(test_crypto, sha256_no_data); - WASM_TEST_HANDLER(test_crypto, sha512_no_data); - WASM_TEST_HANDLER(test_crypto, ripemd160_no_data); - WASM_TEST_HANDLER(test_crypto, sha256_null); - WASM_TEST_HANDLER(test_crypto, assert_sha256_false); - WASM_TEST_HANDLER(test_crypto, assert_sha256_true); - WASM_TEST_HANDLER(test_crypto, assert_sha1_false); - WASM_TEST_HANDLER(test_crypto, assert_sha1_true); - WASM_TEST_HANDLER(test_crypto, assert_sha512_false); - WASM_TEST_HANDLER(test_crypto, assert_sha512_true); - WASM_TEST_HANDLER(test_crypto, assert_ripemd160_false); - WASM_TEST_HANDLER(test_crypto, assert_ripemd160_true); - - //test transaction - WASM_TEST_HANDLER(test_transaction, test_tapos_block_num); - WASM_TEST_HANDLER(test_transaction, test_tapos_block_prefix); - WASM_TEST_HANDLER(test_transaction, send_action); - WASM_TEST_HANDLER(test_transaction, send_action_inline_fail); - WASM_TEST_HANDLER(test_transaction, send_action_empty); - WASM_TEST_HANDLER(test_transaction, send_action_large); - WASM_TEST_HANDLER(test_transaction, send_action_recurse); - WASM_TEST_HANDLER(test_transaction, test_read_transaction); - WASM_TEST_HANDLER(test_transaction, test_transaction_size); - WASM_TEST_HANDLER_EX(test_transaction, send_transaction); - WASM_TEST_HANDLER_EX(test_transaction, send_transaction_empty); - WASM_TEST_HANDLER_EX(test_transaction, send_transaction_trigger_error_handler); - WASM_TEST_HANDLER_EX(test_transaction, send_transaction_large); - WASM_TEST_HANDLER_EX(test_transaction, send_action_sender); - WASM_TEST_HANDLER(test_transaction, deferred_print); - WASM_TEST_HANDLER_EX(test_transaction, send_deferred_transaction); - WASM_TEST_HANDLER_EX(test_transaction, send_deferred_transaction_replace); - WASM_TEST_HANDLER(test_transaction, send_deferred_tx_with_dtt_action); - WASM_TEST_HANDLER(test_transaction, cancel_deferred_transaction_success); - WASM_TEST_HANDLER(test_transaction, cancel_deferred_transaction_not_found); - WASM_TEST_HANDLER(test_transaction, send_cf_action); - WASM_TEST_HANDLER(test_transaction, send_cf_action_fail); - WASM_TEST_HANDLER(test_transaction, stateful_api); - WASM_TEST_HANDLER(test_transaction, context_free_api); - WASM_TEST_HANDLER(test_transaction, new_feature); - WASM_TEST_HANDLER(test_transaction, active_new_feature); - WASM_TEST_HANDLER_EX(test_transaction, repeat_deferred_transaction); - - //test chain - WASM_TEST_HANDLER(test_chain, test_activeprods); - - // test fixed_point - WASM_TEST_HANDLER(test_fixedpoint, create_instances); - WASM_TEST_HANDLER(test_fixedpoint, test_addition); - WASM_TEST_HANDLER(test_fixedpoint, test_subtraction); - WASM_TEST_HANDLER(test_fixedpoint, test_multiplication); - WASM_TEST_HANDLER(test_fixedpoint, test_division); - WASM_TEST_HANDLER(test_fixedpoint, test_division_by_0); - - // test checktime - WASM_TEST_HANDLER(test_checktime, checktime_pass); - WASM_TEST_HANDLER(test_checktime, checktime_failure); - WASM_TEST_HANDLER(test_checktime, checktime_sha1_failure); - WASM_TEST_HANDLER(test_checktime, checktime_assert_sha1_failure); - WASM_TEST_HANDLER(test_checktime, checktime_sha256_failure); - WASM_TEST_HANDLER(test_checktime, checktime_assert_sha256_failure); - WASM_TEST_HANDLER(test_checktime, checktime_sha512_failure); - WASM_TEST_HANDLER(test_checktime, checktime_assert_sha512_failure); - WASM_TEST_HANDLER(test_checktime, checktime_ripemd160_failure); - WASM_TEST_HANDLER(test_checktime, checktime_assert_ripemd160_failure); - - // test datastream - WASM_TEST_HANDLER(test_datastream, test_basic); - - // test permission - WASM_TEST_HANDLER_EX(test_permission, check_authorization); - WASM_TEST_HANDLER_EX(test_permission, test_permission_last_used); - WASM_TEST_HANDLER_EX(test_permission, test_account_creation_time); - - //unhandled test call - eosio_assert(false, "Unknown Test"); - - } -} diff --git a/contracts/test_api/test_datastream.cpp b/contracts/test_api/test_datastream.cpp deleted file mode 100644 index 3ad663ec48a..00000000000 --- a/contracts/test_api/test_datastream.cpp +++ /dev/null @@ -1,87 +0,0 @@ - -#include -#include -#include - -#include "test_api.hpp" - -template -struct testtype { - static void run(const T &v, const char *errmsg = "") { - char buf[128]; - eosio::datastream ds(buf, sizeof(buf)); - ds << v; - T v2; - ds.seekp(0); - ds >> v2; - eosio_assert(v == v2, errmsg); - } -}; - -template <> -struct testtype { - static void run(const double &v, const char *errmsg = "") { - char buf[128]; - eosio::datastream ds(buf, sizeof(buf)); - ds << v; - double v2; - ds.seekp(0); - ds >> v2; - eosio_assert(std::abs(v - v2) < 1e-20, errmsg); - } -}; - -template <> -struct testtype { - static void run(const float &v, const char *errmsg = "") { - char buf[128]; - eosio::datastream ds(buf, sizeof(buf)); - ds << v; - float v2; - ds.seekp(0); - ds >> v2; - eosio_assert(std::abs(v - v2) < float(1e-10), errmsg); - } -}; - -void test_datastream::test_basic() -{ - - testtype::run(true, "bool"); - testtype::run(false, "bool"); - testtype::run(-123, "int8"); - testtype::run(127, "uint8"); - testtype::run(-12345, "int16"); - testtype::run(12345, "uint16"); - testtype::run(-1234567890, "int32"); - testtype::run(3234567890u, "uint32"); - testtype::run((long long)0x8000000000000000ll, "int64"); - testtype::run(0x7fffffffffffffffull, "uint64"); - testtype::run(1.234f, "float"); - testtype::run(0.333333333333333333, "double"); - - // this should generate compile error - //testtype::run((char *)0x12345678, "pointer"); - - struct Pair { - int a; - double d; - bool operator==(const Pair &p) const { return a == p.a && std::abs(d - p.d) < 1e-20;} - }; - testtype::run({1, 1.23456}, "struct"); - - struct StaticArray { - int a[2]; - bool operator==(const StaticArray &o) const { return a[0] == o.a[0] && a[1] == o.a[1]; } - }; - testtype::run({{10,20}}, "StaticArray"); - - testtype::run("hello", "string"); - - testtype >::run({10,20,30}, "vector"); - testtype >::run({}, "empty vector"); - testtype >::run({{10,20,30}}, "std::array"); - testtype >::run({{1,"apple"}, {2,"cat"}, {3,"panda"}}, "map"); - testtype >::run({1, "abc", 3.3333}, "tuple"); -} - diff --git a/contracts/test_api/test_transaction.cpp b/contracts/test_api/test_transaction.cpp deleted file mode 100644 index cc1128ae5f6..00000000000 --- a/contracts/test_api/test_transaction.cpp +++ /dev/null @@ -1,339 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include -#include -#include - -#include "test_api.hpp" - -#pragma pack(push, 1) -template -struct test_action_action { - static account_name get_account() { - return account_name(ACCOUNT); - } - - static action_name get_name() { - return action_name(NAME); - } - - eosio::vector data; - - template - friend DataStream& operator << ( DataStream& ds, const test_action_action& a ) { - for ( auto c : a.data ) - ds << c; - return ds; - } - /* - template - friend DataStream& operator >> ( DataStream& ds, test_action_action& a ) { - return ds; - } - */ -}; - - -template -struct test_dummy_action { - static account_name get_account() { - return account_name(ACCOUNT); - } - - static action_name get_name() { - return action_name(NAME); - } - char a; - unsigned long long b; - int32_t c; - - template - friend DataStream& operator << ( DataStream& ds, const test_dummy_action& da ) { - ds << da.a; - ds << da.b; - ds << da.c; - return ds; - } - - template - friend DataStream& operator >> ( DataStream& ds, test_dummy_action& da ) { - ds >> da.a; - ds >> da.b; - ds >> da.c; - return ds; - } -}; -#pragma pack(pop) - -void copy_data(char* data, size_t data_len, eosio::vector& data_out) { - for (unsigned int i=0; i < data_len; i++) - data_out.push_back(data[i]); -} - -void test_transaction::send_action() { - using namespace eosio; - test_dummy_action test_action = {DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C}; - action act(eosio::vector{{N(testapi), N(active)}}, test_action); - act.send(); -} - -void test_transaction::send_action_empty() { - using namespace eosio; - test_action_action test_action; - - action act(eosio::vector{{N(testapi), N(active)}}, test_action); - - act.send(); -} - -/** - * cause failure due to a large action payload - */ -void test_transaction::send_action_large() { - using namespace eosio; - static char large_message[8 * 1024]; - test_action_action test_action; - copy_data(large_message, 8*1024, test_action.data); - action act(vector{{N(testapi), N(active)}}, test_action); - act.send(); - eosio_assert(false, "send_message_large() should've thrown an error"); -} - -/** - * cause failure due recursive loop - */ -void test_transaction::send_action_recurse() { - using namespace eosio; - char buffer[1024]; - read_action_data(buffer, 1024); - - test_action_action test_action; - copy_data(buffer, 1024, test_action.data); - action act(vector{{N(testapi), N(active)}}, test_action); - - act.send(); -} - -/** - * cause failure due to inline TX failure - */ -void test_transaction::send_action_inline_fail() { - using namespace eosio; - test_action_action test_action; - - action act(vector{{N(testapi), N(active)}}, test_action); - - act.send(); -} - -void test_transaction::test_tapos_block_prefix() { - using namespace eosio; - int tbp; - read_action_data( (char*)&tbp, sizeof(int) ); - eosio_assert( tbp == tapos_block_prefix(), "tapos_block_prefix does not match" ); -} - -void test_transaction::test_tapos_block_num() { - using namespace eosio; - int tbn; - read_action_data( (char*)&tbn, sizeof(int) ); - eosio_assert( tbn == tapos_block_num(), "tapos_block_num does not match" ); -} - - -void test_transaction::test_read_transaction() { - using namespace eosio; - checksum256 h; - auto size = transaction_size(); - char buf[size]; - uint32_t read = read_transaction( buf, size ); - eosio_assert( size == read, "read_transaction failed"); - sha256(buf, read, &h); - printhex( &h, sizeof(h) ); -} - -void test_transaction::test_transaction_size() { - using namespace eosio; - uint32_t trans_size = 0; - read_action_data( (char*)&trans_size, sizeof(uint32_t) ); - print( "size: ", transaction_size() ); - eosio_assert( trans_size == transaction_size(), "transaction size does not match" ); -} - -void test_transaction::send_transaction(uint64_t receiver, uint64_t, uint64_t) { - using namespace eosio; - dummy_action payload = {DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C}; - - test_action_action test_action; - copy_data((char*)&payload, sizeof(dummy_action), test_action.data); - - auto trx = transaction(); - trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); - trx.send(0, receiver); -} - -void test_transaction::send_action_sender(uint64_t receiver, uint64_t, uint64_t) { - using namespace eosio; - account_name cur_send; - read_action_data( &cur_send, sizeof(account_name) ); - test_action_action test_action; - copy_data((char*)&cur_send, sizeof(account_name), test_action.data); - - auto trx = transaction(); - trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); - trx.send(0, receiver); -} - -void test_transaction::send_transaction_empty(uint64_t receiver, uint64_t, uint64_t) { - using namespace eosio; - auto trx = transaction(); - trx.send(0, receiver); - - eosio_assert(false, "send_transaction_empty() should've thrown an error"); -} - -void test_transaction::send_transaction_trigger_error_handler(uint64_t receiver, uint64_t, uint64_t) { - using namespace eosio; - auto trx = transaction(); - test_action_action test_action; - trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); - trx.send(0, receiver); -} - -void test_transaction::assert_false_error_handler(const eosio::transaction& dtrx) { - eosio_assert(dtrx.actions.size() == 1, "transaction should only have one action"); - eosio_assert(dtrx.actions[0].account == N(testapi), "transaction has wrong code"); - eosio_assert(dtrx.actions[0].name == WASM_TEST_ACTION("test_action", "assert_false"), "transaction has wrong name"); - eosio_assert(dtrx.actions[0].authorization.size() == 1, "action should only have one authorization"); - eosio_assert(dtrx.actions[0].authorization[0].actor == N(testapi), "action's authorization has wrong actor"); - eosio_assert(dtrx.actions[0].authorization[0].permission == N(active), "action's authorization has wrong permission"); -} - -/** - * cause failure due to a large transaction size - */ -void test_transaction::send_transaction_large(uint64_t receiver, uint64_t, uint64_t) { - using namespace eosio; - auto trx = transaction(); - for (int i = 0; i < 32; i ++) { - char large_message[1024]; - test_action_action test_action; - copy_data(large_message, 1024, test_action.data); - trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); - } - - trx.send(0, receiver); - - eosio_assert(false, "send_transaction_large() should've thrown an error"); -} - -/** - * deferred transaction - */ -void test_transaction::deferred_print() { - eosio::print("deferred executed\n"); -} - -void test_transaction::send_deferred_transaction(uint64_t receiver, uint64_t, uint64_t) { - using namespace eosio; - auto trx = transaction(); - test_action_action test_action; - trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); - trx.delay_sec = 2; - trx.send( 0xffffffffffffffff, receiver ); -} - -void test_transaction::send_deferred_transaction_replace(uint64_t receiver, uint64_t, uint64_t) { - using namespace eosio; - auto trx = transaction(); - test_action_action test_action; - trx.actions.emplace_back(vector{{N(testapi), N(active)}}, test_action); - trx.delay_sec = 2; - trx.send( 0xffffffffffffffff, receiver, true ); -} - -void test_transaction::send_deferred_tx_with_dtt_action() { - using namespace eosio; - dtt_action dtt_act; - read_action_data(&dtt_act, action_data_size()); - - action deferred_act; - deferred_act.account = dtt_act.deferred_account; - deferred_act.name = dtt_act.deferred_action; - deferred_act.authorization = vector{{N(testapi), dtt_act.permission_name}}; - - auto trx = transaction(); - trx.actions.emplace_back(deferred_act); - trx.delay_sec = dtt_act.delay_sec; - cancel_deferred( 0xffffffffffffffff ); // TODO: Remove this line after fixing deferred trx replacement RAM bug - trx.send( 0xffffffffffffffff, dtt_act.payer, true ); -} - - -void test_transaction::cancel_deferred_transaction_success() { - using namespace eosio; - auto r = cancel_deferred( 0xffffffffffffffff ); //use the same id (0) as in send_deferred_transaction - eosio_assert( (bool)r, "transaction was not found" ); -} - -void test_transaction::cancel_deferred_transaction_not_found() { - using namespace eosio; - auto r = cancel_deferred( 0xffffffffffffffff ); //use the same id (0) as in send_deferred_transaction - eosio_assert( !r, "transaction was canceled, whild should not be found" ); -} - -void test_transaction::send_cf_action() { - using namespace eosio; - test_action_action cfa; - action act(cfa); - act.send_context_free(); -} - -void test_transaction::send_cf_action_fail() { - using namespace eosio; - test_action_action cfa; - action act(vector{{N(dummy), N(active)}}, cfa); - act.send_context_free(); - eosio_assert(false, "send_cfa_action_fail() should've thrown an error"); -} - -void test_transaction::stateful_api() { - char buf[4] = {1}; - db_store_i64(N(test_transaction), N(table), N(test_transaction), 0, buf, 4); -} - -void test_transaction::context_free_api() { - char buf[128] = {0}; - get_context_free_data(0, buf, sizeof(buf)); -} - -extern "C" { int is_feature_active(int64_t); } -void test_transaction::new_feature() { - eosio_assert(false == is_feature_active((int64_t)N(newfeature)), "we should not have new features unless hardfork"); -} - -void test_transaction::active_new_feature() { - activate_feature((int64_t)N(newfeature)); -} - -void test_transaction::repeat_deferred_transaction(uint64_t receiver, uint64_t code, uint64_t action) { - using namespace eosio; - - uint128_t sender_id = 0; - - uint32_t payload = unpack_action_data(); - print( "repeat_deferred_transaction called: payload = ", payload ); - - bool res = cancel_deferred( sender_id ); - - print( "\nrepeat_deferred_transaction cancelled trx with sender_id = ", sender_id, ", result is ", res ); - - if( payload == 0 ) return; - - --payload; - transaction trx; - trx.actions.emplace_back( permission_level{receiver, N(active)}, code, action, payload ); - trx.send( sender_id, receiver ); -} diff --git a/contracts/test_api/test_types.cpp b/contracts/test_api/test_types.cpp deleted file mode 100644 index bc9dca52e2a..00000000000 --- a/contracts/test_api/test_types.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include - -#include "test_api.hpp" - -void test_types::types_size() { - - eosio_assert( sizeof(int64_t) == 8, "int64_t size != 8"); - eosio_assert( sizeof(uint64_t) == 8, "uint64_t size != 8"); - eosio_assert( sizeof(uint32_t) == 4, "uint32_t size != 4"); - eosio_assert( sizeof(int32_t) == 4, "int32_t size != 4"); - eosio_assert( sizeof(uint128_t) == 16, "uint128_t size != 16"); - eosio_assert( sizeof(int128_t) == 16, "int128_t size != 16"); - eosio_assert( sizeof(uint8_t) == 1, "uint8_t size != 1"); - - eosio_assert( sizeof(account_name) == 8, "account_name size != 8"); - eosio_assert( sizeof(table_name) == 8, "table_name size != 8"); - eosio_assert( sizeof(time) == 4, "time size != 4"); - eosio_assert( sizeof(eosio::key256) == 32, "key256 size != 32" ); -} - -void test_types::char_to_symbol() { - - eosio_assert( eosio::char_to_symbol('1') == 1, "eosio::char_to_symbol('1') != 1"); - eosio_assert( eosio::char_to_symbol('2') == 2, "eosio::char_to_symbol('2') != 2"); - eosio_assert( eosio::char_to_symbol('3') == 3, "eosio::char_to_symbol('3') != 3"); - eosio_assert( eosio::char_to_symbol('4') == 4, "eosio::char_to_symbol('4') != 4"); - eosio_assert( eosio::char_to_symbol('5') == 5, "eosio::char_to_symbol('5') != 5"); - eosio_assert( eosio::char_to_symbol('a') == 6, "eosio::char_to_symbol('a') != 6"); - eosio_assert( eosio::char_to_symbol('b') == 7, "eosio::char_to_symbol('b') != 7"); - eosio_assert( eosio::char_to_symbol('c') == 8, "eosio::char_to_symbol('c') != 8"); - eosio_assert( eosio::char_to_symbol('d') == 9, "eosio::char_to_symbol('d') != 9"); - eosio_assert( eosio::char_to_symbol('e') == 10, "eosio::char_to_symbol('e') != 10"); - eosio_assert( eosio::char_to_symbol('f') == 11, "eosio::char_to_symbol('f') != 11"); - eosio_assert( eosio::char_to_symbol('g') == 12, "eosio::char_to_symbol('g') != 12"); - eosio_assert( eosio::char_to_symbol('h') == 13, "eosio::char_to_symbol('h') != 13"); - eosio_assert( eosio::char_to_symbol('i') == 14, "eosio::char_to_symbol('i') != 14"); - eosio_assert( eosio::char_to_symbol('j') == 15, "eosio::char_to_symbol('j') != 15"); - eosio_assert( eosio::char_to_symbol('k') == 16, "eosio::char_to_symbol('k') != 16"); - eosio_assert( eosio::char_to_symbol('l') == 17, "eosio::char_to_symbol('l') != 17"); - eosio_assert( eosio::char_to_symbol('m') == 18, "eosio::char_to_symbol('m') != 18"); - eosio_assert( eosio::char_to_symbol('n') == 19, "eosio::char_to_symbol('n') != 19"); - eosio_assert( eosio::char_to_symbol('o') == 20, "eosio::char_to_symbol('o') != 20"); - eosio_assert( eosio::char_to_symbol('p') == 21, "eosio::char_to_symbol('p') != 21"); - eosio_assert( eosio::char_to_symbol('q') == 22, "eosio::char_to_symbol('q') != 22"); - eosio_assert( eosio::char_to_symbol('r') == 23, "eosio::char_to_symbol('r') != 23"); - eosio_assert( eosio::char_to_symbol('s') == 24, "eosio::char_to_symbol('s') != 24"); - eosio_assert( eosio::char_to_symbol('t') == 25, "eosio::char_to_symbol('t') != 25"); - eosio_assert( eosio::char_to_symbol('u') == 26, "eosio::char_to_symbol('u') != 26"); - eosio_assert( eosio::char_to_symbol('v') == 27, "eosio::char_to_symbol('v') != 27"); - eosio_assert( eosio::char_to_symbol('w') == 28, "eosio::char_to_symbol('w') != 28"); - eosio_assert( eosio::char_to_symbol('x') == 29, "eosio::char_to_symbol('x') != 29"); - eosio_assert( eosio::char_to_symbol('y') == 30, "eosio::char_to_symbol('y') != 30"); - eosio_assert( eosio::char_to_symbol('z') == 31, "eosio::char_to_symbol('z') != 31"); - - for(unsigned char i = 0; i<255; i++) { - if((i >= 'a' && i <= 'z') || (i >= '1' || i <= '5')) continue; - eosio_assert( eosio::char_to_symbol((char)i) == 0, "eosio::char_to_symbol() != 0"); - } -} - -void test_types::string_to_name() { - - eosio_assert( eosio::string_to_name("a") == N(a) , "eosio::string_to_name(a)" ); - eosio_assert( eosio::string_to_name("ba") == N(ba) , "eosio::string_to_name(ba)" ); - eosio_assert( eosio::string_to_name("cba") == N(cba) , "eosio::string_to_name(cba)" ); - eosio_assert( eosio::string_to_name("dcba") == N(dcba) , "eosio::string_to_name(dcba)" ); - eosio_assert( eosio::string_to_name("edcba") == N(edcba) , "eosio::string_to_name(edcba)" ); - eosio_assert( eosio::string_to_name("fedcba") == N(fedcba) , "eosio::string_to_name(fedcba)" ); - eosio_assert( eosio::string_to_name("gfedcba") == N(gfedcba) , "eosio::string_to_name(gfedcba)" ); - eosio_assert( eosio::string_to_name("hgfedcba") == N(hgfedcba) , "eosio::string_to_name(hgfedcba)" ); - eosio_assert( eosio::string_to_name("ihgfedcba") == N(ihgfedcba) , "eosio::string_to_name(ihgfedcba)" ); - eosio_assert( eosio::string_to_name("jihgfedcba") == N(jihgfedcba) , "eosio::string_to_name(jihgfedcba)" ); - eosio_assert( eosio::string_to_name("kjihgfedcba") == N(kjihgfedcba) , "eosio::string_to_name(kjihgfedcba)" ); - eosio_assert( eosio::string_to_name("lkjihgfedcba") == N(lkjihgfedcba) , "eosio::string_to_name(lkjihgfedcba)" ); - eosio_assert( eosio::string_to_name("mlkjihgfedcba") == N(mlkjihgfedcba) , "eosio::string_to_name(mlkjihgfedcba)" ); - eosio_assert( eosio::string_to_name("mlkjihgfedcba1") == N(mlkjihgfedcba2) , "eosio::string_to_name(mlkjihgfedcba2)" ); - eosio_assert( eosio::string_to_name("mlkjihgfedcba55") == N(mlkjihgfedcba14) , "eosio::string_to_name(mlkjihgfedcba14)" ); - - eosio_assert( eosio::string_to_name("azAA34") == N(azBB34) , "eosio::string_to_name N(azBB34)" ); - eosio_assert( eosio::string_to_name("AZaz12Bc34") == N(AZaz12Bc34) , "eosio::string_to_name AZaz12Bc34" ); - eosio_assert( eosio::string_to_name("AAAAAAAAAAAAAAA") == eosio::string_to_name("BBBBBBBBBBBBBDDDDDFFFGG") , "eosio::string_to_name BBBBBBBBBBBBBDDDDDFFFGG" ); -} - -void test_types::name_class() { - - eosio_assert( eosio::name{eosio::string_to_name("azAA34")}.value == N(azAA34), "eosio::name != N(azAA34)" ); - eosio_assert( eosio::name{eosio::string_to_name("AABBCC")}.value == 0, "eosio::name != N(0)" ); - eosio_assert( eosio::name{eosio::string_to_name("AA11")}.value == N(AA11), "eosio::name != N(AA11)" ); - eosio_assert( eosio::name{eosio::string_to_name("11AA")}.value == N(11), "eosio::name != N(11)" ); - eosio_assert( eosio::name{eosio::string_to_name("22BBCCXXAA")}.value == N(22), "eosio::name != N(22)" ); - eosio_assert( eosio::name{eosio::string_to_name("AAAbbcccdd")} == eosio::name{eosio::string_to_name("AAAbbcccdd")}, "eosio::name == eosio::name" ); - - uint64_t tmp = eosio::name{eosio::string_to_name("11bbcccdd")}; - eosio_assert(N(11bbcccdd) == tmp, "N(11bbcccdd) == tmp"); -} diff --git a/contracts/test_api_db/CMakeLists.txt b/contracts/test_api_db/CMakeLists.txt deleted file mode 100644 index 0121439dbf1..00000000000 --- a/contracts/test_api_db/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_wast_executable(TARGET test_api_db - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/test_api_db/test_api_db.cpp b/contracts/test_api_db/test_api_db.cpp deleted file mode 100644 index d603477a631..00000000000 --- a/contracts/test_api_db/test_api_db.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include -#include "../test_api/test_api.hpp" - -#include "test_db.cpp" - -extern "C" { - void apply( uint64_t receiver, uint64_t code, uint64_t action ) { - require_auth(code); - WASM_TEST_HANDLER_EX(test_db, primary_i64_general); - WASM_TEST_HANDLER_EX(test_db, primary_i64_lowerbound); - WASM_TEST_HANDLER_EX(test_db, primary_i64_upperbound); - WASM_TEST_HANDLER_EX(test_db, idx64_general); - WASM_TEST_HANDLER_EX(test_db, idx64_lowerbound); - WASM_TEST_HANDLER_EX(test_db, idx64_upperbound); - WASM_TEST_HANDLER_EX(test_db, test_invalid_access); - WASM_TEST_HANDLER_EX(test_db, idx_double_nan_create_fail); - WASM_TEST_HANDLER_EX(test_db, idx_double_nan_modify_fail); - WASM_TEST_HANDLER_EX(test_db, idx_double_nan_lookup_fail); - WASM_TEST_HANDLER_EX(test_db, misaligned_secondary_key256_tests); - - //unhandled test call - eosio_assert(false, "Unknown Test"); - } - -} diff --git a/contracts/test_api_db/test_db.cpp b/contracts/test_api_db/test_db.cpp deleted file mode 100644 index a4096fc2ede..00000000000 --- a/contracts/test_api_db/test_db.cpp +++ /dev/null @@ -1,552 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "../test_api/test_api.hpp" - -int primary[11] = {0,1,2,3,4,5,6,7,8,9,10}; -int secondary[11] = {7,0,1,3,6,9,10,2,4,5,8}; -int tertiary[11] = {0,10,1,2,4,3,5,6,7,8,9}; - -int primary_lb[11] = {0,0,0,3,3,3,6,7,7,9,9}; -int secondary_lb[11] = {0,0,10,0,10,10,0,7,8,0,10}; -int tertiary_lb[11] = {0,1,2,3,2,5,6,7,8,9,0}; - -int primary_ub[11] = {3,3,3,6,6,6,7,9,9,-1,-1}; -int secondary_ub[11] = {10,10,8,10,8,8,10,0,-1,10,8}; -int tertiary_ub[11] = {1,2,3,5,3,6,7,8,9,-1,1}; - -#pragma pack(push, 1) -struct test_model { - account_name name; - unsigned char age; - uint64_t phone; -}; - -struct test_model_v2 : test_model { - test_model_v2() : new_field(0) {} - uint64_t new_field; -}; - -struct test_model_v3 : test_model_v2 { - uint64_t another_field; -}; - -struct TestModel128x2 { - uint128_t number; - uint128_t price; - uint64_t extra; - uint64_t table_name; -}; - -struct TestModel128x2_V2 : TestModel128x2 { - uint64_t new_field; -}; - -struct TestModel3xi64 { - uint64_t a; - uint64_t b; - uint64_t c; - uint64_t table; -}; - -struct TestModel3xi64_V2 : TestModel3xi64 { - uint64_t new_field; -}; - -#pragma pack(pop) - -#define STRLEN(s) my_strlen(s) - -extern "C" { - void my_memset(void *vptr, unsigned char val, unsigned int size) { - char *ptr = (char *)vptr; - while(size--) { *(ptr++)=(char)val; } - } - uint32_t my_strlen(const char *str) { - uint32_t len = 0; - while(str[len]) ++len; - return len; - } - bool my_memcmp(void *s1, void *s2, uint32_t n) { - unsigned char *c1 = (unsigned char*)s1; - unsigned char *c2 = (unsigned char*)s2; - for (uint32_t i = 0; i < n; i++) { - if (c1[i] != c2[i]) { - return false; - } - } - return true; - } -} - -void test_db::primary_i64_general(uint64_t receiver, uint64_t code, uint64_t action) -{ - (void)code; (void)action; - auto table1 = N(table1); - - int alice_itr = db_store_i64(receiver, table1, receiver, N(alice), "alice's info", strlen("alice's info")); - db_store_i64(receiver, table1, receiver, N(bob), "bob's info", strlen("bob's info")); - db_store_i64(receiver, table1, receiver, N(charlie), "charlie's info", strlen("charlies's info")); - db_store_i64(receiver, table1, receiver, N(allyson), "allyson's info", strlen("allyson's info")); - - - // find - { - uint64_t prim = 0; - int itr_next = db_next_i64(alice_itr, &prim); - int itr_next_expected = db_find_i64(receiver, receiver, table1, N(allyson)); - eosio_assert(itr_next == itr_next_expected && prim == N(allyson), "primary_i64_general - db_find_i64" ); - itr_next = db_next_i64(itr_next, &prim); - itr_next_expected = db_find_i64(receiver, receiver, table1, N(bob)); - eosio_assert(itr_next == itr_next_expected && prim == N(bob), "primary_i64_general - db_next_i64"); - } - - // next - { - int charlie_itr = db_find_i64(receiver, receiver, table1, N(charlie)); - // nothing after charlie - uint64_t prim = 0; - int end_itr = db_next_i64(charlie_itr, &prim); - eosio_assert(end_itr < 0, "primary_i64_general - db_next_i64"); - // prim didn't change - eosio_assert(prim == 0, "primary_i64_general - db_next_i64"); - } - - // previous - { - int charlie_itr = db_find_i64(receiver, receiver, table1, N(charlie)); - uint64_t prim = 0; - int itr_prev = db_previous_i64(charlie_itr, &prim); - int itr_prev_expected = db_find_i64(receiver, receiver, table1, N(bob)); - eosio_assert(itr_prev == itr_prev_expected && prim == N(bob), "primary_i64_general - db_previous_i64"); - - itr_prev = db_previous_i64(itr_prev, &prim); - itr_prev_expected = db_find_i64(receiver, receiver, table1, N(allyson)); - eosio_assert(itr_prev == itr_prev_expected && prim == N(allyson), "primary_i64_general - db_previous_i64"); - - itr_prev = db_previous_i64(itr_prev, &prim); - itr_prev_expected = db_find_i64(receiver, receiver, table1, N(alice)); - eosio_assert(itr_prev == itr_prev_expected && prim == N(alice), "primary_i64_general - db_previous_i64"); - - itr_prev = db_previous_i64(itr_prev, &prim); - eosio_assert(itr_prev < 0 && prim == N(alice), "primary_i64_general - db_previous_i64"); - } - - // remove - { - int itr = db_find_i64(receiver, receiver, table1, N(alice)); - eosio_assert(itr >= 0, "primary_i64_general - db_find_i64"); - db_remove_i64(itr); - itr = db_find_i64(receiver, receiver, table1, N(alice)); - eosio_assert(itr < 0, "primary_i64_general - db_find_i64"); - } - - // get - { - int itr = db_find_i64(receiver, receiver, table1, N(bob)); - eosio_assert(itr >= 0, ""); - uint32_t buffer_len = 5; - char value[50]; - auto len = db_get_i64(itr, value, buffer_len); - value[buffer_len] = '\0'; - std::string s(value); - eosio_assert(uint32_t(len) == buffer_len, "primary_i64_general - db_get_i64"); - eosio_assert(s == "bob's", "primary_i64_general - db_get_i64 - 5"); - - buffer_len = 20; - len = db_get_i64(itr, value, 0); - len = db_get_i64(itr, value, (uint32_t)len); - value[len] = '\0'; - std::string sfull(value); - eosio_assert(sfull == "bob's info", "primary_i64_general - db_get_i64 - full"); - } - - // update - { - int itr = db_find_i64(receiver, receiver, table1, N(bob)); - eosio_assert(itr >= 0, ""); - const char* new_value = "bob's new info"; - uint32_t new_value_len = strlen(new_value); - db_update_i64(itr, receiver, new_value, new_value_len); - char ret_value[50]; - db_get_i64(itr, ret_value, new_value_len); - ret_value[new_value_len] = '\0'; - std::string sret(ret_value); - eosio_assert(sret == "bob's new info", "primary_i64_general - db_update_i64"); - } -} - -void test_db::primary_i64_lowerbound(uint64_t receiver, uint64_t code, uint64_t action) -{ - (void)code;(void)action; - auto table = N(mytable); - db_store_i64(receiver, table, receiver, N(alice), "alice's info", strlen("alice's info")); - db_store_i64(receiver, table, receiver, N(bob), "bob's info", strlen("bob's info")); - db_store_i64(receiver, table, receiver, N(charlie), "charlie's info", strlen("charlies's info")); - db_store_i64(receiver, table, receiver, N(emily), "emily's info", strlen("emily's info")); - db_store_i64(receiver, table, receiver, N(allyson), "allyson's info", strlen("allyson's info")); - db_store_i64(receiver, table, receiver, N(joe), "nothing here", strlen("nothing here")); - - const std::string err = "primary_i64_lowerbound"; - - { - int lb = db_lowerbound_i64(receiver, receiver, table, N(alice)); - eosio_assert(lb == db_find_i64(receiver, receiver, table, N(alice)), err.c_str()); - } - { - int lb = db_lowerbound_i64(receiver, receiver, table, N(billy)); - eosio_assert(lb == db_find_i64(receiver, receiver, table, N(bob)), err.c_str()); - } - { - int lb = db_lowerbound_i64(receiver, receiver, table, N(frank)); - eosio_assert(lb == db_find_i64(receiver, receiver, table, N(joe)), err.c_str()); - } - { - int lb = db_lowerbound_i64(receiver, receiver, table, N(joe)); - eosio_assert(lb == db_find_i64(receiver, receiver, table, N(joe)), err.c_str()); - } - { - int lb = db_lowerbound_i64(receiver, receiver, table, N(kevin)); - eosio_assert(lb < 0, err.c_str()); - } -} - -void test_db::primary_i64_upperbound(uint64_t receiver, uint64_t code, uint64_t action) -{ - (void)code;(void)action; - auto table = N(mytable); - const std::string err = "primary_i64_upperbound"; - { - int ub = db_upperbound_i64(receiver, receiver, table, N(alice)); - eosio_assert(ub == db_find_i64(receiver, receiver, table, N(allyson)), err.c_str()); - } - { - int ub = db_upperbound_i64(receiver, receiver, table, N(billy)); - eosio_assert(ub == db_find_i64(receiver, receiver, table, N(bob)), err.c_str()); - } - { - int ub = db_upperbound_i64(receiver, receiver, table, N(frank)); - eosio_assert(ub == db_find_i64(receiver, receiver, table, N(joe)), err.c_str()); - } - { - int ub = db_upperbound_i64(receiver, receiver, table, N(joe)); - eosio_assert(ub < 0, err.c_str()); - } - { - int ub = db_upperbound_i64(receiver, receiver, table, N(kevin)); - eosio_assert(ub < 0, err.c_str()); - } -} - -void test_db::idx64_general(uint64_t receiver, uint64_t code, uint64_t action) -{ - (void)code;(void)action; - const auto table = N(myindextable); - - typedef uint64_t secondary_type; - - struct record { - uint64_t ssn; - secondary_type name; - }; - - record records[] = {{265, N(alice)}, - {781, N(bob)}, - {234, N(charlie)}, - {650, N(allyson)}, - {540, N(bob)}, - {976, N(emily)}, - {110, N(joe)} - }; - - for (uint32_t i = 0; i < sizeof(records)/sizeof(records[0]); ++i) { - db_idx64_store(receiver, table, receiver, records[i].ssn, &records[i].name); - } - - // find_primary - { - secondary_type sec = 0; - int itr = db_idx64_find_primary(receiver, receiver, table, &sec, 999); - eosio_assert(itr < 0 && sec == 0, "idx64_general - db_idx64_find_primary"); - itr = db_idx64_find_primary(receiver, receiver, table, &sec, 110); - eosio_assert(itr >= 0 && sec == N(joe), "idx64_general - db_idx64_find_primary"); - uint64_t prim_next = 0; - int itr_next = db_idx64_next(itr, &prim_next); - eosio_assert(itr_next < 0 && prim_next == 0, "idx64_general - db_idx64_find_primary"); - } - - // iterate forward starting with charlie - { - secondary_type sec = 0; - int itr = db_idx64_find_primary(receiver, receiver, table, &sec, 234); - eosio_assert(itr >= 0 && sec == N(charlie), "idx64_general - db_idx64_find_primary"); - - uint64_t prim_next = 0; - int itr_next = db_idx64_next(itr, &prim_next); - eosio_assert(itr_next >= 0 && prim_next == 976, "idx64_general - db_idx64_next"); - secondary_type sec_next = 0; - int itr_next_expected = db_idx64_find_primary(receiver, receiver, table, &sec_next, prim_next); - eosio_assert(itr_next == itr_next_expected && sec_next == N(emily), "idx64_general - db_idx64_next"); - - itr_next = db_idx64_next(itr_next, &prim_next); - eosio_assert(itr_next >= 0 && prim_next == 110, "idx64_general - db_idx64_next"); - itr_next_expected = db_idx64_find_primary(receiver, receiver, table, &sec_next, prim_next); - eosio_assert(itr_next == itr_next_expected && sec_next == N(joe), "idx64_general - db_idx64_next"); - - itr_next = db_idx64_next(itr_next, &prim_next); - eosio_assert(itr_next < 0 && prim_next == 110, "idx64_general - db_idx64_next"); - } - - // iterate backward staring with second bob - { - secondary_type sec = 0; - int itr = db_idx64_find_primary(receiver, receiver, table, &sec, 781); - eosio_assert(itr >= 0 && sec == N(bob), "idx64_general - db_idx64_find_primary"); - - uint64_t prim_prev = 0; - int itr_prev = db_idx64_previous(itr, &prim_prev); - eosio_assert(itr_prev >= 0 && prim_prev == 540, "idx64_general - db_idx64_previous"); - - secondary_type sec_prev = 0; - int itr_prev_expected = db_idx64_find_primary(receiver, receiver, table, &sec_prev, prim_prev); - eosio_assert(itr_prev == itr_prev_expected && sec_prev == N(bob), "idx64_general - db_idx64_previous"); - - itr_prev = db_idx64_previous(itr_prev, &prim_prev); - eosio_assert(itr_prev >= 0 && prim_prev == 650, "idx64_general - db_idx64_previous"); - itr_prev_expected = db_idx64_find_primary(receiver, receiver, table, &sec_prev, prim_prev); - eosio_assert(itr_prev == itr_prev_expected && sec_prev == N(allyson), "idx64_general - db_idx64_previous"); - - itr_prev = db_idx64_previous(itr_prev, &prim_prev); - eosio_assert(itr_prev >= 0 && prim_prev == 265, "idx64_general - db_idx64_previous"); - itr_prev_expected = db_idx64_find_primary(receiver, receiver, table, &sec_prev, prim_prev); - eosio_assert(itr_prev == itr_prev_expected && sec_prev == N(alice), "idx64_general - db_idx64_previous"); - - itr_prev = db_idx64_previous(itr_prev, &prim_prev); - eosio_assert(itr_prev < 0 && prim_prev == 265, "idx64_general - db_idx64_previous"); - } - - // find_secondary - { - uint64_t prim = 0; - auto sec = N(bob); - int itr = db_idx64_find_secondary(receiver, receiver, table, &sec, &prim); - eosio_assert(itr >= 0 && prim == 540, "idx64_general - db_idx64_find_secondary"); - - sec = N(emily); - itr = db_idx64_find_secondary(receiver, receiver, table, &sec, &prim); - eosio_assert(itr >= 0 && prim == 976, "idx64_general - db_idx64_find_secondary"); - - sec = N(frank); - itr = db_idx64_find_secondary(receiver, receiver, table, &sec, &prim); - eosio_assert(itr < 0 && prim == 976, "idx64_general - db_idx64_find_secondary"); - } - - // update and remove - { - auto one_more_bob = N(bob); - const uint64_t ssn = 421; - int itr = db_idx64_store(receiver, table, receiver, ssn, &one_more_bob); - auto new_name = N(billy); - db_idx64_update(itr, receiver, &new_name); - secondary_type sec = 0; - int sec_itr = db_idx64_find_primary(receiver, receiver, table, &sec, ssn); - eosio_assert(sec_itr == itr && sec == new_name, "idx64_general - db_idx64_update"); - db_idx64_remove(itr); - int itrf = db_idx64_find_primary(receiver, receiver, table, &sec, ssn); - eosio_assert(itrf < 0, "idx64_general - db_idx64_remove"); - } -} - -void test_db::idx64_lowerbound(uint64_t receiver, uint64_t code, uint64_t action) -{ - (void)code;(void)action; - const auto table = N(myindextable); - typedef uint64_t secondary_type; - const std::string err = "idx64_lowerbound"; - { - secondary_type lb_sec = N(alice); - uint64_t lb_prim = 0; - const uint64_t ssn = 265; - int lb = db_idx64_lowerbound(receiver, receiver, table, &lb_sec, &lb_prim); - eosio_assert(lb_prim == ssn && lb_sec == N(alice), err.c_str()); - eosio_assert(lb == db_idx64_find_primary(receiver, receiver, table, &lb_sec, ssn), err.c_str()); - } - { - secondary_type lb_sec = N(billy); - uint64_t lb_prim = 0; - const uint64_t ssn = 540; - int lb = db_idx64_lowerbound(receiver, receiver, table, &lb_sec, &lb_prim); - eosio_assert(lb_prim == ssn && lb_sec == N(bob), err.c_str()); - eosio_assert(lb == db_idx64_find_primary(receiver, receiver, table, &lb_sec, ssn), err.c_str()); - } - { - secondary_type lb_sec = N(joe); - uint64_t lb_prim = 0; - const uint64_t ssn = 110; - int lb = db_idx64_lowerbound(receiver, receiver, table, &lb_sec, &lb_prim); - eosio_assert(lb_prim == ssn && lb_sec == N(joe), err.c_str()); - eosio_assert(lb == db_idx64_find_primary(receiver, receiver, table, &lb_sec, ssn), err.c_str()); - } - { - secondary_type lb_sec = N(kevin); - uint64_t lb_prim = 0; - int lb = db_idx64_lowerbound(receiver, receiver, table, &lb_sec, &lb_prim); - eosio_assert(lb_prim == 0 && lb_sec == N(kevin), err.c_str()); - eosio_assert(lb < 0, ""); - } -} - -void test_db::idx64_upperbound(uint64_t receiver, uint64_t code, uint64_t action) -{ - (void)code;(void)action; - const auto table = N(myindextable); - typedef uint64_t secondary_type; - const std::string err = "idx64_upperbound"; - { - secondary_type ub_sec = N(alice); - uint64_t ub_prim = 0; - const uint64_t allyson_ssn = 650; - int ub = db_idx64_upperbound(receiver, receiver, table, &ub_sec, &ub_prim); - eosio_assert(ub_prim == allyson_ssn && ub_sec == N(allyson), ""); - eosio_assert(ub == db_idx64_find_primary(receiver, receiver, table, &ub_sec, allyson_ssn), err.c_str()); - } - { - secondary_type ub_sec = N(billy); - uint64_t ub_prim = 0; - const uint64_t bob_ssn = 540; - int ub = db_idx64_upperbound(receiver, receiver, table, &ub_sec, &ub_prim); - eosio_assert(ub_prim == bob_ssn && ub_sec == N(bob), ""); - eosio_assert(ub == db_idx64_find_primary(receiver, receiver, table, &ub_sec, bob_ssn), err.c_str()); - } - { - secondary_type ub_sec = N(joe); - uint64_t ub_prim = 0; - int ub = db_idx64_upperbound(receiver, receiver, table, &ub_sec, &ub_prim); - eosio_assert(ub_prim == 0 && ub_sec == N(joe), err.c_str()); - eosio_assert(ub < 0, err.c_str()); - } - { - secondary_type ub_sec = N(kevin); - uint64_t ub_prim = 0; - int ub = db_idx64_upperbound(receiver, receiver, table, &ub_sec, &ub_prim); - eosio_assert(ub_prim == 0 && ub_sec == N(kevin), err.c_str()); - eosio_assert(ub < 0, err.c_str()); - } -} - -void test_db::test_invalid_access(uint64_t receiver, uint64_t code, uint64_t action) -{ - (void)code;(void)action; - auto act = eosio::get_action(1, 0); - auto ia = eosio::unpack(act.data); - uint64_t scope = N(access); - uint64_t table = scope; - uint64_t pk = scope; - - int32_t itr = -1; - uint64_t value = 0; - switch( ia.index ) { - case 1: - itr = db_idx64_find_primary(ia.code, scope, table, &value, pk); - break; - case 0: - default: - itr = db_find_i64(ia.code, scope, table, pk); - break; - } - if( ia.store ) { - uint64_t value_to_store = ia.val; - if( itr < 0 ) { - switch( ia.index ) { - case 1: - db_idx64_store( scope, table, receiver, pk, &value_to_store ); - break; - case 0: - default: - db_store_i64( scope, table, receiver, pk, &value_to_store, sizeof(value_to_store) ); - break; - } - } else { - switch( ia.index ) { - case 1: - db_idx64_update( itr, receiver, &value_to_store); - break; - case 0: - default: - db_update_i64( itr, receiver, &value_to_store, sizeof(value_to_store) ); - break; - } - } - //eosio::print("test_invalid_access: stored ", value_to_store, "\n"); - } else { - eosio_assert( itr >= 0, "test_invalid_access: could not find row" ); - switch( ia.index ) { - case 1: - break; - case 0: - default: - eosio_assert( db_get_i64( itr, &value, sizeof(value) ) == sizeof(value), - "test_invalid_access: value in primary table was incorrect size" ); - break; - } - //eosio::print("test_invalid_access: expected ", ia.val, " and retrieved ", value, "\n"); - eosio_assert( value == ia.val, "test_invalid_access: value did not match" ); - } -} - -void test_db::idx_double_nan_create_fail(uint64_t receiver, uint64_t, uint64_t) { - double x = 0.0; - x = x / x; // create a NaN - db_idx_double_store( N(nan), N(nan), receiver, 0, &x); // should fail -} - -void test_db::idx_double_nan_modify_fail(uint64_t receiver, uint64_t, uint64_t) { - double x = 0.0; - db_idx_double_store( N(nan), N(nan), receiver, 0, &x); - auto itr = db_idx_double_find_primary(receiver, N(nan), N(nan), &x, 0); - x = 0.0; - x = x / x; // create a NaN - db_idx_double_update(itr, 0, &x); // should fail -} - -void test_db::idx_double_nan_lookup_fail(uint64_t receiver, uint64_t, uint64_t) { - auto act = eosio::get_action(1, 0); - auto lookup_type = eosio::unpack(act.data); - - uint64_t pk; - double x = 0.0; - db_idx_double_store( N(nan), N(nan), receiver, 0, &x); - x = x / x; // create a NaN - switch( lookup_type ) { - case 0: // find - db_idx_double_find_secondary(receiver, N(nan), N(nan), &x, &pk); - break; - case 1: // lower bound - db_idx_double_lowerbound(receiver, N(nan), N(nan), &x, &pk); - break; - case 2: // upper bound - db_idx_double_upperbound(receiver, N(nan), N(nan), &x, &pk); - break; - default: - eosio_assert( false, "idx_double_nan_lookup_fail: unexpected lookup_type" ); - } -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-align" - -void test_db::misaligned_secondary_key256_tests(uint64_t /* receiver */, uint64_t, uint64_t) { - auto key = eosio::key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 42ULL); - char* ptr = (char*)(&key); - ptr += 1; - // test that store doesn't crash on unaligned data - db_idx256_store( N(testapi), N(testtable), N(testapi), 1, (uint128_t*)(ptr), 2 ); - // test that find_primary doesn't crash on unaligned data - db_idx256_find_primary( N(testapi), N(testtable), N(testapi), (uint128_t*)(ptr), 2, 0); -} - -#pragma clang diagnostic pop diff --git a/contracts/test_api_mem/CMakeLists.txt b/contracts/test_api_mem/CMakeLists.txt deleted file mode 100644 index fc0d40f21e4..00000000000 --- a/contracts/test_api_mem/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -#set the MAX_MEMORY to 1MB for these tests; there were lots of memory unit tests that assume such - -add_wast_executable( TARGET test_api_mem - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} - MAX_MEMORY 1048576 -) diff --git a/contracts/test_api_mem/test_api_mem.cpp b/contracts/test_api_mem/test_api_mem.cpp deleted file mode 100644 index ce59249425d..00000000000 --- a/contracts/test_api_mem/test_api_mem.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include -#include "../test_api/test_api.hpp" - -#include "test_extended_memory.cpp" -#include "test_memory.cpp" - -extern "C" { - void apply( uint64_t /*receiver*/, uint64_t code, uint64_t action ) { - require_auth(code); - - //test_extended_memory - WASM_TEST_HANDLER(test_extended_memory, test_initial_buffer); - WASM_TEST_HANDLER(test_extended_memory, test_page_memory); - WASM_TEST_HANDLER(test_extended_memory, test_page_memory_exceeded); - WASM_TEST_HANDLER(test_extended_memory, test_page_memory_negative_bytes); - - //test_memory - WASM_TEST_HANDLER(test_memory, test_memory_allocs); - WASM_TEST_HANDLER(test_memory, test_memory_hunk); - WASM_TEST_HANDLER(test_memory, test_memory_hunks); - WASM_TEST_HANDLER(test_memory, test_memory_hunks_disjoint); - WASM_TEST_HANDLER(test_memory, test_memset_memcpy); - WASM_TEST_HANDLER(test_memory, test_memcpy_overlap_start); - WASM_TEST_HANDLER(test_memory, test_memcpy_overlap_end); - WASM_TEST_HANDLER(test_memory, test_memcmp); - WASM_TEST_HANDLER(test_memory, test_outofbound_0); - WASM_TEST_HANDLER(test_memory, test_outofbound_1); - WASM_TEST_HANDLER(test_memory, test_outofbound_2); - WASM_TEST_HANDLER(test_memory, test_outofbound_3); - WASM_TEST_HANDLER(test_memory, test_outofbound_4); - WASM_TEST_HANDLER(test_memory, test_outofbound_5); - WASM_TEST_HANDLER(test_memory, test_outofbound_6); - WASM_TEST_HANDLER(test_memory, test_outofbound_7); - WASM_TEST_HANDLER(test_memory, test_outofbound_8); - WASM_TEST_HANDLER(test_memory, test_outofbound_9); - WASM_TEST_HANDLER(test_memory, test_outofbound_10); - WASM_TEST_HANDLER(test_memory, test_outofbound_11); - WASM_TEST_HANDLER(test_memory, test_outofbound_12); - WASM_TEST_HANDLER(test_memory, test_outofbound_13); - - //unhandled test call - eosio_assert(false, "Unknown Test"); - } - -} diff --git a/contracts/test_api_mem/test_memory.cpp b/contracts/test_api_mem/test_memory.cpp deleted file mode 100644 index 3e1eb52243e..00000000000 --- a/contracts/test_api_mem/test_memory.cpp +++ /dev/null @@ -1,396 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ - -#include - - -void verify_mem(const void* const ptr, const uint32_t val, const uint32_t size) -{ - const char* char_ptr = (const char*)ptr; - for (uint32_t i = 0; i < size; ++i) - { - eosio_assert(static_cast(static_cast(char_ptr[i])) == val, "buf slot doesn't match"); - } -} - -/* -void print(const void* const ptr, const uint32_t size) -{ - const char* char_ptr = (const char*)ptr; - eosio::print("\n{ "); - for (uint32_t i = 0; i < size; ++i) - { - const char* delim = (i % 8 == 7) ? ", " : " "; - eosio::print("", static_cast(static_cast(char_ptr[i])), delim); - } - eosio::print("}\n"); -} -*/ - -/* -* malloc and realloc always allocate on 8 byte boundaries based off of total allocation, so -* if the requested size + the 2 byte header is not divisible by 8, then the allocated space -* will be larger than the requested size -*/ -void test_memory::test_memory_allocs() -{ - char* ptr1 = (char*)malloc(0); - eosio_assert(ptr1 == nullptr, "should not have allocated a 0 char buf"); - - // 20 chars - 20 + 4(header) which is divisible by 8 - ptr1 = (char*)malloc(20); - eosio_assert(ptr1 != nullptr, "should have allocated a 20 char buf"); - verify_mem(ptr1, 0, 20); - // existing memory layout -> |24| - - // 36 chars allocated - 30 + 4 plus an extra 6 to be divisible by 8 - char* ptr1_realloc = (char*)realloc(ptr1, 30); - eosio_assert(ptr1_realloc != nullptr, "should have returned a 30 char buf"); - eosio_assert(ptr1_realloc == ptr1, "should have enlarged the 20 char buf"); - // existing memory layout -> |40| - - // 20 chars allocated - char* ptr2 = (char*)malloc(20); - eosio_assert(ptr2 != nullptr, "should have allocated another 20 char buf"); - eosio_assert(ptr1 + 36 < ptr2, "20 char buf should have been created after ptr1"); // test specific to implementation (can remove for refactor) - verify_mem(ptr1, 0, 36); - eosio_assert(ptr1[36] != 0, "should not have empty bytes following since block allocated"); // test specific to implementation (can remove for refactor) - // existing memory layout -> |40|24| - - //shrink the buffer - ptr1[14] = 0x7e; - // 20 chars allocated (still) - ptr1_realloc = (char*)realloc(ptr1, 15); - eosio_assert(ptr1_realloc != nullptr, "should have returned a 15 char buf"); - eosio_assert(ptr1_realloc == ptr1, "should have shrunk the reallocated 30 char buf"); - verify_mem(ptr1, 0, 14); // test specific to implementation (can remove for refactor) - eosio_assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched"); - // existing memory layout -> |24(shrunk)|16(freed)|24| - - //same size the buffer (verify corner case) - // 20 chars allocated (still) - ptr1_realloc = (char*)realloc(ptr1, 15); - eosio_assert(ptr1_realloc != nullptr, "should have returned a reallocated 15 char buf"); - eosio_assert(ptr1_realloc == ptr1, "should have reallocated 15 char buf as the same buf"); - eosio_assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched for unchanged buf"); - - //same size as max allocated buffer -- test specific to implementation (can remove for refactor) - ptr1_realloc = (char*)realloc(ptr1, 30); - eosio_assert(ptr1_realloc != nullptr, "should have returned a 30 char buf"); - eosio_assert(ptr1_realloc == ptr1, "should have increased the buf back to orig max"); //test specific to implementation (can remove for refactor) - eosio_assert(ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched for expanded buf"); - - //increase buffer beyond (indicated) allocated space - // 36 chars allocated (still) - ptr1_realloc = (char*)realloc(ptr1, 36); - eosio_assert(ptr1_realloc != nullptr, "should have returned a 36 char buf"); - eosio_assert(ptr1_realloc == ptr1, "should have increased char buf to actual size"); // test specific to implementation (can remove for refactor) - - //increase buffer beyond allocated space - ptr1[35] = 0x7f; - // 44 chars allocated - 37 + 4 plus an extra 7 to be divisible by 8 - ptr1_realloc = (char*)realloc(ptr1, 37); - eosio_assert(ptr1_realloc != nullptr, "should have returned a 37 char buf"); - eosio_assert(ptr1_realloc != ptr1, "should have had to create new 37 char buf from 36 char buf"); - eosio_assert(ptr2 < ptr1_realloc, "should have been created after ptr2"); // test specific to implementation (can remove for refactor) - eosio_assert(ptr1_realloc[14] == 0x7e, "orig 36 char buf's content should be copied"); - eosio_assert(ptr1_realloc[35] == 0x7f, "orig 36 char buf's content should be copied"); - - //realloc with nullptr - char* nullptr_realloc = (char*)realloc(nullptr, 50); - eosio_assert(nullptr_realloc != nullptr, "should have returned a 50 char buf and ignored nullptr"); - eosio_assert(ptr1_realloc < nullptr_realloc, "should have created after ptr1_realloc"); // test specific to implementation (can remove for refactor) - - //realloc with invalid ptr - char* invalid_ptr_realloc = (char*)realloc(nullptr_realloc + 4, 10); - eosio_assert(invalid_ptr_realloc != nullptr, "should have returned a 10 char buf and ignored invalid ptr"); - eosio_assert(nullptr_realloc < invalid_ptr_realloc, "should have created invalid_ptr_realloc after nullptr_realloc"); // test specific to implementation (can remove for refactor) -} - -// this test verifies that malloc can allocate 15 64K pages and treat them as one big heap space (if sbrk is not called in the mean time) -void test_memory::test_memory_hunk() -{ - // try to allocate the largest buffer we can, which is 15 contiguous 64K pages (with the 4 char space for the ptr header) - char* ptr1 = (char*)malloc(15 * 64 * 1024 - 4); - eosio_assert(ptr1 != nullptr, "should have allocated a ~983K char buf"); -} - -void test_memory::test_memory_hunks() -{ - // leave 784 bytes of initial buffer to allocate later (rounds up to nearest 8 byte boundary, - // 16 bytes bigger than remainder left below in 15 64K page heap)) - char* ptr1 = (char*)malloc(7404); - eosio_assert(ptr1 != nullptr, "should have allocated a 7404 char buf"); - - char* last_ptr = nullptr; - // 96 * (10 * 1024 - 15) => 15 ~64K pages with 768 byte buffer left to allocate - for (int i = 0; i < 96; ++i) - { - char* ptr2 = (char*)malloc(10 * 1024 - 15); - eosio_assert(ptr2 != nullptr, "should have allocated a ~10K char buf"); - if (last_ptr != nullptr) - { - // - 15 rounds to -8 - eosio_assert(last_ptr + 10 * 1024 - 8 == ptr2, "should allocate the very next ptr"); // test specific to implementation (can remove for refactor) - } - - last_ptr = ptr2; - } - - // try to allocate a buffer slightly larger than the remaining buffer| 765 + 4 rounds to 776 - char* ptr3 = (char*)malloc(765); - eosio_assert(ptr3 != nullptr, "should have allocated a 772 char buf"); - eosio_assert(ptr1 + 7408 == ptr3, "should allocate the very next ptr after ptr1 in initial heap"); // test specific to implementation (can remove for refactor) - - // use all but 8 chars - char* ptr4 = (char*)malloc(764); - eosio_assert(ptr4 != nullptr, "should have allocated a 764 char buf"); - eosio_assert(last_ptr + 10 * 1024 - 8 == ptr4, "should allocate the very next ptr after last_ptr at end of contiguous heap"); // test specific to implementation (can remove for refactor) - - // use up remaining 8 chars - char* ptr5 = (char*)malloc(4); - eosio_assert(ptr5 != nullptr, "should have allocated a 4 char buf"); - eosio_assert(ptr3 + 776 == ptr5, "should allocate the very next ptr after ptr3 in initial heap"); // test specific to implementation (can remove for refactor) - - // nothing left to allocate - char* ptr6 = (char*)malloc(4); - eosio_assert(ptr6 == nullptr, "should not have allocated a char buf"); -} - -void test_memory::test_memory_hunks_disjoint() -{ - // leave 8 bytes of initial buffer to allocate later - char* ptr1 = (char*)malloc(8 * 1024 - 12); - eosio_assert(ptr1 != nullptr, "should have allocated a 8184 char buf"); - - // can only make 14 extra (64K) heaps for malloc, since calls to sbrk will eat up part - char* loop_ptr1[14]; - // 14 * (64 * 1024 - 28) => 14 ~64K pages with each page having 24 bytes left to allocate - for (int i = 0; i < 14; ++i) - { - // allocates a new heap for each request, since sbrk call doesn't allow contiguous heaps to grow - loop_ptr1[i] = (char*)malloc(64 * 1024 - 28); - eosio_assert(loop_ptr1[i] != nullptr, "should have allocated a 64K char buf"); - - eosio_assert(reinterpret_cast(sbrk(4)) != -1, "should be able to allocate 8 bytes"); - } - - // the 15th extra heap is reduced in size because of the 14 * 8 bytes allocated by sbrk calls - // will leave 8 bytes to allocate later (verifying that we circle back in the list - char* ptr2 = (char*)malloc(65412); - eosio_assert(ptr2 != nullptr, "should have allocated a 65412 char buf"); - - char* loop_ptr2[14]; - for (int i = 0; i < 14; ++i) - { - // 12 char buffer to leave 8 bytes for another pass - loop_ptr2[i] = (char*)malloc(12); - eosio_assert(loop_ptr2[i] != nullptr, "should have allocated a 12 char buf"); - eosio_assert(loop_ptr1[i] + 64 * 1024 - 24 == loop_ptr2[i], "loop_ptr2[i] should be very next pointer after loop_ptr1[i]"); - } - - // this shows that searching for free ptrs starts at the last loop to find free memory, not at the begining - char* ptr3 = (char*)malloc(4); - eosio_assert(ptr3 != nullptr, "should have allocated a 4 char buf"); - eosio_assert(loop_ptr2[13] + 16 == ptr3, "should allocate the very next ptr after loop_ptr2[13]"); // test specific to implementation (can remove for refactor) - - char* ptr4 = (char*)malloc(4); - eosio_assert(ptr4 != nullptr, "should have allocated a 4 char buf"); - eosio_assert(ptr2 + 65416 == ptr4, "should allocate the very next ptr after ptr2 in last heap"); // test specific to implementation (can remove for refactor) - - char* ptr5 = (char*)malloc(4); - eosio_assert(ptr5 != nullptr, "should have allocated a 4 char buf"); - eosio_assert(ptr1 + 8184 == ptr5, "should allocate the very next ptr after ptr1 in last heap"); // test specific to implementation (can remove for refactor) - - // will eat up remaining memory (14th heap already used up) - char* loop_ptr3[13]; - for (int i = 0; i < 13; ++i) - { - // 4 char buffer to use up buffer - loop_ptr3[i] = (char*)malloc(4); - eosio_assert(loop_ptr3[i] != nullptr, "should have allocated a 4 char buf"); - eosio_assert(loop_ptr2[i] + 16 == loop_ptr3[i], "loop_ptr3[i] should be very next pointer after loop_ptr2[i]"); - } - - char* ptr6 = (char*)malloc(4); - eosio_assert(ptr6 == nullptr, "should not have allocated a char buf"); - - free(loop_ptr1[3]); - free(loop_ptr2[3]); - free(loop_ptr3[3]); - - char* slot3_ptr[64]; - for (int i = 0; i < 64; ++i) - { - slot3_ptr[i] = (char*)malloc(1020); - eosio_assert(slot3_ptr[i] != nullptr, "should have allocated a 1020 char buf"); - if (i == 0) - eosio_assert(loop_ptr1[3] == slot3_ptr[0], "loop_ptr1[3] should be very next pointer after slot3_ptr[0]"); - else - eosio_assert(slot3_ptr[i - 1] + 1024 == slot3_ptr[i], "slot3_ptr[i] should be very next pointer after slot3_ptr[i-1]"); - } - - char* ptr7 = (char*)malloc(4); - eosio_assert(ptr7 == nullptr, "should not have allocated a char buf"); -} - -void test_memory::test_memset_memcpy() -{ - char buf1[40] = {}; - char buf2[40] = {}; - - verify_mem(buf1, 0, 40); - verify_mem(buf2, 0, 40); - - memset(buf1, 0x22, 20); - verify_mem(buf1, 0x22, 20); - verify_mem(&buf1[20], 0, 20); - - memset(&buf2[20], 0xff, 20); - verify_mem(buf2, 0, 20); - verify_mem(&buf2[20], 0xff, 20); - - memcpy(&buf1[10], &buf2[10], 20); - verify_mem(buf1, 0x22, 10); - verify_mem(&buf1[10], 0, 10); - verify_mem(&buf1[20], 0xff, 10); - verify_mem(&buf1[30], 0, 10); - - memset(&buf1[1], 1, 1); - verify_mem(buf1, 0x22, 1); - verify_mem(&buf1[1], 1, 1); - verify_mem(&buf1[2], 0x22, 8); - - // verify adjacent non-overlapping buffers - char buf3[50] = {}; - memset(&buf3[25], 0xee, 25); - verify_mem(buf3, 0, 25); - memcpy(buf3, &buf3[25], 25); - verify_mem(buf3, 0xee, 50); - - memset(buf3, 0, 25); - verify_mem(&buf3[25], 0xee, 25); - memcpy(&buf3[25], buf3, 25); - verify_mem(buf3, 0, 50); -} - -void test_memory::test_memcpy_overlap_start() -{ - char buf3[99] = {}; - memset(buf3, 0xee, 50); - memset(&buf3[50], 0xff, 49); - memcpy(&buf3[49], buf3, 50); -} - - -void test_memory::test_memcpy_overlap_end() -{ - char buf3[99] = {}; - memset(buf3, 0xee, 50); - memset(&buf3[50], 0xff, 49); - memcpy(buf3, &buf3[49], 50); -} - -void test_memory::test_memcmp() -{ - char buf1[] = "abcde"; - char buf2[] = "abcde"; - int32_t res1 = memcmp(buf1, buf2, 6); - eosio_assert(res1 == 0, "first data should be equal to second data"); - - char buf3[] = "abcde"; - char buf4[] = "fghij"; - int32_t res2 = memcmp(buf3, buf4, 6); - eosio_assert(res2 < 0, "first data should be smaller than second data"); - - char buf5[] = "fghij"; - char buf6[] = "abcde"; - int32_t res3 = memcmp(buf5, buf6, 6); - eosio_assert(res3 > 0, "first data should be larger than second data"); -} - -void test_memory::test_outofbound_0() -{ - memset((char *)0, 0xff, 1024 * 1024 * 1024); // big memory -} - -void test_memory::test_outofbound_1() -{ - memset((char *)16, 0xff, 0xffffffff); // memory wrap around -} - -void test_memory::test_outofbound_2() -{ - char buf[1024] = {0}; - char *ptr = (char *)malloc(1048576); - memcpy(buf, ptr, 1048576); // stack memory out of bound -} - -void test_memory::test_outofbound_3() -{ - char *ptr = (char *)malloc(128); - memset(ptr, 0xcc, 1048576); // heap memory out of bound -} - -template -void test_memory_store() { - T *ptr = (T *)(8192 * 1024 - 1); - ptr[0] = (T)1; -} - -template -void test_memory_load() { - T *ptr = (T *)(8192 * 1024 - 1); - volatile T tmp = ptr[0]; - (void)tmp; -} - -void test_memory::test_outofbound_4() -{ - test_memory_store(); -} -void test_memory::test_outofbound_5() -{ - test_memory_store(); -} -void test_memory::test_outofbound_6() -{ - test_memory_store(); -} -void test_memory::test_outofbound_7() -{ - test_memory_store(); -} -void test_memory::test_outofbound_8() -{ - test_memory_load(); -} -void test_memory::test_outofbound_9() -{ - test_memory_load(); -} -void test_memory::test_outofbound_10() -{ - test_memory_load(); -} -void test_memory::test_outofbound_11() -{ - test_memory_load(); -} - -void test_memory::test_outofbound_12() -{ - volatile unsigned int a = 0xffffffff; - double *ptr = (double *)a; // store with memory wrap - ptr[0] = 1; -} - -void test_memory::test_outofbound_13() -{ - volatile unsigned int a = 0xffffffff; - double *ptr = (double *)a; // load with memory wrap - volatile double tmp = ptr[0]; - (void)tmp; -} diff --git a/contracts/test_api_multi_index/CMakeLists.txt b/contracts/test_api_multi_index/CMakeLists.txt deleted file mode 100644 index b6906b0fb34..00000000000 --- a/contracts/test_api_multi_index/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_wast_executable(TARGET test_api_multi_index - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/test_api_multi_index/test_api_multi_index.cpp b/contracts/test_api_multi_index/test_api_multi_index.cpp deleted file mode 100644 index 828a1d75b88..00000000000 --- a/contracts/test_api_multi_index/test_api_multi_index.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include -#include "../test_api/test_api.hpp" - -#include "test_multi_index.cpp" - -extern "C" { - - void apply( uint64_t receiver, uint64_t code, uint64_t action ) { - require_auth(code); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_general); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_store_only); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_check_without_storing); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_require_find_fail); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_require_find_fail_with_msg); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_require_find_sk_fail); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_require_find_sk_fail_with_msg); - WASM_TEST_HANDLER_EX(test_multi_index, idx128_general); - WASM_TEST_HANDLER_EX(test_multi_index, idx128_store_only); - WASM_TEST_HANDLER_EX(test_multi_index, idx128_check_without_storing); - WASM_TEST_HANDLER_EX(test_multi_index, idx128_autoincrement_test); - WASM_TEST_HANDLER_EX(test_multi_index, idx128_autoincrement_test_part1); - WASM_TEST_HANDLER_EX(test_multi_index, idx128_autoincrement_test_part2); - WASM_TEST_HANDLER_EX(test_multi_index, idx256_general); - WASM_TEST_HANDLER_EX(test_multi_index, idx_double_general); - WASM_TEST_HANDLER_EX(test_multi_index, idx_long_double_general); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pk_iterator_exceed_end); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_sk_iterator_exceed_end); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pk_iterator_exceed_begin); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_sk_iterator_exceed_begin); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pass_pk_ref_to_other_table); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pass_sk_ref_to_other_table); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pass_pk_end_itr_to_iterator_to); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pass_pk_end_itr_to_modify); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pass_pk_end_itr_to_erase); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pass_sk_end_itr_to_iterator_to); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pass_sk_end_itr_to_modify); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pass_sk_end_itr_to_erase); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_modify_primary_key); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_run_out_of_avl_pk); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_sk_cache_pk_lookup); - WASM_TEST_HANDLER_EX(test_multi_index, idx64_pk_cache_sk_lookup); - - //unhandled test call - eosio_assert(false, "Unknown Test"); - } - -} diff --git a/contracts/test_api_multi_index/test_multi_index.cpp b/contracts/test_api_multi_index/test_multi_index.cpp deleted file mode 100644 index cbbe86eb44e..00000000000 --- a/contracts/test_api_multi_index/test_multi_index.cpp +++ /dev/null @@ -1,953 +0,0 @@ -#include -#include "../test_api/test_api.hpp" -#include -#include -#include -#include - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" - -namespace _test_multi_index { - - using eosio::key256; - - struct record_idx64 { - uint64_t id; - uint64_t sec; - - auto primary_key()const { return id; } - uint64_t get_secondary()const { return sec; } - - EOSLIB_SERIALIZE( record_idx64, (id)(sec) ) - }; - - struct record_idx128 { - uint64_t id; - uint128_t sec; - - auto primary_key()const { return id; } - uint128_t get_secondary()const { return sec; } - - EOSLIB_SERIALIZE( record_idx128, (id)(sec) ) - }; - - struct record_idx256 { - uint64_t id; - key256 sec; - - auto primary_key()const { return id; } - const key256& get_secondary()const { return sec; } - - EOSLIB_SERIALIZE( record_idx256, (id)(sec) ) - }; - - struct record_idx_double { - uint64_t id; - double sec; - - auto primary_key()const { return id; } - double get_secondary()const { return sec; } - - EOSLIB_SERIALIZE( record_idx_double, (id)(sec) ) - }; - - struct record_idx_long_double { - uint64_t id; - long double sec; - - auto primary_key()const { return id; } - long double get_secondary()const { return sec; } - - EOSLIB_SERIALIZE( record_idx_long_double, (id)(sec) ) - }; - - template - void idx64_store_only(uint64_t receiver) - { - using namespace eosio; - - typedef record_idx64 record; - - record records[] = {{265, N(alice)}, - {781, N(bob)}, - {234, N(charlie)}, - {650, N(allyson)}, - {540, N(bob)}, - {976, N(emily)}, - {110, N(joe)} - }; - size_t num_records = sizeof(records)/sizeof(records[0]); - - // Construct and fill table using multi_index - multi_index > - > table( receiver, receiver ); - - auto payer = receiver; - - for (size_t i = 0; i < num_records; ++i) { - table.emplace( payer, [&]( auto& r ) { - r.id = records[i].id; - r.sec = records[i].sec; - }); - } - } - - template - void idx64_check_without_storing(uint64_t receiver) - { - using namespace eosio; - - typedef record_idx64 record; - - // Load table using multi_index - multi_index > - > table( receiver, receiver ); - - auto payer = receiver; - - auto secondary_index = table.template get_index(); - - // find by primary key - { - auto itr = table.find(999); - eosio_assert(itr == table.end(), "idx64_general - table.find() of non-existing primary key"); - - itr = table.find(976); - eosio_assert(itr != table.end() && itr->sec == N(emily), "idx64_general - table.find() of existing primary key"); - - ++itr; - eosio_assert(itr == table.end(), "idx64_general - increment primary iterator to end"); - - itr = table.require_find(976); - eosio_assert(itr != table.end() && itr->sec == N(emily), "idx64_general - table.require_find() of existing primary key"); - - ++itr; - eosio_assert(itr == table.end(), "idx64_general - increment primary iterator to end"); - } - - // iterate forward starting with charlie - { - auto itr = secondary_index.lower_bound(N(charlie)); - eosio_assert(itr != secondary_index.end() && itr->sec == N(charlie), "idx64_general - secondary_index.lower_bound()"); - - ++itr; - eosio_assert(itr != secondary_index.end() && itr->id == 976 && itr->sec == N(emily), "idx64_general - increment secondary iterator"); - - ++itr; - eosio_assert(itr != secondary_index.end() && itr->id == 110 && itr->sec == N(joe), "idx64_general - increment secondary iterator again"); - - ++itr; - eosio_assert(itr == secondary_index.end(), "idx64_general - increment secondary iterator to end"); - } - - // iterate backward starting with second bob - { - auto pk_itr = table.find(781); - eosio_assert(pk_itr != table.end() && pk_itr->sec == N(bob), "idx64_general - table.find() of existing primary key"); - - auto itr = secondary_index.iterator_to(*pk_itr); - eosio_assert(itr->id == 781 && itr->sec == N(bob), "idx64_general - iterator to existing object in secondary index"); - - --itr; - eosio_assert(itr != secondary_index.end() && itr->id == 540 && itr->sec == N(bob), "idx64_general - decrement secondary iterator"); - - --itr; - eosio_assert(itr != secondary_index.end() && itr->id == 650 && itr->sec == N(allyson), "idx64_general - decrement secondary iterator again"); - - --itr; - eosio_assert(itr == secondary_index.begin() && itr->id == 265 && itr->sec == N(alice), "idx64_general - decrement secondary iterator to beginning"); - } - - // iterate backward starting with emily using const_reverse_iterator - { - std::array pks{{976, 234, 781, 540, 650, 265}}; - - auto pk_itr = pks.begin(); - - auto itr = --std::make_reverse_iterator( secondary_index.find( N(emily) ) ); - for( ; itr != secondary_index.rend(); ++itr ) { - eosio_assert(pk_itr != pks.end(), "idx64_general - unexpected continuation of secondary index in reverse iteration"); - eosio_assert(*pk_itr == itr->id, "idx64_general - primary key mismatch in reverse iteration"); - ++pk_itr; - } - eosio_assert( pk_itr == pks.end(), "idx64_general - did not iterate backwards through secondary index properly" ); - } - - // require_find secondary key - { - auto itr = secondary_index.require_find(N(bob)); - eosio_assert(itr != secondary_index.end(), "idx64_general - require_find must never return end iterator"); - eosio_assert(itr->id == 540, "idx64_general - require_find test"); - - ++itr; - eosio_assert(itr->id == 781, "idx64_general - require_find secondary key test"); - } - - // modify and erase - { - const uint64_t ssn = 421; - auto new_person = table.emplace( payer, [&]( auto& r ) { - r.id = ssn; - r.sec = N(bob); - }); - - table.modify(new_person, payer, [&]( auto& r ) { - r.sec = N(billy); - }); - - auto itr1 = table.find(ssn); - eosio_assert(itr1 != table.end() && itr1->sec == N(billy), "idx64_general - table.modify()"); - - table.erase(itr1); - auto itr2 = table.find(ssn); - eosio_assert( itr2 == table.end(), "idx64_general - table.erase()"); - } - } - - template - void idx64_require_find_fail(uint64_t receiver) - { - using namespace eosio; - typedef record_idx64 record; - - // Load table using multi_index - multi_index table( receiver, receiver ); - - // make sure we're looking at the right table - auto itr = table.require_find(781, "table not loaded"); - eosio_assert(itr != table.end(), "table not loaded"); - - // require_find by primary key - // should fail - itr = table.require_find(999); - } - - template - void idx64_require_find_fail_with_msg(uint64_t receiver) - { - using namespace eosio; - typedef record_idx64 record; - - // Load table using multi_index - multi_index table( receiver, receiver ); - - // make sure we're looking at the right table - auto itr = table.require_find(234, "table not loaded"); - eosio_assert(itr != table.end(), "table not loaded"); - - // require_find by primary key - // should fail - itr = table.require_find(335, "unable to find primary key in require_find"); - } - - template - void idx64_require_find_sk_fail(uint64_t receiver) - { - using namespace eosio; - typedef record_idx64 record; - - // Load table using multi_index - multi_index>> table( receiver, receiver ); - auto sec_index = table.template get_index(); - - // make sure we're looking at the right table - auto itr = sec_index.require_find(N(charlie), "table not loaded"); - eosio_assert(itr != sec_index.end(), "table not loaded"); - - // require_find by secondary key - // should fail - itr = sec_index.require_find(N(bill)); - } - - template - void idx64_require_find_sk_fail_with_msg(uint64_t receiver) - { - using namespace eosio; - typedef record_idx64 record; - - // Load table using multi_index - multi_index>> table( receiver, receiver ); - auto sec_index = table.template get_index(); - - // make sure we're looking at the right table - auto itr = sec_index.require_find(N(emily), "table not loaded"); - eosio_assert(itr != sec_index.end(), "table not loaded"); - - // require_find by secondary key - // should fail - itr = sec_index.require_find(N(frank), "unable to find sec key"); - } - - template - void idx128_store_only(uint64_t receiver) - { - using namespace eosio; - - typedef record_idx128 record; - - - // Construct and fill table using multi_index - multi_index > - > table( receiver, receiver ); - - auto payer = receiver; - - for (uint64_t i = 0; i < 5; ++i) { - table.emplace( payer, [&]( auto& r ) { - r.id = i; - r.sec = static_cast(1ULL << 63) * i; - }); - } - } - - template - void idx128_check_without_storing(uint64_t receiver) - { - using namespace eosio; - - typedef record_idx128 record; - - // Load table using multi_index - multi_index > - > table( receiver, receiver ); - - auto payer = receiver; - - auto secondary_index = table.template get_index(); - - table.modify(table.get(3), payer, [&]( auto& r ) { - r.sec *= 2; - }); - - { - uint128_t multiplier = 1ULL << 63; - - auto itr = secondary_index.begin(); - eosio_assert( itr->primary_key() == 0 && itr->get_secondary() == multiplier*0, "idx128_general - secondary key sort" ); - ++itr; - eosio_assert( itr->primary_key() == 1 && itr->get_secondary() == multiplier*1, "idx128_general - secondary key sort" ); - ++itr; - eosio_assert( itr->primary_key() == 2 && itr->get_secondary() == multiplier*2, "idx128_general - secondary key sort" ); - ++itr; - eosio_assert( itr->primary_key() == 4 && itr->get_secondary() == multiplier*4, "idx128_general - secondary key sort" ); - ++itr; - eosio_assert( itr->primary_key() == 3 && itr->get_secondary() == multiplier*6, "idx128_general - secondary key sort" ); - ++itr; - eosio_assert( itr == secondary_index.end(), "idx128_general - secondary key sort" ); - } - - } - - template - auto idx64_table(uint64_t receiver) - { - using namespace eosio; - typedef record_idx64 record; - // Load table using multi_index - multi_index > - > table( receiver, receiver ); - return table; - } - -} /// _test_multi_index - -void test_multi_index::idx64_store_only(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx64_store_only(receiver); -} - -void test_multi_index::idx64_check_without_storing(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx64_check_without_storing(receiver); -} - -void test_multi_index::idx64_general(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx64_store_only(receiver); - _test_multi_index::idx64_check_without_storing(receiver); -} - -void test_multi_index::idx128_store_only(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx128_store_only(receiver); -} - -void test_multi_index::idx128_check_without_storing(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx128_check_without_storing(receiver); -} - -void test_multi_index::idx128_general(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx128_store_only(receiver); - _test_multi_index::idx128_check_without_storing(receiver); -} - -void test_multi_index::idx64_require_find_fail(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx64_store_only(receiver); - _test_multi_index::idx64_require_find_fail(receiver); -} - -void test_multi_index::idx64_require_find_fail_with_msg(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx64_store_only(receiver); - _test_multi_index::idx64_require_find_fail_with_msg(receiver); -} - -void test_multi_index::idx64_require_find_sk_fail(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx64_store_only(receiver); - _test_multi_index::idx64_require_find_sk_fail(receiver); -} - -void test_multi_index::idx64_require_find_sk_fail_with_msg(uint64_t receiver, uint64_t code, uint64_t action) -{ - _test_multi_index::idx64_store_only(receiver); - _test_multi_index::idx64_require_find_sk_fail_with_msg(receiver); -} - -void test_multi_index::idx128_autoincrement_test(uint64_t receiver, uint64_t code, uint64_t action) -{ - using namespace eosio; - using namespace _test_multi_index; - - typedef record_idx128 record; - - const uint64_t table_name = N(autoinctbl1); - auto payer = receiver; - - multi_index > - > table( receiver, receiver ); - - for( int i = 0; i < 5; ++i ) { - table.emplace( payer, [&]( auto& r ) { - r.id = table.available_primary_key(); - r.sec = 1000 - static_cast(r.id); - }); - } - - uint64_t expected_key = 4; - for( const auto& r : table.get_index() ) - { - eosio_assert( r.primary_key() == expected_key, "idx128_autoincrement_test - unexpected primary key" ); - --expected_key; - } - eosio_assert( expected_key == static_cast(-1), "idx128_autoincrement_test - did not iterate through secondary index properly" ); - - auto itr = table.find(3); - eosio_assert( itr != table.end(), "idx128_autoincrement_test - could not find object with primary key of 3" ); - - // The modification below would trigger an error: - /* - table.modify(itr, payer, [&]( auto& r ) { - r.id = 100; - }); - */ - - table.emplace( payer, [&]( auto& r) { - r.id = 100; - r.sec = itr->sec; - }); - table.erase(itr); - - eosio_assert( table.available_primary_key() == 101, "idx128_autoincrement_test - next_primary_key was not correct after record modify" ); -} - -void test_multi_index::idx128_autoincrement_test_part1(uint64_t receiver, uint64_t code, uint64_t action) -{ - using namespace eosio; - using namespace _test_multi_index; - - typedef record_idx128 record; - - const uint64_t table_name = N(autoinctbl2); - auto payer = receiver; - - multi_index > - > table( receiver, receiver ); - - for( int i = 0; i < 3; ++i ) { - table.emplace( payer, [&]( auto& r ) { - r.id = table.available_primary_key(); - r.sec = 1000 - static_cast(r.id); - }); - } - - table.erase(table.get(0)); - - uint64_t expected_key = 2; - for( const auto& r : table.get_index() ) - { - eosio_assert( r.primary_key() == expected_key, "idx128_autoincrement_test_part1 - unexpected primary key" ); - --expected_key; - } - eosio_assert( expected_key == 0, "idx128_autoincrement_test_part1 - did not iterate through secondary index properly" ); - -} - -void test_multi_index::idx128_autoincrement_test_part2(uint64_t receiver, uint64_t code, uint64_t action) -{ - using namespace eosio; - using namespace _test_multi_index; - - typedef record_idx128 record; - - const uint64_t table_name = N(autoinctbl2); - auto payer = receiver; - - { - multi_index > - > table( receiver, receiver ); - - eosio_assert( table.available_primary_key() == 3, "idx128_autoincrement_test_part2 - did not recover expected next primary key"); - } - - multi_index > - > table( receiver, receiver ); - - table.emplace( payer, [&]( auto& r) { - r.id = 0; - r.sec = 1000; - }); - // Done this way to make sure that table._next_primary_key is not incorrectly set to 1. - - for( int i = 3; i < 5; ++i ) { - table.emplace( payer, [&]( auto& r ) { - auto itr = table.available_primary_key(); - r.id = itr; - r.sec = 1000 - static_cast(r.id); - }); - } - - uint64_t expected_key = 4; - for( const auto& r : table.get_index() ) - { - eosio_assert( r.primary_key() == expected_key, "idx128_autoincrement_test_part2 - unexpected primary key" ); - --expected_key; - } - eosio_assert( expected_key == static_cast(-1), "idx128_autoincrement_test_part2 - did not iterate through secondary index properly" ); - - auto itr = table.find(3); - eosio_assert( itr != table.end(), "idx128_autoincrement_test_part2 - could not find object with primary key of 3" ); - - table.emplace( payer, [&]( auto& r) { - r.id = 100; - r.sec = itr->sec; - }); - table.erase(itr); - - eosio_assert( table.available_primary_key() == 101, "idx128_autoincrement_test_part2 - next_primary_key was not correct after record update" ); -} - -void test_multi_index::idx256_general(uint64_t receiver, uint64_t code, uint64_t action) -{ - using namespace eosio; - using namespace _test_multi_index; - - typedef record_idx256 record; - - const uint64_t table_name = N(indextable5); - auto payer = receiver; - - print("Testing key256 secondary index.\n"); - multi_index > - > table( receiver, receiver ); - - auto fourtytwo = key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 42ULL); - //auto onetwothreefour = key256::make_from_word_sequence(1ULL, 2ULL, 3ULL, 4ULL); - auto onetwothreefour = key256{std::array{{0,1, 0,2, 0,3, 0,4}}}; - - table.emplace( payer, [&]( auto& o ) { - o.id = 1; - o.sec = fourtytwo; - }); - - table.emplace( payer, [&]( auto& o ) { - o.id = 2; - o.sec = onetwothreefour; - }); - - table.emplace( payer, [&]( auto& o ) { - o.id = 3; - o.sec = fourtytwo; - }); - - auto e = table.find( 2 ); - - print("Items sorted by primary key:\n"); - for( const auto& item : table ) { - print(" ID=", item.primary_key(), ", secondary=", item.sec, "\n"); - } - - { - auto itr = table.begin(); - eosio_assert( itr->primary_key() == 1 && itr->get_secondary() == fourtytwo, "idx256_general - primary key sort" ); - ++itr; - eosio_assert( itr->primary_key() == 2 && itr->get_secondary() == onetwothreefour, "idx256_general - primary key sort" ); - ++itr; - eosio_assert( itr->primary_key() == 3 && itr->get_secondary() == fourtytwo, "idx256_general - primary key sort" ); - ++itr; - eosio_assert( itr == table.end(), "idx256_general - primary key sort" ); - } - - auto secidx = table.get_index(); - - auto lower1 = secidx.lower_bound(key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 40ULL)); - print("First entry with a secondary key of at least 40 has ID=", lower1->id, ".\n"); - eosio_assert( lower1->id == 1, "idx256_general - lower_bound" ); - - auto lower2 = secidx.lower_bound(key256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 50ULL)); - print("First entry with a secondary key of at least 50 has ID=", lower2->id, ".\n"); - eosio_assert( lower2->id == 2, "idx256_general - lower_bound" ); - - if( table.iterator_to(*lower2) == e ) { - print("Previously found entry is the same as the one found earlier with a primary key value of 2.\n"); - } - - print("Items sorted by secondary key (key256):\n"); - for( const auto& item : secidx ) { - print(" ID=", item.primary_key(), ", secondary=", item.sec, "\n"); - } - - { - auto itr = secidx.begin(); - eosio_assert( itr->primary_key() == 1, "idx256_general - secondary key sort" ); - ++itr; - eosio_assert( itr->primary_key() == 3, "idx256_general - secondary key sort" ); - ++itr; - eosio_assert( itr->primary_key() == 2, "idx256_general - secondary key sort" ); - ++itr; - eosio_assert( itr == secidx.end(), "idx256_general - secondary key sort" ); - } - - auto upper = secidx.upper_bound(key256{std::array{{0, 0, 0, 42}}}); - - print("First entry with a secondary key greater than 42 has ID=", upper->id, ".\n"); - eosio_assert( upper->id == 2, "idx256_general - upper_bound" ); - eosio_assert( upper->id == secidx.get(onetwothreefour).id, "idx256_general - secondary index get" ); - - print("Removed entry with ID=", lower1->id, ".\n"); - secidx.erase( lower1 ); - - print("Items reverse sorted by primary key:\n"); - for( const auto& item : boost::make_iterator_range(table.rbegin(), table.rend()) ) { - print(" ID=", item.primary_key(), ", secondary=", item.sec, "\n"); - } - - { - auto itr = table.rbegin(); - eosio_assert( itr->primary_key() == 3 && itr->get_secondary() == fourtytwo, "idx256_general - primary key sort after remove" ); - ++itr; - eosio_assert( itr->primary_key() == 2 && itr->get_secondary() == onetwothreefour, "idx256_general - primary key sort after remove" ); - ++itr; - eosio_assert( itr == table.rend(), "idx256_general - primary key sort after remove" ); - } -} - -void test_multi_index::idx_double_general(uint64_t receiver, uint64_t code, uint64_t action) -{ - using namespace eosio; - using namespace _test_multi_index; - - typedef record_idx_double record; - - const uint64_t table_name = N(floattable1); - auto payer = receiver; - - print("Testing double secondary index.\n"); - multi_index > - > table( receiver, receiver ); - - auto secidx = table.get_index(); - - double tolerance = std::numeric_limits::epsilon(); - print("tolerance = ", tolerance, "\n"); - - for( uint64_t i = 1; i <= 10; ++i ) { - table.emplace( payer, [&]( auto& o ) { - o.id = i; - o.sec = 1.0 / (i * 1000000.0); - }); - } - - double expected_product = 1.0 / 1000000.0; - print( "expected_product = ", expected_product, "\n" ); - - uint64_t expected_key = 10; - for( const auto& obj : secidx ) { - eosio_assert( obj.primary_key() == expected_key, "idx_double_general - unexpected primary key" ); - - double prod = obj.sec * obj.id; - - print(" id = ", obj.id, ", sec = ", obj.sec, ", sec * id = ", prod, "\n"); - - eosio_assert( std::abs(prod - expected_product) <= tolerance, - "idx_double_general - product of secondary and id not equal to expected_product within tolerance" ); - - --expected_key; - } - eosio_assert( expected_key == 0, "idx_double_general - did not iterate through secondary index properly" ); - - { - auto itr = secidx.lower_bound( expected_product / 5.5 ); - eosio_assert( std::abs(1.0 / itr->sec - 5000000.0) <= tolerance, "idx_double_general - lower_bound" ); - - itr = secidx.upper_bound( expected_product / 5.0 ); - eosio_assert( std::abs(1.0 / itr->sec - 4000000.0) <= tolerance, "idx_double_general - upper_bound" ); - - } -} - -void test_multi_index::idx_long_double_general(uint64_t receiver, uint64_t code, uint64_t action) -{ - using namespace eosio; - using namespace _test_multi_index; - - typedef record_idx_long_double record; - - const uint64_t table_name = N(floattable2); - auto payer = receiver; - - print("Testing long double secondary index.\n"); - multi_index > - > table( receiver, receiver ); - - auto secidx = table.get_index(); - - long double tolerance = std::min( static_cast(std::numeric_limits::epsilon()), - std::numeric_limits::epsilon() * 1e7l ); - print("tolerance = ", tolerance, "\n"); - - long double f = 1.0l; - for( uint64_t i = 1; i <= 10; ++i, f += 1.0l ) { - table.emplace( payer, [&]( auto& o ) { - o.id = i; - o.sec = 1.0l / (i * 1000000.0l); - }); - } - - long double expected_product = 1.0l / 1000000.0l; - print( "expected_product = ", expected_product, "\n" ); - - uint64_t expected_key = 10; - for( const auto& obj : secidx ) { - eosio_assert( obj.primary_key() == expected_key, "idx_long_double_general - unexpected primary key" ); - - long double prod = obj.sec * obj.id; - - print(" id = ", obj.id, ", sec = ", obj.sec, ", sec * id = ", prod, "\n"); - - eosio_assert( std::abs(prod - expected_product) <= tolerance, - "idx_long_double_general - product of secondary and id not equal to expected_product within tolerance" ); - - --expected_key; - } - eosio_assert( expected_key == 0, "idx_long_double_general - did not iterate through secondary index properly" ); - - { - auto itr = secidx.lower_bound( expected_product / 5.5l ); - eosio_assert( std::abs(1.0l / itr->sec - 5000000.0l) <= tolerance, "idx_long_double_general - lower_bound" ); - - itr = secidx.upper_bound( expected_product / 5.0l ); - eosio_assert( std::abs(1.0l / itr->sec - 4000000.0l) <= tolerance, "idx_long_double_general - upper_bound" ); - - } -} - -void test_multi_index::idx64_pk_iterator_exceed_end(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto end_itr = table.end(); - // Should fail - ++end_itr; -} - -void test_multi_index::idx64_sk_iterator_exceed_end(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto end_itr = table.get_index().end(); - // Should fail - ++end_itr; -} - -void test_multi_index::idx64_pk_iterator_exceed_begin(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto begin_itr = table.begin(); - // Should fail - --begin_itr; -} - -void test_multi_index::idx64_sk_iterator_exceed_begin(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto begin_itr = table.get_index().begin(); - // Should fail - --begin_itr; -} - -void test_multi_index::idx64_pass_pk_ref_to_other_table(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table1 = _test_multi_index::idx64_table(receiver); - auto table2 = _test_multi_index::idx64_table(receiver); - - auto table1_pk_itr = table1.find(781); - eosio_assert(table1_pk_itr != table1.end() && table1_pk_itr->sec == N(bob), "idx64_pass_pk_ref_to_other_table - table.find() of existing primary key"); - - // Should fail - table2.iterator_to(*table1_pk_itr); -} - -void test_multi_index::idx64_pass_sk_ref_to_other_table(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table1 = _test_multi_index::idx64_table(receiver); - auto table2 = _test_multi_index::idx64_table(receiver); - - auto table1_pk_itr = table1.find(781); - eosio_assert(table1_pk_itr != table1.end() && table1_pk_itr->sec == N(bob), "idx64_pass_sk_ref_to_other_table - table.find() of existing primary key"); - - auto table2_sec_index = table2.get_index(); - // Should fail - table2_sec_index.iterator_to(*table1_pk_itr); -} - -void test_multi_index::idx64_pass_pk_end_itr_to_iterator_to(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto end_itr = table.end(); - // Should fail - table.iterator_to(*end_itr); -} - -void test_multi_index::idx64_pass_pk_end_itr_to_modify(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto end_itr = table.end(); - - auto payer = receiver; - // Should fail - table.modify(end_itr, payer, [](auto&){}); -} - -void test_multi_index::idx64_pass_pk_end_itr_to_erase(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto end_itr = table.end(); - - // Should fail - table.erase(end_itr); -} - -void test_multi_index::idx64_pass_sk_end_itr_to_iterator_to(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto sec_index = table.get_index(); - auto end_itr = sec_index.end(); - - // Should fail - sec_index.iterator_to(*end_itr); -} - -void test_multi_index::idx64_pass_sk_end_itr_to_modify(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto sec_index = table.get_index(); - auto end_itr = sec_index.end(); - - auto payer = receiver; - // Should fail - sec_index.modify(end_itr, payer, [](auto&){}); -} - - -void test_multi_index::idx64_pass_sk_end_itr_to_erase(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - auto sec_index = table.get_index(); - auto end_itr = sec_index.end(); - - // Should fail - sec_index.erase(end_itr); -} - -void test_multi_index::idx64_modify_primary_key(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - - auto pk_itr = table.find(781); - eosio_assert(pk_itr != table.end() && pk_itr->sec == N(bob), "idx64_modify_primary_key - table.find() of existing primary key"); - - auto payer = receiver; - - // Should fail - table.modify(pk_itr, payer, [](auto& r){ - r.id = 1100; - }); -} - -void test_multi_index::idx64_run_out_of_avl_pk(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - - auto pk_itr = table.find(781); - eosio_assert(pk_itr != table.end() && pk_itr->sec == N(bob), "idx64_modify_primary_key - table.find() of existing primary key"); - - auto payer = receiver; - - table.emplace( payer, [&]( auto& r ) { - r.id = static_cast(-4); - r.sec = N(alice); - }); - eosio_assert(table.available_primary_key() == static_cast(-3), "idx64_run_out_of_avl_pk - incorrect available primary key"); - - table.emplace( payer, [&]( auto& r ) { - r.id = table.available_primary_key(); - r.sec = N(bob); - }); - - // Should fail - table.available_primary_key(); -} - -void test_multi_index::idx64_sk_cache_pk_lookup(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - - auto sec_index = table.get_index(); - auto sk_itr = sec_index.find(N(bob)); - eosio_assert(sk_itr != sec_index.end() && sk_itr->id == 540, "idx64_sk_cache_pk_lookup - sec_index.find() of existing secondary key"); - - auto pk_itr = table.iterator_to(*sk_itr); - auto prev_itr = --pk_itr; - eosio_assert(prev_itr->id == 265 && prev_itr->sec == N(alice), "idx64_sk_cache_pk_lookup - previous record"); -} - -void test_multi_index::idx64_pk_cache_sk_lookup(uint64_t receiver, uint64_t code, uint64_t action) -{ - auto table = _test_multi_index::idx64_table(receiver); - - - auto pk_itr = table.find(540); - eosio_assert(pk_itr != table.end() && pk_itr->sec == N(bob), "idx64_pk_cache_sk_lookup - table.find() of existing primary key"); - - auto sec_index = table.get_index(); - auto sk_itr = sec_index.iterator_to(*pk_itr); - auto next_itr = ++sk_itr; - eosio_assert(next_itr->id == 781 && next_itr->sec == N(bob), "idx64_pk_cache_sk_lookup - next record"); -} - -#pragma GCC diagnostic pop diff --git a/contracts/test_ram_limit/CMakeLists.txt b/contracts/test_ram_limit/CMakeLists.txt deleted file mode 100644 index c7ee9939951..00000000000 --- a/contracts/test_ram_limit/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET test_ram_limit - INCLUDE_FOLDERS ${STANDARD_INCLUDE_FOLDERS} - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/test_ram_limit/test_ram_limit.abi b/contracts/test_ram_limit/test_ram_limit.abi deleted file mode 100644 index 9d3413b8b8e..00000000000 --- a/contracts/test_ram_limit/test_ram_limit.abi +++ /dev/null @@ -1,87 +0,0 @@ -{ - "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-03-29T02:09:11", - "version": "eosio::abi/1.0", - "types": [{ - "new_type_name": "account_name", - "type": "name" - }], - "structs": [{ - "name": "setentry", - "base": "", - "fields": [{ - "name": "payer", - "type": "account_name" - },{ - "name": "from", - "type": "uint64" - },{ - "name": "to", - "type": "uint64" - },{ - "name": "size", - "type": "uint64" - } - ] - },{ - "name": "rmentry", - "base": "", - "fields": [{ - "name": "from", - "type": "uint64" - },{ - "name": "to", - "type": "uint64" - } - ] - },{ - "name": "printentry", - "base": "", - "fields": [{ - "name": "from", - "type": "uint64" - },{ - "name": "to", - "type": "uint64" - } - ] - },{ - "name": "test", - "base": "", - "fields": [{ - "name": "key", - "type": "uint64" - },{ - "name": "data", - "type": "int8[]" - } - ] - } - ], - "actions": [{ - "name": "setentry", - "type": "setentry", - "ricardian_contract": "" - },{ - "name": "rmentry", - "type": "rmentry", - "ricardian_contract": "" - },{ - "name": "printentry", - "type": "printentry", - "ricardian_contract": "" - } - ], - "tables": [{ - "name": "test.table", - "index_type": "i64", - "key_names": [ - "key" - ], - "key_types": [ - "uint64" - ], - "type": "test" - } - ], - "ricardian_clauses": [] -} diff --git a/contracts/tic_tac_toe/CMakeLists.txt b/contracts/tic_tac_toe/CMakeLists.txt deleted file mode 100644 index c98bfc2ae49..00000000000 --- a/contracts/tic_tac_toe/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET tic_tac_toe - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/tic_tac_toe/tic_tac_toe.abi b/contracts/tic_tac_toe/tic_tac_toe.abi deleted file mode 100644 index 35cf2033d0d..00000000000 --- a/contracts/tic_tac_toe/tic_tac_toe.abi +++ /dev/null @@ -1,116 +0,0 @@ -{ - "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-07-06T13:38:01", - "version": "eosio::abi/1.0", - "types": [], - "structs": [{ - "name": "game", - "base": "", - "fields": [{ - "name": "challenger", - "type": "name" - },{ - "name": "host", - "type": "name" - },{ - "name": "turn", - "type": "name" - },{ - "name": "winner", - "type": "name" - },{ - "name": "board", - "type": "uint8[]" - } - ] - },{ - "name": "create", - "base": "", - "fields": [{ - "name": "challenger", - "type": "name" - },{ - "name": "host", - "type": "name" - } - ] - },{ - "name": "restart", - "base": "", - "fields": [{ - "name": "challenger", - "type": "name" - },{ - "name": "host", - "type": "name" - },{ - "name": "by", - "type": "name" - } - ] - },{ - "name": "close", - "base": "", - "fields": [{ - "name": "challenger", - "type": "name" - },{ - "name": "host", - "type": "name" - } - ] - },{ - "name": "move", - "base": "", - "fields": [{ - "name": "challenger", - "type": "name" - },{ - "name": "host", - "type": "name" - },{ - "name": "by", - "type": "name" - },{ - "name": "row", - "type": "uint16" - },{ - "name": "column", - "type": "uint16" - } - ] - } - ], - "actions": [{ - "name": "create", - "type": "create", - "ricardian_contract": "" - },{ - "name": "restart", - "type": "restart", - "ricardian_contract": "" - },{ - "name": "close", - "type": "close", - "ricardian_contract": "" - },{ - "name": "move", - "type": "move", - "ricardian_contract": "" - } - ], - "tables": [{ - "name": "games", - "index_type": "i64", - "key_names": [ - "challenger" - ], - "key_types": [ - "name" - ], - "type": "game" - } - ], - "ricardian_clauses": [], - "error_messages": [], - "abi_extensions": [] -} \ No newline at end of file diff --git a/contracts/tic_tac_toe/tic_tac_toe.cpp b/contracts/tic_tac_toe/tic_tac_toe.cpp deleted file mode 100644 index a6eb62eccf6..00000000000 --- a/contracts/tic_tac_toe/tic_tac_toe.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include "tic_tac_toe.hpp" - -using namespace eosio; - -/** - * @brief Check if cell is empty - * @param cell - value of the cell (should be either 0, 1, or 2) - * @return true if cell is empty - */ -bool is_empty_cell(const uint8_t& cell) { - return cell == 0; -} - -/** - * @brief Check for valid movement - * @detail Movement is considered valid if it is inside the board and done on empty cell - * @param row - the row of movement made by the player - * @param column - the column of movement made by the player - * @param board - the board on which the movement is being made - * @return true if movement is valid - */ -bool is_valid_movement(const uint16_t& row, const uint16_t& column, const vector& board) { - uint16_t board_width = tic_tac_toe::game::board_width; - uint16_t board_height = tic_tac_toe::game::board_height; - uint32_t movement_location = row * board_width + column; - bool is_valid = column < board_width && row < board_height && is_empty_cell(board[movement_location]); - return is_valid; -} - -/** - * @brief Get winner of the game - * @detail Winner of the game is the first player who made three consecutive aligned movement - * @param current_game - the game which we want to determine the winner of - * @return winner of the game (can be either none/ draw/ account name of host/ account name of challenger) - */ -account_name get_winner(const tic_tac_toe::game& current_game) { - auto& board = current_game.board; - - bool is_board_full = true; - - - - // Use bitwise AND operator to determine the consecutive values of each column, row and diagonal - // Since 3 == 0b11, 2 == 0b10, 1 = 0b01, 0 = 0b00 - vector consecutive_column(tic_tac_toe::game::board_width, 3 ); - vector consecutive_row(tic_tac_toe::game::board_height, 3 ); - uint32_t consecutive_diagonal_backslash = 3; - uint32_t consecutive_diagonal_slash = 3; - for (uint32_t i = 0; i < board.size(); i++) { - is_board_full &= !is_empty_cell(board[i]); - uint16_t row = uint16_t(i / tic_tac_toe::game::board_width); - uint16_t column = uint16_t(i % tic_tac_toe::game::board_width); - - // Calculate consecutive row and column value - consecutive_row[column] = consecutive_row[column] & board[i]; - consecutive_column[row] = consecutive_column[row] & board[i]; - // Calculate consecutive diagonal \ value - if (row == column) { - consecutive_diagonal_backslash = consecutive_diagonal_backslash & board[i]; - } - // Calculate consecutive diagonal / value - if ( row + column == tic_tac_toe::game::board_width - 1) { - consecutive_diagonal_slash = consecutive_diagonal_slash & board[i]; - } - } - - // Inspect the value of all consecutive row, column, and diagonal and determine winner - vector aggregate = { consecutive_diagonal_backslash, consecutive_diagonal_slash }; - aggregate.insert(aggregate.end(), consecutive_column.begin(), consecutive_column.end()); - aggregate.insert(aggregate.end(), consecutive_row.begin(), consecutive_row.end()); - for (auto value: aggregate) { - if (value == 1) { - return current_game.host; - } else if (value == 2) { - return current_game.challenger; - } - } - // Draw if the board is full, otherwise the winner is not determined yet - return is_board_full ? N(draw) : N(none); -} - -/** - * @brief Apply create action - */ -void tic_tac_toe::create(const account_name& challenger, const account_name& host) { - require_auth(host); - eosio_assert(challenger != host, "challenger shouldn't be the same as host"); - - // Check if game already exists - games existing_host_games(_self, host); - auto itr = existing_host_games.find( challenger ); - eosio_assert(itr == existing_host_games.end(), "game already exists"); - - existing_host_games.emplace(host, [&]( auto& g ) { - g.challenger = challenger; - g.host = host; - g.turn = host; - }); -} - -/** - * @brief Apply restart action - */ -void tic_tac_toe::restart(const account_name& challenger, const account_name& host, const account_name& by) { - require_auth(by); - - // Check if game exists - games existing_host_games(_self, host); - auto itr = existing_host_games.find( challenger ); - eosio_assert(itr != existing_host_games.end(), "game doesn't exists"); - - // Check if this game belongs to the action sender - eosio_assert(by == itr->host || by == itr->challenger, "this is not your game!"); - - // Reset game - existing_host_games.modify(itr, itr->host, []( auto& g ) { - g.reset_game(); - }); -} - -/** - * @brief Apply close action - */ -void tic_tac_toe::close(const account_name& challenger, const account_name& host) { - require_auth(host); - - // Check if game exists - games existing_host_games(_self, host); - auto itr = existing_host_games.find( challenger ); - eosio_assert(itr != existing_host_games.end(), "game doesn't exists"); - - // Remove game - existing_host_games.erase(itr); -} - -/** - * @brief Apply move action - */ -void tic_tac_toe::move(const account_name& challenger, const account_name& host, const account_name& by, const uint16_t& row, const uint16_t& column ) { - require_auth(by); - - // Check if game exists - games existing_host_games(_self, host); - auto itr = existing_host_games.find( challenger ); - eosio_assert(itr != existing_host_games.end(), "game doesn't exists"); - - // Check if this game hasn't ended yet - eosio_assert(itr->winner == N(none), "the game has ended!"); - // Check if this game belongs to the action sender - eosio_assert(by == itr->host || by == itr->challenger, "this is not your game!"); - // Check if this is the action sender's turn - eosio_assert(by == itr->turn, "it's not your turn yet!"); - - - // Check if user makes a valid movement - eosio_assert(is_valid_movement(row, column, itr->board), "not a valid movement!"); - - // Fill the cell, 1 for host, 2 for challenger - const uint8_t cell_value = itr->turn == itr->host ? 1 : 2; - const auto turn = itr->turn == itr->host ? itr->challenger : itr->host; - existing_host_games.modify(itr, itr->host, [&]( auto& g ) { - g.board[row * tic_tac_toe::game::board_width + column] = cell_value; - g.turn = turn; - g.winner = get_winner(g); - }); -} - - -EOSIO_ABI( tic_tac_toe, (create)(restart)(close)(move)) diff --git a/contracts/tic_tac_toe/tic_tac_toe.hpp b/contracts/tic_tac_toe/tic_tac_toe.hpp deleted file mode 100644 index f4f32982ff6..00000000000 --- a/contracts/tic_tac_toe/tic_tac_toe.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#include - -/** - * @defgroup tictactoecontract Tic Tac Toe Contract - * @brief Defines the PvP tic tac toe contract example - * @ingroup examplecontract - * - * @details - * For the following tic-tac-toe game: - * - Each pair of player can have 2 unique game, one where player_1 become host and player_2 become challenger and vice versa - * - The game data is stored in the "host" scope and use the "challenger" as the key - * - * (0,0) coordinate is on the top left corner of the board - * @code - * (0,2) - * (0,0) - | o | x where - = empty cell - * - | x | - x = move by host - * (2,0) x | o | o o = move by challenger - * @endcode - * - * Board is represented with number: - * - 0 represents empty cell - * - 1 represents cell filled by host - * - 2 represents cell filled by challenger - * Therefore, assuming x is host, the above board will have the following representation: [0, 2, 1, 0, 1, 0, 1, 2, 2] inside the game object - * - * In order to deploy this contract: - * - Create an account called tic.tac.toe - * - Add tic.tac.toe key to your wallet - * - Set the contract on the tic.tac.toe account - * - * How to play the game: - * - Create a game using `create` action, with you as the host and other account as the challenger. - * - The first move needs to be done by the host, use the `move` action to make a move by specifying which row and column to fill. - * - Then ask the challenger to make a move, after that it's back to the host turn again, repeat until the winner is determined. - * - If you want to restart the game, use the `restart` action - * - If you want to clear the game from the database to save up some space after the game has ended, use the `close` action - * @{ - */ - -class tic_tac_toe : public eosio::contract { - public: - tic_tac_toe( account_name self ):contract(self){} - /** - * @brief Information related to a game - * @abi table games i64 - */ - struct game { - static const uint16_t board_width = 3; - static const uint16_t board_height = board_width; - game() { - initialize_board(); - } - account_name challenger; - account_name host; - account_name turn; // = account name of host/ challenger - account_name winner = N(none); // = none/ draw/ name of host/ name of challenger - std::vector board; - - // Initialize board with empty cell - void initialize_board() { - board = std::vector(board_width * board_height, 0); - } - - // Reset game - void reset_game() { - initialize_board(); - turn = host; - winner = N(none); - } - - auto primary_key() const { return challenger; } - EOSLIB_SERIALIZE( game, (challenger)(host)(turn)(winner)(board)) - }; - - /** - * @brief The table definition, used to store existing games and their current state - */ - typedef eosio::multi_index< N(games), game> games; - - /// @abi action - /// Create a new game - void create(const account_name& challenger, const account_name& host); - - /// @abi action - /// Restart a game - /// @param by the account who wants to restart the game - void restart(const account_name& challenger, const account_name& host, const account_name& by); - - /// @abi action - /// Close an existing game, and remove it from storage - void close(const account_name& challenger, const account_name& host); - - /// @abi action - /// Make movement - /// @param by the account who wants to make the move - void move(const account_name& challenger, const account_name& host, const account_name& by, const uint16_t& row, const uint16_t& column); - -}; -/// @} diff --git a/eosio_build.sh b/eosio_build.sh index d1e77b6e85f..b37942a78ab 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -262,7 +262,7 @@ fi if ! "${CMAKE}" -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" -DCMAKE_CXX_COMPILER="${CXX_COMPILER}" \ - -DCMAKE_C_COMPILER="${C_COMPILER}" -DWASM_ROOT="${WASM_ROOT}" -DCORE_SYMBOL_NAME="${CORE_SYMBOL_NAME}" \ + -DCMAKE_C_COMPILER="${C_COMPILER}" -DCORE_SYMBOL_NAME="${CORE_SYMBOL_NAME}" \ -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" -DBUILD_MONGO_DB_PLUGIN=true \ -DENABLE_COVERAGE_TESTING="${ENABLE_COVERAGE_TESTING}" -DBUILD_DOXYGEN="${DOXYGEN}" \ -DCMAKE_INSTALL_PREFIX="/usr/local/eosio" ${LOCAL_CMAKE_FLAGS} "${SOURCE_DIR}" diff --git a/eosio_install.sh b/eosio_install.sh index 9ed195df7d0..d68a28a2d38 100755 --- a/eosio_install.sh +++ b/eosio_install.sh @@ -67,11 +67,7 @@ fi install_symlinks() { printf "\\n\\tInstalling EOSIO Binary Symlinks\\n\\n" create_symlink "cleos" - create_symlink "eosio-abigen" create_symlink "eosio-launcher" - create_symlink "eosio-s2wasm" - create_symlink "eosio-wast2wasm" - create_symlink "eosiocpp" create_symlink "keosd" create_symlink "nodeos" } diff --git a/eosio_uninstall.sh b/eosio_uninstall.sh index b025cae8c12..b080176a139 100755 --- a/eosio_uninstall.sh +++ b/eosio_uninstall.sh @@ -1,14 +1,9 @@ #! /bin/bash binaries=(cleos - eosio-abigen eosio-launcher - eosio-s2wasm - eosio-wast2wasm - eosiocpp keosd - nodeos - eosio-applesdemo) + nodeos) if [ -d "/usr/local/eosio" ]; then printf "\tDo you wish to remove this install? (requires sudo)\n" diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt deleted file mode 100644 index 4fac3528746..00000000000 --- a/externals/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory( binaryen ) diff --git a/externals/binaryen b/externals/binaryen deleted file mode 160000 index 16d641f62ab..00000000000 --- a/externals/binaryen +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 16d641f62ab14df845c87a63efe4d991b508d19a diff --git a/externals/magic_get b/externals/magic_get deleted file mode 160000 index 89fda1da702..00000000000 --- a/externals/magic_get +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 89fda1da702e6c76a22bfb6233e9e3d0641708ec diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 18013317c57..eeaf5afa771 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -7,8 +7,9 @@ add_subdirectory( appbase ) add_subdirectory( chain ) add_subdirectory( testing ) -#turn these off for now +#turn tools&tests off; not needed for library build set(BUILD_TESTS OFF CACHE BOOL "Build GTest-based tests") set(BUILD_TOOLS OFF CACHE BOOL "Build wabt tools") set(RUN_RE2C OFF CACHE BOOL "Run re2c") +set(WITH_EXCEPTIONS ON CACHE BOOL "Build with exceptions enabled" FORCE) add_subdirectory( wabt ) diff --git a/libraries/appbase b/libraries/appbase index 1d6e6e4a0b3..1dc659f92aa 160000 --- a/libraries/appbase +++ b/libraries/appbase @@ -1 +1 @@ -Subproject commit 1d6e6e4a0b334553658fe05cfa1e86081b6d0b4a +Subproject commit 1dc659f92aa1745946211dbb44591ac93a31d7aa diff --git a/libraries/chain/block_log.cpp b/libraries/chain/block_log.cpp index 41e9756483e..827cab3d298 100644 --- a/libraries/chain/block_log.cpp +++ b/libraries/chain/block_log.cpp @@ -247,6 +247,9 @@ namespace eosio { namespace chain { if (first_block) { append(first_block); + } else { + my->head.reset(); + my->head_id = {}; } auto pos = my->block_stream.tellp(); @@ -360,6 +363,8 @@ namespace eosio { namespace chain { while( pos < end_pos ) { fc::raw::unpack(my->block_stream, tmp); my->block_stream.read((char*)&pos, sizeof(pos)); + if(tmp.block_num() % 1000 == 0) + ilog( "Block log index reconstructed for block ${n}", ("n", tmp.block_num())); my->index_stream.write((char*)&pos, sizeof(pos)); } } // construct_index @@ -481,6 +486,8 @@ namespace eosio { namespace chain { new_block_stream.write( data.data(), data.size() ); new_block_stream.write( reinterpret_cast(&pos), sizeof(pos) ); block_num = tmp.block_num(); + if(block_num % 1000 == 0) + ilog( "Recovered block ${num}", ("num", block_num) ); pos = new_block_stream.tellp(); if( block_num == truncate_at_block ) break; diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 4d76e0da363..b2a390fe648 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -107,6 +107,7 @@ struct building_block { }; struct assembled_block { + block_id_type _id; pending_block_header_state _pending_block_header_state; vector _trx_metas; signed_block_ptr _unsigned_block; @@ -176,7 +177,6 @@ struct controller_impl { authorization_manager authorization; controller::config conf; chain_id_type chain_id; - bool replaying= false; optional replay_head_time; db_read_mode read_mode = db_read_mode::SPECULATIVE; bool in_trx_requiring_checks = false; ///< if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped @@ -193,11 +193,15 @@ struct controller_impl { * are removed from this list if they are re-applied in other blocks. Producers * can query this list when scheduling new transactions into blocks. */ - map unapplied_transactions; + map unapplied_transactions; void pop_block() { auto prev = fork_db.get_block( head->header.previous ); - EOS_ASSERT( prev, block_validate_exception, "attempt to pop beyond last irreversible block" ); + + if( !prev ) { + EOS_ASSERT( fork_db.root()->id == head->header.previous, block_validate_exception, "attempt to pop beyond last irreversible block" ); + prev = fork_db.root(); + } if( const auto* b = reversible_blocks.find(head->block_num) ) { @@ -209,9 +213,9 @@ struct controller_impl { for( const auto& t : head->trxs ) unapplied_transactions[t->signed_id] = t; } + head = prev; db.undo(); - } @@ -255,11 +259,6 @@ struct controller_impl { */ SET_APP_HANDLER( eosio, eosio, canceldelay ); - - fork_db.irreversible.connect( [&]( auto b ) { - on_irreversible(b); - }); - } /** @@ -288,90 +287,131 @@ struct controller_impl { } } - void on_irreversible( const block_state_ptr& s ) { - if( !blog.head() ) - blog.read_head(); + void log_irreversible() { + EOS_ASSERT( fork_db.root(), fork_database_exception, "fork database not properly initialized" ); const auto& log_head = blog.head(); - bool append_to_blog = false; - if (!log_head) { - if (s->block) { - EOS_ASSERT(s->block_num == blog.first_block_num(), block_log_exception, "block log has no blocks and is appending the wrong first block. Expected ${expected}, but received: ${actual}", - ("expected", blog.first_block_num())("actual", s->block_num)); - append_to_blog = true; - } else { - EOS_ASSERT(s->block_num == blog.first_block_num() - 1, block_log_exception, "block log has no blocks and is not properly set up to start after the snapshot"); - } + + auto lib_num = log_head ? log_head->block_num() : (blog.first_block_num() - 1); + + auto root_id = fork_db.root()->id; + + if( log_head ) { + EOS_ASSERT( root_id == log_head->id(), fork_database_exception, "fork database root does not match block log head" ); } else { - auto lh_block_num = log_head->block_num(); - if (s->block_num > lh_block_num) { - EOS_ASSERT(s->block_num - 1 == lh_block_num, unlinkable_block_exception, "unlinkable block", ("s->block_num", s->block_num)("lh_block_num", lh_block_num)); - EOS_ASSERT(s->block->previous == log_head->id(), unlinkable_block_exception, "irreversible doesn't link to block log head"); - append_to_blog = true; - } + EOS_ASSERT( fork_db.root()->block_num == lib_num, fork_database_exception, + "empty block log expects the first appended block to build off a block that is not the fork database root" ); } + auto fork_head = (read_mode == db_read_mode::IRREVERSIBLE) ? fork_db.pending_head() : fork_db.head(); - db.commit( s->block_num ); + if( fork_head->dpos_irreversible_blocknum <= lib_num ) + return; - if( append_to_blog ) { - blog.append(s->block); - } + /* + const auto& rbi = reversible_blocks.get_index(); + auto libitr = rbi.find( fork_head->dpos_irreversible_blocknum ); + EOS_ASSERT( libitr != rbi.end(), fork_database_exception, + "new LIB according to fork database is not in reversible block database" ); + + fc::datastream ds( libitr->packedblock.data(), libitr->packedblock.size() ); + block_header h; + fc::raw::unpack( ds, h ); + auto lib_id = h.id(); + */ - const auto& ubi = reversible_blocks.get_index(); - auto objitr = ubi.begin(); - while( objitr != ubi.end() && objitr->blocknum <= s->block_num ) { - reversible_blocks.remove( *objitr ); - objitr = ubi.begin(); - } + const auto branch = fork_db.fetch_branch( fork_head->id, fork_head->dpos_irreversible_blocknum ); //fork_db.fetch_branch( lib_id ); + try { + const auto& rbi = reversible_blocks.get_index(); - // the "head" block when a snapshot is loaded is virtual and has no block data, all of its effects - // should already have been loaded from the snapshot so, it cannot be applied - if (s->block) { - if (read_mode == db_read_mode::IRREVERSIBLE) { - // when applying a snapshot, head may not be present - // when not applying a snapshot, make sure this is the next block - if (!head || s->block_num == head->block_num + 1) { - apply_block(s->block, controller::block_status::complete); - head = s; - } else { - // otherwise, assert the one odd case where initializing a chain - // from genesis creates and applies the first block automatically. - // when syncing from another chain, this is pushed in again - EOS_ASSERT(!head || head->block_num == 1, block_validate_exception, "Attempting to re-apply an irreversible block that was not the implied genesis block"); + for( auto bitr = branch.rbegin(); bitr != branch.rend(); ++bitr ) { + if( read_mode == db_read_mode::IRREVERSIBLE ) { + apply_block( (*bitr)->block, controller::block_status::complete ); + head = (*bitr); + fork_db.mark_valid( head ); } - fork_db.mark_in_current_chain(head, true); - fork_db.set_validity(head, true); + emit( self.irreversible_block, *bitr ); + + db.commit( (*bitr)->block_num ); + root_id = (*bitr)->id; + + blog.append( (*bitr)->block ); + + auto rbitr = rbi.begin(); + while( rbitr != rbi.end() && rbitr->blocknum <= (*bitr)->block_num ) { + reversible_blocks.remove( *rbitr ); + rbitr = rbi.begin(); + } } - emit(self.irreversible_block, s); + } catch( fc::exception& ) { + if( root_id != fork_db.root()->id ) { + fork_db.advance_root( root_id ); + } + throw; } + + //db.commit( fork_head->dpos_irreversible_blocknum ); // redundant + + if( root_id != fork_db.root()->id ) { + fork_db.advance_root( root_id ); + } + } + + /** + * Sets fork database head to the genesis state. + */ + void initialize_blockchain_state() { + wlog( "Initializing new blockchain with genesis state" ); + producer_schedule_type initial_schedule{ 0, {{config::system_account_name, conf.genesis.initial_key}} }; + + block_header_state genheader; + genheader.active_schedule = initial_schedule; + genheader.pending_schedule.schedule = initial_schedule; + genheader.pending_schedule.schedule_hash = fc::sha256::hash(initial_schedule); + genheader.header.timestamp = conf.genesis.initial_timestamp; + genheader.header.action_mroot = conf.genesis.compute_chain_id(); + genheader.id = genheader.header.id(); + genheader.block_num = genheader.header.block_num(); + + head = std::make_shared(); + static_cast(*head) = genheader; + head->block = std::make_shared(genheader.header); + fork_db.reset( *head ); + db.set_revision( head->block_num ); + + initialize_database(); } void replay(std::function shutdown) { - auto blog_head = blog.read_head(); + auto blog_head = blog.head(); auto blog_head_time = blog_head->timestamp.to_time_point(); - replaying = true; replay_head_time = blog_head_time; auto start_block_num = head->block_num + 1; - ilog( "existing block log, attempting to replay from ${s} to ${n} blocks", - ("s", start_block_num)("n", blog_head->block_num()) ); - auto start = fc::time_point::now(); - while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) { - replay_push_block( next, controller::block_status::irreversible ); - if( next->block_num() % 100 == 0 ) { - std::cerr << std::setw(10) << next->block_num() << " of " << blog_head->block_num() <<"\r"; - if( shutdown() ) break; + + if( start_block_num <= blog_head->block_num() ) { + ilog( "existing block log, attempting to replay from ${s} to ${n} blocks", + ("s", start_block_num)("n", blog_head->block_num()) ); + while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) { + replay_push_block( next, controller::block_status::irreversible ); + if( next->block_num() % 100 == 0 ) { + std::cerr << std::setw(10) << next->block_num() << " of " << blog_head->block_num() <<"\r"; + if( shutdown() ) break; + } } - } - std::cerr<< "\n"; - ilog( "${n} blocks replayed", ("n", head->block_num - start_block_num) ); + std::cerr<< "\n"; + ilog( "${n} irreversible blocks replayed", ("n", 1 + head->block_num - start_block_num) ); - // if the irreverible log is played without undo sessions enabled, we need to sync the - // revision ordinal to the appropriate expected value here. - if( self.skip_db_sessions( controller::block_status::irreversible ) ) - db.set_revision(head->block_num); + fork_db.reset( *head ); + + // if the irreverible log is played without undo sessions enabled, we need to sync the + // revision ordinal to the appropriate expected value here. + if( self.skip_db_sessions( controller::block_status::irreversible ) ) + db.set_revision( head->block_num ); + } else { + ilog( "no irreversible blocks need to be replayed" ); + } int rev = 0; while( auto obj = reversible_blocks.find(head->block_num+1) ) { @@ -384,59 +424,88 @@ struct controller_impl { ilog( "replayed ${n} blocks in ${duration} seconds, ${mspb} ms/block", ("n", head->block_num - start_block_num)("duration", (end-start).count()/1000000) ("mspb", ((end-start).count()/1000.0)/(head->block_num-start_block_num)) ); - replaying = false; replay_head_time.reset(); } void init(std::function shutdown, const snapshot_reader_ptr& snapshot) { + auto blog_head = blog.head(); + auto lib_num = (blog_head ? blog_head->block_num() : 1); + auto last_block_num = lib_num; + + const auto& rbi = reversible_blocks.get_index(); + + { + auto rbitr = rbi.rbegin(); + if( rbitr != rbi.rend() ) { + EOS_ASSERT( blog_head, fork_database_exception, + "non-empty reversible blocks despite empty irreversible block log" ); + EOS_ASSERT( rbitr->blocknum > lib_num, fork_database_exception, + "reversible block database is inconsistent with the block log" ); + last_block_num = rbitr->blocknum; + } + } - bool report_integrity_hash = !!snapshot; - if (snapshot) { + // Setup state if necessary (or in the default case stay with already loaded state) + if( snapshot ) { EOS_ASSERT( !head, fork_database_exception, "" ); snapshot->validate(); read_from_snapshot( snapshot ); - auto end = blog.read_head(); - if( !end ) { - blog.reset( conf.genesis, signed_block_ptr(), head->block_num + 1 ); - } else if( end->block_num() > head->block_num ) { - replay( shutdown ); - } else { - EOS_ASSERT( end->block_num() == head->block_num, fork_database_exception, - "Block log is provided with snapshot but does not contain the head block from the snapshot" ); + if( !blog_head ) { + lib_num = head->block_num; + blog.reset( conf.genesis, signed_block_ptr(), lib_num + 1 ); } + + EOS_ASSERT( lib_num >= head->block_num, fork_database_exception, + "Block log is provided with snapshot but does not contain the head block from the snapshot" ); } else { if( !head ) { - initialize_fork_db(); // set head to genesis state + initialize_blockchain_state(); // set head to genesis state + } else { + EOS_ASSERT( last_block_num == head->block_num, fork_database_exception, + "reversible block database is inconsistent with fork database, replay blockchain", + ("head", head->block_num)("last_block_num", last_block_num) + ); } - auto end = blog.read_head(); - if( !end ) { - blog.reset( conf.genesis, head->block ); - } else if( end->block_num() > head->block_num ) { - replay( shutdown ); - report_integrity_hash = true; + if( !blog_head ) { + if( blog.first_block_num() > 1 ) { + lib_num = blog.first_block_num() - 1; + last_block_num = lib_num; + EOS_ASSERT( lib_num == head->block_num, fork_database_exception, + "Empty block log requires the next block to be appended to it to be at height ${first_block_num} which is not compatible with the head block", + ("first_block_num", blog.first_block_num())("head", head->block_num) + ); + } else { + blog.reset( conf.genesis, head->block ); + } } } - if( shutdown() ) return; + bool report_integrity_hash = !!snapshot || (lib_num > head->block_num); - const auto& ubi = reversible_blocks.get_index(); - auto objitr = ubi.rbegin(); - if( objitr != ubi.rend() ) { - EOS_ASSERT( objitr->blocknum == head->block_num, fork_database_exception, - "reversible block database is inconsistent with fork database, replay blockchain", - ("head",head->block_num)("unconfimed", objitr->blocknum) ); - } else { - auto end = blog.read_head(); - EOS_ASSERT( !end || end->block_num() == head->block_num, fork_database_exception, - "fork database exists but reversible block database does not, replay blockchain", - ("blog_head",end->block_num())("head",head->block_num) ); + // Trim any irreversible blocks from start of reversible blocks database + if( lib_num >= last_block_num ) { + last_block_num = lib_num; + auto rbitr = rbi.begin(); + while( rbitr != rbi.end() && rbitr->blocknum <= lib_num ) { + reversible_blocks.remove( *rbitr ); + rbitr = rbi.begin(); + } + } + + if( lib_num > head->block_num ) { + replay( shutdown ); // replay irreversible blocks and any reversible blocks + } else if( last_block_num > lib_num ) { + replay( shutdown ); // replay reversible blocks } - EOS_ASSERT( db.revision() >= head->block_num, fork_database_exception, "fork database is inconsistent with shared memory", - ("db",db.revision())("head",head->block_num) ); + if( shutdown() ) return; + + EOS_ASSERT( db.revision() >= head->block_num, fork_database_exception, + "fork database is inconsistent with state", + ("db",db.revision())("head",head->block_num) ); if( db.revision() > head->block_num ) { wlog( "warning: database revision (${db}) is greater than head block number (${head}), " @@ -451,7 +520,6 @@ struct controller_impl { const auto hash = calculate_integrity_hash(); ilog( "database initialized with hash: ${hash}", ("hash", hash) ); } - } ~controller_impl() { @@ -584,11 +652,9 @@ struct controller_impl { block_header_state head_header_state; section.read_row(head_header_state, db); + fork_db.reset( head_header_state ); auto head_state = std::make_shared(); static_cast(*head_state) = head_header_state; - fork_db.set(head_state); - fork_db.set_validity(head_state, true); - fork_db.mark_in_current_chain(head_state, true); head = head_state; snapshot_head_block = head->block_num; }); @@ -628,32 +694,6 @@ struct controller_impl { return enc.result(); } - - /** - * Sets fork database head to the genesis state. - */ - void initialize_fork_db() { - wlog( " Initializing new blockchain with genesis state " ); - producer_schedule_type initial_schedule{ 0, {{config::system_account_name, conf.genesis.initial_key}} }; - - block_header_state genheader; - genheader.active_schedule = initial_schedule; - genheader.pending_schedule.schedule = initial_schedule; - genheader.pending_schedule.schedule_hash = fc::sha256::hash(initial_schedule); - genheader.header.timestamp = conf.genesis.initial_timestamp; - genheader.header.action_mroot = conf.genesis.compute_chain_id(); - genheader.id = genheader.header.id(); - genheader.block_num = genheader.header.block_num(); - - head = std::make_shared(); - static_cast(*head) = genheader; - head->block = std::make_shared(genheader.header); - fork_db.set( head ); - db.set_revision( head->block_num ); - - initialize_database(); - } - void create_native_account( account_name name, const authority& owner, const authority& active, bool is_privileged = false ) { db.create([&](auto& a) { a.name = name; @@ -1152,7 +1192,7 @@ struct controller_impl { ) { // Promote proposed schedule to pending schedule. - if( !replaying ) { + if( !replay_head_time ) { ilog( "promoting proposed schedule (set in block ${proposed_num}) to pending; current block: ${n} lib: ${lib} schedule: ${schedule} ", ("proposed_num", *gpo.proposed_schedule_block_num)("n", pbhs.block_num) ("lib", pbhs.dpos_irreversible_blocknum) @@ -1193,7 +1233,7 @@ struct controller_impl { guard_pending.cancel(); } /// start_block - signed_block_ptr finalize_block() + void finalize_block() { EOS_ASSERT( pending, block_validate_exception, "it is not valid to finalize when there is no pending block"); EOS_ASSERT( pending->_block_stage.contains(), block_validate_exception, "already called finalize_block"); @@ -1224,13 +1264,15 @@ struct controller_impl { block_ptr->transactions = std::move( bb._pending_trx_receipts ); + auto id = block_ptr->id(); + // Update TaPoS table: - create_block_summary( block_ptr->id() ); + create_block_summary( id ); /* ilog( "finalized block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}", ("n",pbhs.block_num) - ("id",block_ptr->id()) + ("id",id) ("t",pbhs.timestamp) ("p",pbhs.producer) ("signing_key", pbhs.block_signing_key) @@ -1242,12 +1284,11 @@ struct controller_impl { */ pending->_block_stage = assembled_block{ + id, std::move( bb._pending_block_header_state ), std::move( bb._pending_trx_metas ), - block_ptr + std::move( block_ptr ) }; - - return block_ptr; } FC_CAPTURE_AND_RETHROW() } /// finalize_block /** @@ -1264,22 +1305,25 @@ struct controller_impl { auto bsp = pending->_block_stage.get()._block_state; - if (add_to_fork_db) { - bsp->in_current_chain = true; - bsp->validated = true; - auto new_bsp = fork_db.add(bsp, true); - emit(self.accepted_block_header, bsp); + if( add_to_fork_db ) { + fork_db.add( bsp ); + fork_db.mark_valid( bsp ); + emit( self.accepted_block_header, bsp ); head = fork_db.head(); - EOS_ASSERT(new_bsp == head, fork_database_exception, "committed block did not become the new head in fork database"); + EOS_ASSERT( bsp == head, fork_database_exception, "committed block did not become the new head in fork database"); } - if( !replaying ) { + if( !replay_head_time && read_mode != db_read_mode::IRREVERSIBLE ) { reversible_blocks.create( [&]( auto& ubo ) { ubo.blocknum = bsp->block_num; ubo.set_block( bsp->block ); }); } + if( add_to_fork_db ) { + log_irreversible(); + } + emit( self.accepted_block, bsp ); } catch (...) { // dont bother resetting pending, instead abort the block @@ -1346,18 +1390,17 @@ struct controller_impl { ("producer_receipt", receipt)("validator_receipt", trx_receipts.back()) ); } - auto block_ptr = finalize_block(); + finalize_block(); - // this implicitly asserts that all header fields (less the signature) are identical - auto id = block_ptr->id(); - EOS_ASSERT( producer_block_id == id, block_validate_exception, "Block ID does not match", - ("producer_block_id",producer_block_id)("validator_block_id",id) ); + auto& ab = pending->_block_stage.get(); - auto&& ab = pending->_block_stage.get(); + // this implicitly asserts that all header fields (less the signature) are identical + EOS_ASSERT( producer_block_id == ab._id, block_validate_exception, "Block ID does not match", + ("producer_block_id",producer_block_id)("validator_block_id",ab._id) ); auto bsp = std::make_shared( std::move( ab._pending_block_header_state ), - b, + std::move( ab._unsigned_block ), std::move( ab._trx_metas ), true // signature should have already been verified (assuming untrusted) prior to apply_block ); @@ -1382,8 +1425,9 @@ struct controller_impl { auto existing = fork_db.get_block( id ); EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) ); - auto prev = fork_db.get_block( b->previous ); - EOS_ASSERT( prev, unlinkable_block_exception, "unlinkable block ${id}", ("id", id)("previous", b->previous) ); + auto prev = fork_db.get_block_header( b->previous ); + EOS_ASSERT( prev, unlinkable_block_exception, + "unlinkable block ${id}", ("id", id)("previous", b->previous) ); return async_thread_pool( thread_pool, [b, prev]() { const bool skip_validate_signee = false; @@ -1399,19 +1443,23 @@ struct controller_impl { trusted_producer_light_validation = old_value; }); try { - block_state_ptr new_header_state = block_state_future.get(); - auto& b = new_header_state->block; + block_state_ptr bsp = block_state_future.get(); + const auto& b = bsp->block; + emit( self.pre_accepted_block, b ); - fork_db.add( new_header_state, false ); + fork_db.add( bsp ); if (conf.trusted_producers.count(b->producer)) { trusted_producer_light_validation = true; }; - emit( self.accepted_block_header, new_header_state ); - if ( read_mode != db_read_mode::IRREVERSIBLE ) { - maybe_switch_forks( s ); + emit( self.accepted_block_header, bsp ); + + if( read_mode != db_read_mode::IRREVERSIBLE ) { + maybe_switch_forks( fork_db.pending_head(), s ); + } else { + log_irreversible(); } } FC_LOG_AND_RETHROW( ) @@ -1429,41 +1477,49 @@ struct controller_impl { block_validate_exception, "invalid block status for replay" ); emit( self.pre_accepted_block, b ); const bool skip_validate_signee = !conf.force_all_checks; - auto new_header_state = fork_db.add( b, skip_validate_signee ); - emit( self.accepted_block_header, new_header_state ); + auto bsp = std::make_shared( *head, b, skip_validate_signee ); - if ( read_mode != db_read_mode::IRREVERSIBLE ) { - maybe_switch_forks( s ); + if( s != controller::block_status::irreversible ) { + fork_db.add( bsp ); } - // on replay irreversible is not emitted by fork database, so emit it explicitly here - if( s == controller::block_status::irreversible ) - emit( self.irreversible_block, new_header_state ); + emit( self.accepted_block_header, bsp ); + + if( s == controller::block_status::irreversible ) { + apply_block( bsp->block, s ); + head = bsp; + + // On replay, log_irreversible is not called and so no irreversible_block signal is emittted. + // So emit it explicitly here. + emit( self.irreversible_block, bsp ); + } else if( read_mode != db_read_mode::IRREVERSIBLE ) { + maybe_switch_forks( bsp, s ); + } else { + log_irreversible(); + } } FC_LOG_AND_RETHROW( ) } - void maybe_switch_forks( controller::block_status s ) { - auto new_head = fork_db.head(); - + void maybe_switch_forks( const block_state_ptr& new_head, controller::block_status s ) { + bool head_changed = true; if( new_head->header.previous == head->id ) { try { apply_block( new_head->block, s ); - fork_db.mark_in_current_chain( new_head, true ); - fork_db.set_validity( new_head, true ); + fork_db.mark_valid( new_head ); head = new_head; } catch ( const fc::exception& e ) { - fork_db.set_validity( new_head, false ); // Removes new_head from fork_db index, so no need to mark it as not in the current chain. + fork_db.remove( new_head->id ); throw; } } else if( new_head->id != head->id ) { + auto old_head = head; ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})", ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) ); auto branches = fork_db.fetch_branch_from( new_head->id, head->id ); for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) { - fork_db.mark_in_current_chain( *itr, false ); pop_block(); } EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception, @@ -1472,24 +1528,26 @@ struct controller_impl { for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr ) { optional except; try { - apply_block( (*ritr)->block, (*ritr)->validated ? controller::block_status::validated : controller::block_status::complete ); + apply_block( (*ritr)->block, (*ritr)->is_valid() ? controller::block_status::validated : controller::block_status::complete ); + fork_db.mark_valid( *ritr ); head = *ritr; - fork_db.mark_in_current_chain( *ritr, true ); - (*ritr)->validated = true; + } catch (const fc::exception& e) { + except = e; } - catch (const fc::exception& e) { except = e; } - if (except) { + if( except ) { elog("exception thrown while switching forks ${e}", ("e", except->to_detail_string())); // ritr currently points to the block that threw - // if we mark it invalid it will automatically remove all forks built off it. - fork_db.set_validity( *ritr, false ); + // Remove the block that threw and all forks built off it. + fork_db.remove( (*ritr)->id ); + + EOS_ASSERT( head->id == fork_db.head()->id, fork_database_exception, + "loss of sync between fork_db and controller head during fork switch error" ); // pop all blocks from the bad fork // ritr base is a forward itr to the last block successfully applied auto applied_itr = ritr.base(); for( auto itr = applied_itr; itr != branches.first.end(); ++itr ) { - fork_db.mark_in_current_chain( *itr, false ); pop_block(); } EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception, @@ -1499,13 +1557,17 @@ struct controller_impl { for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) { apply_block( (*ritr)->block, controller::block_status::validated /* we previously validated these blocks*/ ); head = *ritr; - fork_db.mark_in_current_chain( *ritr, true ); } throw *except; } // end if exception } /// end for each block in branch - ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id) ); + ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id)); + } else { + head_changed = false; } + + if( head_changed ) + log_irreversible(); } /// push_block void abort_block() { @@ -1789,10 +1851,12 @@ controller::controller( const controller::config& cfg ) controller::~controller() { my->abort_block(); + /* Shouldn't be needed anymore. //close fork_db here, because it can generate "irreversible" signal to this controller, //in case if read-mode == IRREVERSIBLE, we will apply latest irreversible block //for that we need 'my' to be valid pointer pointing to valid controller_impl. my->fork_db.close(); + */ } void controller::add_indices() { @@ -1822,13 +1886,13 @@ void controller::start_block( block_timestamp_type when, uint16_t confirm_block_ block_state_ptr controller::finalize_block( const std::function& signer_callback ) { validate_db_available_size(); - auto block_ptr = my->finalize_block(); + my->finalize_block(); auto& ab = my->pending->_block_stage.get(); auto bsp = std::make_shared( std::move( ab._pending_block_header_state ), - std::move( block_ptr ), + std::move( ab._unsigned_block ), std::move( ab._trx_metas ), signer_callback ); @@ -1952,6 +2016,22 @@ account_name controller::fork_db_head_block_producer()const { return my->fork_db.head()->header.producer; } +uint32_t controller::fork_db_pending_head_block_num()const { + return my->fork_db.pending_head()->block_num; +} + +block_id_type controller::fork_db_pending_head_block_id()const { + return my->fork_db.pending_head()->id; +} + +time_point controller::fork_db_pending_head_block_time()const { + return my->fork_db.pending_head()->header.timestamp; +} + +account_name controller::fork_db_pending_head_block_producer()const { + return my->fork_db.pending_head()->header.producer; +} + time_point controller::pending_block_time()const { EOS_ASSERT( my->pending, block_validate_exception, "no pending block" ); @@ -1990,7 +2070,10 @@ const vector& controller::get_pending_trx_receipts()const { } uint32_t controller::last_irreversible_block_num() const { - return std::max( my->head->dpos_irreversible_blocknum, my->snapshot_head_block); + uint32_t lib_num = (my->read_mode == db_read_mode::IRREVERSIBLE) + ? my->fork_db.pending_head()->dpos_irreversible_blocknum + : my->head->dpos_irreversible_blocknum; + return std::max( lib_num, my->snapshot_head_block ); } block_id_type controller::last_irreversible_block_id() const { @@ -2000,8 +2083,12 @@ block_id_type controller::last_irreversible_block_id() const { if( block_header::num_from_id(tapos_block_summary.block_id) == lib_num ) return tapos_block_summary.block_id; - return fetch_block_by_number(lib_num)->id(); + auto signed_blk = my->blog.read_block_by_num( lib_num ); + EOS_ASSERT( BOOST_LIKELY( signed_blk != nullptr ), unknown_block_exception, + "Could not find block: ${block}", ("block", lib_num) ); + + return signed_blk->id(); } const dynamic_global_property_object& controller::get_dynamic_global_properties()const { @@ -2020,8 +2107,8 @@ signed_block_ptr controller::fetch_block_by_id( block_id_type id )const { } signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const { try { - auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num ); - if( blk_state && blk_state->block ) { + auto blk_state = fetch_block_state_by_number( block_num ); + if( blk_state ) { return blk_state->block; } @@ -2034,14 +2121,46 @@ block_state_ptr controller::fetch_block_state_by_id( block_id_type id )const { } block_state_ptr controller::fetch_block_state_by_number( uint32_t block_num )const { try { - auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num ); - return blk_state; + const auto& rev_blocks = my->reversible_blocks.get_index(); + auto objitr = rev_blocks.find(block_num); + + if( objitr == rev_blocks.end() ) { + if( my->read_mode == db_read_mode::IRREVERSIBLE ) { + return my->fork_db.search_on_branch( my->fork_db.pending_head()->id, block_num ); + } else { + return block_state_ptr(); + } + } + + fc::datastream ds( objitr->packedblock.data(), objitr->packedblock.size() ); + block_header h; + fc::raw::unpack( ds, h ); + // Only need the block id to then look up the block state in fork database, so just unpack the block_header from the stored packed data. + // Avoid calling objitr->get_block() since that constructs a new signed_block in heap memory and unpacks the full signed_block from the stored packed data. + + return my->fork_db.get_block( h.id() ); } FC_CAPTURE_AND_RETHROW( (block_num) ) } block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try { - auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num ); - if( blk_state ) { - return blk_state->id; + const auto& blog_head = my->blog.head(); + + bool find_in_blog = (blog_head && block_num <= blog_head->block_num()); + + if( !find_in_blog ) { + if( my->read_mode != db_read_mode::IRREVERSIBLE ) { + const auto& rev_blocks = my->reversible_blocks.get_index(); + auto objitr = rev_blocks.find(block_num); + if( objitr != rev_blocks.end() ) { + fc::datastream ds( objitr->packedblock.data(), objitr->packedblock.size() ); + block_header h; + fc::raw::unpack( ds, h ); + return h.id(); + } + } else { + auto bsp = my->fork_db.search_on_branch( my->fork_db.pending_head()->id, block_num ); + + if( bsp ) return bsp->id; + } } auto signed_blk = my->blog.read_block_by_num(block_num); @@ -2103,7 +2222,7 @@ int64_t controller::set_proposed_producers( vector producers ) { int64_t version = sch.version; - wlog( "proposed producer schedule with version ${v}", ("v", version) ); + ilog( "proposed producer schedule with version ${v}", ("v", version) ); my->db.modify( gpo, [&]( auto& gp ) { gp.proposed_schedule_block_num = cur_block_num; diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index f73b3aec07d..68238ccddda 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -13,6 +13,15 @@ namespace eosio { namespace chain { using boost::multi_index_container; using namespace boost::multi_index; + const uint32_t fork_database::magic_number = 0x30510FDB; + + const uint32_t fork_database::min_supported_version = 1; + const uint32_t fork_database::max_supported_version = 1; + + /** + * History: + * Version 1: initial version of the new refactored fork database portable format + */ struct by_block_id; struct by_block_num; @@ -23,26 +32,31 @@ namespace eosio { namespace chain { indexed_by< hashed_unique< tag, member, std::hash>, ordered_non_unique< tag, const_mem_fun >, - ordered_non_unique< tag, + ordered_unique< tag, composite_key< block_state, - member, - member - >, - composite_key_compare< std::less, std::greater > - >, - ordered_non_unique< tag, - composite_key< block_header_state, - member, - member + member, + member, + member, + member >, - composite_key_compare< std::greater, std::greater > + composite_key_compare< + std::greater, + std::greater, + std::greater, + sha256_less + > > > > fork_multi_index_type; + bool first_preferred( const block_header_state& lhs, const block_header_state& rhs ) { + return std::tie( lhs.dpos_irreversible_blocknum, lhs.block_num ) + > std::tie( rhs.dpos_irreversible_blocknum, rhs.block_num ); + } struct fork_database_impl { fork_multi_index_type index; + block_state_ptr root; // Only uses the block_header_state portion block_state_ptr head; fc::path datadir; }; @@ -56,48 +70,137 @@ namespace eosio { namespace chain { auto fork_db_dat = my->datadir / config::forkdb_filename; if( fc::exists( fork_db_dat ) ) { - string content; - fc::read_file_contents( fork_db_dat, content ); - - fc::datastream ds( content.data(), content.size() ); - unsigned_int size; fc::raw::unpack( ds, size ); - for( uint32_t i = 0, n = size.value; i < n; ++i ) { - block_state s; - fc::raw::unpack( ds, s ); - set( std::make_shared( move( s ) ) ); - } - block_id_type head_id; - fc::raw::unpack( ds, head_id ); - - my->head = get_block( head_id ); + try { + string content; + fc::read_file_contents( fork_db_dat, content ); + + fc::datastream ds( content.data(), content.size() ); + + // validate totem + uint32_t totem = 0; + fc::raw::unpack( ds, totem ); + EOS_ASSERT( totem == magic_number, fork_database_exception, + "Fork database file '${filename}' has unexpected magic number: ${actual_totem}. Expected ${expected_totem}", + ("filename", fork_db_dat.generic_string()) + ("actual_totem", totem) + ("expected_totem", magic_number) + ); + + // validate version + uint32_t version = 0; + fc::raw::unpack( ds, version ); + EOS_ASSERT( version >= min_supported_version && version <= max_supported_version, + fork_database_exception, + "Unsupported version of fork database file '${filename}'. " + "Fork database version is ${version} while code supports version(s) [${min},${max}]", + ("filename", fork_db_dat.generic_string()) + ("version", version) + ("min", min_supported_version) + ("max", max_supported_version) + ); + + block_header_state bhs; + fc::raw::unpack( ds, bhs ); + reset( bhs ); + + unsigned_int size; fc::raw::unpack( ds, size ); + for( uint32_t i = 0, n = size.value; i < n; ++i ) { + block_state s; + fc::raw::unpack( ds, s ); + for( const auto& receipt : s.block->transactions ) { + if( receipt.trx.contains() ) { + const auto& pt = receipt.trx.get(); + s.trxs.push_back( std::make_shared( std::make_shared(pt) ) ); + } + } + add( std::make_shared( move( s ) ) ); + } + block_id_type head_id; + fc::raw::unpack( ds, head_id ); + + if( my->root->id == head_id ) { + my->head = my->root; + } else { + my->head = get_block( head_id ); + EOS_ASSERT( my->head, fork_database_exception, + "could not find head while reconstructing fork database from file; '${filename}' is likely corrupted", + ("filename", fork_db_dat.generic_string()) ); + } + + auto candidate = my->index.get().begin(); + if( candidate == my->index.get().end() || !(*candidate)->is_valid() ) { + EOS_ASSERT( my->head->id == my->root->id, fork_database_exception, + "head not set to root despite no better option available; '${filename}' is likely corrupted", + ("filename", fork_db_dat.generic_string()) ); + } else { + EOS_ASSERT( !first_preferred( **candidate, *my->head ), fork_database_exception, + "head not set to best available option available; '${filename}' is likely corrupted", + ("filename", fork_db_dat.generic_string()) ); + } + } FC_CAPTURE_AND_RETHROW( (fork_db_dat) ) fc::remove( fork_db_dat ); } } void fork_database::close() { - if( my->index.size() == 0 ) return; - auto fork_db_dat = my->datadir / config::forkdb_filename; + + if( !my->root ) { + if( my->index.size() > 0 ) { + elog( "fork_database is in a bad state when closing; not writing out '${filename}'", + ("filename", fork_db_dat.generic_string()) ); + } + return; + } + std::ofstream out( fork_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc ); + fc::raw::pack( out, magic_number ); + fc::raw::pack( out, max_supported_version ); // write out current version which is always max_supported_version + fc::raw::pack( out, *static_cast(&*my->root) ); uint32_t num_blocks_in_fork_db = my->index.size(); fc::raw::pack( out, unsigned_int{num_blocks_in_fork_db} ); - for( const auto& s : my->index ) { - fc::raw::pack( out, *s ); + + const auto& indx = my->index.get(); + + auto unvalidated_itr = indx.rbegin(); + auto unvalidated_end = boost::make_reverse_iterator( indx.lower_bound( false ) ); + + auto validated_itr = unvalidated_end; + auto validated_end = indx.rend(); + + for( bool unvalidated_remaining = (unvalidated_itr != unvalidated_end), + validated_remaining = (validated_itr != validated_end); + + unvalidated_remaining || validated_remaining; + + unvalidated_remaining = (unvalidated_itr != unvalidated_end), + validated_remaining = (validated_itr != validated_end) + ) + { + auto itr = (validated_remaining ? validated_itr : unvalidated_itr); + + if( unvalidated_remaining && validated_remaining ) { + if( first_preferred( **unvalidated_itr, **validated_itr ) ) { + itr = unvalidated_itr; + ++unvalidated_itr; + } else { + ++validated_itr; + } + } else if( unvalidated_remaining ) { + ++unvalidated_itr; + } else { + ++validated_itr; + } + + fc::raw::pack( out, *(*itr) ); } - if( my->head ) + + if( my->head ) { fc::raw::pack( out, my->head->id ); - else - fc::raw::pack( out, block_id_type() ); - - /// we don't normally indicate the head block as irreversible - /// we cannot normally prune the lib if it is the head block because - /// the next block needs to build off of the head block. We are exiting - /// now so we can prune this block as irreversible before exiting. - auto lib = my->head->dpos_irreversible_blocknum; - auto oldest = *my->index.get().begin(); - if( oldest->block_num <= lib ) { - prune( oldest ); + } else { + elog( "head not set in fork database; '${filename}' will be corrupted", + ("filename", fork_db_dat.generic_string()) ); } my->index.clear(); @@ -107,64 +210,112 @@ namespace eosio { namespace chain { close(); } - void fork_database::set( block_state_ptr s ) { - auto result = my->index.insert( s ); - EOS_ASSERT( s->id == s->header.id(), fork_database_exception, - "block state id (${id}) is different from block state header id (${hid})", ("id", string(s->id))("hid", string(s->header.id())) ); + void fork_database::reset( const block_header_state& root_bhs ) { + my->index.clear(); + my->root = std::make_shared(); + static_cast(*my->root) = root_bhs; + my->root->validated = true; + my->head = my->root; + } + + void fork_database::advance_root( const block_id_type& id ) { + EOS_ASSERT( my->root, fork_database_exception, "root not yet set" ); - //FC_ASSERT( s->block_num == s->header.block_num() ); + auto new_root = get_block( id ); + EOS_ASSERT( new_root, fork_database_exception, + "cannot advance root to a block that does not exist in the fork database" ); + EOS_ASSERT( new_root->is_valid(), fork_database_exception, + "cannot advance root to a block that has not yet been validated" ); - EOS_ASSERT( result.second, fork_database_exception, "unable to insert block state, duplicate state detected" ); - if( !my->head ) { - my->head = s; - } else if( my->head->block_num < s->block_num ) { - my->head = s; + + vector blocks_to_remove; + for( auto b = new_root; b; ) { + blocks_to_remove.push_back( b->header.previous ); + b = get_block( blocks_to_remove.back() ); + EOS_ASSERT( b || blocks_to_remove.back() == my->root->id, fork_database_exception, "invariant violation: orphaned branch was present in forked database" ); } - } - block_state_ptr fork_database::add( const block_state_ptr& n, bool skip_validate_previous ) { - EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" ); - EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); + // The new root block should be erased from the fork database index individually rather than with the remove method, + // because we do not want the blocks branching off of it to be removed from the fork database. + my->index.erase( my->index.find( id ) ); - if( !skip_validate_previous ) { - auto prior = my->index.find( n->block->previous ); - EOS_ASSERT( prior != my->index.end(), unlinkable_block_exception, - "unlinkable block", ("id", n->block->id())("previous", n->block->previous) ); + // The other blocks to be removed are removed using the remove method so that orphaned branches do not remain in the fork database. + for( const auto& block_id : blocks_to_remove ) { + remove( block_id ); } - auto inserted = my->index.insert(n); - EOS_ASSERT( inserted.second, fork_database_exception, "duplicate block added?" ); + // Even though fork database no longer needs block or trxs when a block state becomes a root of the tree, + // avoid mutating the block state at all, for example clearing the block shared pointer, because other + // parts of the code which run asynchronously (e.g. mongo_db_plugin) may later expect it remain unmodified. - my->head = *my->index.get().begin(); + my->root = new_root; + } - auto lib = my->head->dpos_irreversible_blocknum; - auto oldest = *my->index.get().begin(); + block_header_state_ptr fork_database::get_block_header( const block_id_type& id )const { + const auto& by_id_idx = my->index.get(); - if( oldest->block_num < lib ) { - prune( oldest ); + if( my->root->id == id ) { + return my->root; } - return n; + auto itr = my->index.find( id ); + if( itr != my->index.end() ) + return *itr; + + return block_header_state_ptr(); } - block_state_ptr fork_database::add( signed_block_ptr b, bool skip_validate_signee ) { - EOS_ASSERT( b, fork_database_exception, "attempt to add null block" ); - EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); + void fork_database::add( const block_state_ptr& n ) { + EOS_ASSERT( my->root, fork_database_exception, "root not yet set" ); + EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" ); - const auto& by_id_idx = my->index.get(); - auto existing = by_id_idx.find( b->id() ); - EOS_ASSERT( existing == by_id_idx.end(), fork_database_exception, "we already know about this block" ); + EOS_ASSERT( get_block_header( n->header.previous ), unlinkable_block_exception, + "unlinkable block", ("id", n->id)("previous", n->header.previous) ); - auto prior = by_id_idx.find( b->previous ); - EOS_ASSERT( prior != by_id_idx.end(), unlinkable_block_exception, "unlinkable block", ("id", string(b->id()))("previous", string(b->previous)) ); + auto inserted = my->index.insert(n); + EOS_ASSERT( inserted.second, fork_database_exception, "duplicate block added", ("id", n->id) ); - auto result = std::make_shared( **prior, move(b), skip_validate_signee ); - EOS_ASSERT( result, fork_database_exception , "fail to add new block state" ); - return add(result, true); + auto candidate = my->index.get().begin(); + if( (*candidate)->is_valid() ) { + my->head = *candidate; + } } + const block_state_ptr& fork_database::root()const { return my->root; } + const block_state_ptr& fork_database::head()const { return my->head; } + block_state_ptr fork_database::pending_head()const { + const auto& indx = my->index.get(); + + auto itr = indx.lower_bound( false ); + if( itr != indx.end() && !(*itr)->is_valid() ) { + if( first_preferred( **itr, *my->head ) ) + return *itr; + } + + return my->head; + } + + branch_type fork_database::fetch_branch( const block_id_type& h, uint32_t trim_after_block_num )const { + branch_type result; + for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) { + if( s->block_num <= trim_after_block_num ) + result.push_back( s ); + } + + return result; + } + + block_state_ptr fork_database::search_on_branch( const block_id_type& h, uint32_t block_num )const { + for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) { + if( s->block_num == block_num ) + return s; + } + + return {}; + } + /** * Given two head blocks, return two branches of the fork graph that * end with a common ancestor (same prior block) @@ -179,14 +330,18 @@ namespace eosio { namespace chain { { result.first.push_back(first_branch); first_branch = get_block( first_branch->header.previous ); - EOS_ASSERT( first_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", string(first_branch->header.previous)) ); + EOS_ASSERT( first_branch, fork_db_block_not_found, + "block ${id} does not exist", + ("id", first_branch->header.previous) ); } while( second_branch->block_num > first_branch->block_num ) { result.second.push_back( second_branch ); second_branch = get_block( second_branch->header.previous ); - EOS_ASSERT( second_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", string(second_branch->header.previous)) ); + EOS_ASSERT( second_branch, fork_db_block_not_found, + "block ${id} does not exist", + ("id", second_branch->header.previous) ); } while( first_branch->header.previous != second_branch->header.previous ) @@ -197,7 +352,9 @@ namespace eosio { namespace chain { second_branch = get_block( second_branch->header.previous ); EOS_ASSERT( first_branch && second_branch, fork_db_block_not_found, "either block ${fid} or ${sid} does not exist", - ("fid", string(first_branch->header.previous))("sid", string(second_branch->header.previous)) ); + ("fid", first_branch->header.previous) + ("sid", second_branch->header.previous) + ); } if( first_branch && second_branch ) @@ -208,71 +365,47 @@ namespace eosio { namespace chain { return result; } /// fetch_branch_from - /// remove all of the invalid forks built of this id including this id + /// remove all of the invalid forks built off of this id including this id void fork_database::remove( const block_id_type& id ) { vector remove_queue{id}; + const auto& previdx = my->index.get(); + const auto head_id = my->head->id; for( uint32_t i = 0; i < remove_queue.size(); ++i ) { - auto itr = my->index.find( remove_queue[i] ); - if( itr != my->index.end() ) - my->index.erase(itr); + EOS_ASSERT( remove_queue[i] != head_id, fork_database_exception, + "removing the block and its descendants would remove the current head block" ); - auto& previdx = my->index.get(); - auto previtr = previdx.lower_bound(remove_queue[i]); + auto previtr = previdx.lower_bound( remove_queue[i] ); while( previtr != previdx.end() && (*previtr)->header.previous == remove_queue[i] ) { remove_queue.push_back( (*previtr)->id ); ++previtr; } } - //wdump((my->index.size())); - my->head = *my->index.get().begin(); - } - void fork_database::set_validity( const block_state_ptr& h, bool valid ) { - if( !valid ) { - remove( h->id ); - } else { - /// remove older than irreversible and mark block as valid - h->validated = true; + for( const auto& block_id : remove_queue ) { + auto itr = my->index.find( block_id ); + if( itr != my->index.end() ) + my->index.erase(itr); } } - void fork_database::mark_in_current_chain( const block_state_ptr& h, bool in_current_chain ) { - if( h->in_current_chain == in_current_chain ) - return; + void fork_database::mark_valid( const block_state_ptr& h ) { + if( h->validated ) return; auto& by_id_idx = my->index.get(); - auto itr = by_id_idx.find( h->id ); - EOS_ASSERT( itr != by_id_idx.end(), fork_db_block_not_found, "could not find block in fork database" ); - - by_id_idx.modify( itr, [&]( auto& bsp ) { // Need to modify this way rather than directly so that Boost MultiIndex can re-sort - bsp->in_current_chain = in_current_chain; - }); - } - void fork_database::prune( const block_state_ptr& h ) { - auto num = h->block_num; - - auto& by_bn = my->index.get(); - auto bni = by_bn.begin(); - while( bni != by_bn.end() && (*bni)->block_num < num ) { - prune( *bni ); - bni = by_bn.begin(); - } + auto itr = by_id_idx.find( h->id ); + EOS_ASSERT( itr != by_id_idx.end(), fork_database_exception, + "block state not in fork database; cannot mark as valid", + ("id", h->id) ); - auto itr = my->index.find( h->id ); - if( itr != my->index.end() ) { - irreversible(*itr); - my->index.erase(itr); - } + by_id_idx.modify( itr, []( block_state_ptr& bsp ) { + bsp->validated = true; + } ); - auto& numidx = my->index.get(); - auto nitr = numidx.lower_bound( num ); - while( nitr != numidx.end() && (*nitr)->block_num == num ) { - auto itr_to_remove = nitr; - ++nitr; - auto id = (*itr_to_remove)->id; - remove( id ); + auto candidate = my->index.get().begin(); + if( first_preferred( **candidate, *my->head ) ) { + my->head = *candidate; } } @@ -283,17 +416,4 @@ namespace eosio { namespace chain { return block_state_ptr(); } - block_state_ptr fork_database::get_block_in_current_chain_by_num( uint32_t n )const { - const auto& numidx = my->index.get(); - auto nitr = numidx.lower_bound( n ); - // following asserts removed so null can be returned - //FC_ASSERT( nitr != numidx.end() && (*nitr)->block_num == n, - // "could not find block in fork database with block number ${block_num}", ("block_num", n) ); - //FC_ASSERT( (*nitr)->in_current_chain == true, - // "block (with block number ${block_num}) found in fork database is not in the current chain", ("block_num", n) ); - if( nitr == numidx.end() || (*nitr)->block_num != n || (*nitr)->in_current_chain != true ) - return block_state_ptr(); - return *nitr; - } - } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/authority.hpp b/libraries/chain/include/eosio/chain/authority.hpp index 373deb56120..e7a7307bb56 100644 --- a/libraries/chain/include/eosio/chain/authority.hpp +++ b/libraries/chain/include/eosio/chain/authority.hpp @@ -66,6 +66,15 @@ struct authority { } } + authority( permission_level p, uint32_t delay_sec = 0 ) + :threshold(1),accounts({{p,1}}) + { + if( delay_sec > 0 ) { + threshold = 2; + waits.push_back(wait_weight{delay_sec, 1}); + } + } + authority( uint32_t t, vector k, vector p = {}, vector w = {} ) :threshold(t),keys(move(k)),accounts(move(p)),waits(move(w)){} authority(){} diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 85a09047fdd..2ec87664c28 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -61,7 +61,7 @@ struct block_header_state : public detail::block_header_state_common { block_header_state() = default; - block_header_state( detail::block_header_state_common&& base ) + explicit block_header_state( detail::block_header_state_common&& base ) :detail::block_header_state_common( std::move(base) ) {} @@ -81,7 +81,7 @@ struct block_header_state : public detail::block_header_state_common { void verify_signee(const public_key_type& signee)const; }; - +using block_header_state_ptr = std::shared_ptr; } } /// namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 98fb1594299..94defc13cfd 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -31,10 +31,11 @@ namespace eosio { namespace chain { block_state() = default; - /// weak_ptr prev_block_state.... + bool is_valid()const { return validated; } + + signed_block_ptr block; bool validated = false; - bool in_current_chain = false; /// this data is redundant with the data stored in block, but facilitates /// recapturing transactions when we pop a block @@ -45,4 +46,4 @@ namespace eosio { namespace chain { } } /// namespace eosio::chain -FC_REFLECT_DERIVED( eosio::chain::block_state, (eosio::chain::block_header_state), (block)(validated)(in_current_chain) ) +FC_REFLECT_DERIVED( eosio::chain::block_state, (eosio::chain::block_header_state), (block)(validated) ) diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 0d5ff9e9469..a780cf42832 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -18,7 +18,7 @@ const static auto default_reversible_cache_size = 340*1024*1024ll;/// 1MB * 340 const static auto default_reversible_guard_size = 2*1024*1024ll;/// 1MB * 340 blocks based on 21 producer BFT delay const static auto default_state_dir_name = "state"; -const static auto forkdb_filename = "forkdb.dat"; +const static auto forkdb_filename = "fork_db.dat"; const static auto default_state_size = 1*1024*1024*1024ll; const static auto default_state_guard_size = 128*1024*1024ll; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index f1e28bba78d..641b2d1e42d 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -187,6 +187,11 @@ namespace eosio { namespace chain { time_point fork_db_head_block_time()const; account_name fork_db_head_block_producer()const; + uint32_t fork_db_pending_head_block_num()const; + block_id_type fork_db_pending_head_block_id()const; + time_point fork_db_pending_head_block_time()const; + account_name fork_db_pending_head_block_producer()const; + time_point pending_block_time()const; account_name pending_block_producer()const; public_key_type pending_block_signing_key()const; diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 2ac957f4a65..8e4d9176431 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -22,54 +22,70 @@ namespace eosio { namespace chain { class fork_database { public: - fork_database( const fc::path& data_dir ); + explicit fork_database( const fc::path& data_dir ); ~fork_database(); void close(); - block_state_ptr get_block(const block_id_type& id)const; - block_state_ptr get_block_in_current_chain_by_num( uint32_t n )const; -// vector get_blocks_by_number(uint32_t n)const; + block_header_state_ptr get_block_header( const block_id_type& id )const; + block_state_ptr get_block( const block_id_type& id )const; /** - * Provides a "valid" blockstate upon which other forks may build. + * Purges any existing blocks from the fork database and resets the root block_header_state to the provided value. + * The head will also be reset to point to the root. */ - void set( block_state_ptr s ); + void reset( const block_header_state& root_bhs ); - /** this method will attempt to append the block to an existing - * block_state and will return a pointer to the new block state or - * throw on error. + /** + * Advance root block forward to some other block in the tree. */ - block_state_ptr add( signed_block_ptr b, bool skip_validate_signee ); - block_state_ptr add( const block_state_ptr& next_block, bool skip_validate_previous ); + void advance_root( const block_id_type& id ); + + /** + * Add block state to fork database. + * Must link to existing block in fork database or the root. + */ + void add( const block_state_ptr& next_block ); + void remove( const block_id_type& id ); + const block_state_ptr& root()const; const block_state_ptr& head()const; + block_state_ptr pending_head()const; /** - * Given two head blocks, return two branches of the fork graph that - * end with a common ancestor (same prior block) + * Returns the sequence of block states resulting from trimming the branch from the + * root block (exclusive) to the block with an id of `h` (inclusive) by removing any + * block states corresponding to block numbers greater than `trim_after_block_num`. + * + * The order of the sequence is in descending block number order. + * A block with an id of `h` must exist in the fork database otherwise this method will throw an exception. */ - pair< branch_type, branch_type > fetch_branch_from( const block_id_type& first, - const block_id_type& second )const; + branch_type fetch_branch( const block_id_type& h, uint32_t trim_after_block_num = std::numeric_limits::max() )const; /** - * If the block is invalid, it will be removed. If it is valid, then blocks older - * than the LIB are pruned after emitting irreversible signal. + * Returns the block state with a block number of `block_num` that is on the branch that + * contains a block with an id of`h`, or the empty shared pointer if no such block can be found. */ - void set_validity( const block_state_ptr& h, bool valid ); - void mark_in_current_chain( const block_state_ptr& h, bool in_current_chain ); - void prune( const block_state_ptr& h ); + block_state_ptr search_on_branch( const block_id_type& h, uint32_t block_num )const; /** - * This signal is emited when a block state becomes irreversible, once irreversible - * it is removed unless it is the head block. + * Given two head blocks, return two branches of the fork graph that + * end with a common ancestor (same prior block) */ - signal irreversible; + pair< branch_type, branch_type > fetch_branch_from( const block_id_type& first, + const block_id_type& second )const; + + + void mark_valid( const block_state_ptr& h ); + + static const uint32_t magic_number; + + static const uint32_t min_supported_version; + static const uint32_t max_supported_version; private: - //void set_bft_irreversible( block_id_type id ); unique_ptr my; }; diff --git a/libraries/chain/include/eosio/chain/generated_transaction_object.hpp b/libraries/chain/include/eosio/chain/generated_transaction_object.hpp index 24db926b4a8..7c3da995e65 100644 --- a/libraries/chain/include/eosio/chain/generated_transaction_object.hpp +++ b/libraries/chain/include/eosio/chain/generated_transaction_object.hpp @@ -3,6 +3,7 @@ * @copyright defined in eos/LICENSE */ #pragma once +#include #include #include @@ -116,4 +117,4 @@ namespace eosio { namespace chain { CHAINBASE_SET_INDEX_TYPE(eosio::chain::generated_transaction_object, eosio::chain::generated_transaction_multi_index) -FC_REFLECT(eosio::chain::generated_transaction_object, (trx_id)(sender)(sender_id)(payer)(delay_until)(expiration)(published)(packed_trx)) \ No newline at end of file +FC_REFLECT(eosio::chain::generated_transaction_object, (trx_id)(sender)(sender_id)(payer)(delay_until)(expiration)(published)(packed_trx)) diff --git a/libraries/chain/include/eosio/chain/transaction.hpp b/libraries/chain/include/eosio/chain/transaction.hpp index a8b53b98e0d..3bd836ec0ca 100644 --- a/libraries/chain/include/eosio/chain/transaction.hpp +++ b/libraries/chain/include/eosio/chain/transaction.hpp @@ -218,6 +218,7 @@ FC_REFLECT( eosio::chain::transaction_header, (expiration)(ref_block_num)(ref_bl FC_REFLECT_DERIVED( eosio::chain::transaction, (eosio::chain::transaction_header), (context_free_actions)(actions)(transaction_extensions) ) FC_REFLECT_DERIVED( eosio::chain::signed_transaction, (eosio::chain::transaction), (signatures)(context_free_data) ) FC_REFLECT_ENUM( eosio::chain::packed_transaction::compression_type, (none)(zlib)) +// @ignore unpacked_trx FC_REFLECT( eosio::chain::packed_transaction, (signatures)(compression)(packed_context_free_data)(packed_trx) ) FC_REFLECT_DERIVED( eosio::chain::deferred_transaction, (eosio::chain::signed_transaction), (sender_id)(sender)(payer)(execute_after) ) FC_REFLECT( eosio::chain::deferred_reference, (sender)(sender_id) ) diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index 21fbf216c43..8ee6827efe2 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -207,6 +207,14 @@ namespace eosio { namespace chain { using uint128_t = unsigned __int128; using bytes = vector; + struct sha256_less { + bool operator()( const fc::sha256& lhs, const fc::sha256& rhs ) const { + return + std::tie(lhs._hash[0], lhs._hash[1], lhs._hash[2], lhs._hash[3]) < + std::tie(rhs._hash[0], rhs._hash[1], rhs._hash[2], rhs._hash[3]); + } + }; + /** * Extentions are prefixed with type and are a buffer that can be diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 2053669c0d7..482b3c488f7 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -25,7 +25,7 @@ const flat_set& transaction_metadata::recover_keys( const chain void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id, fc::microseconds time_limit ) { - if( mtrx->signing_keys.valid() ) // already created + if( mtrx->signing_keys_future.valid() || mtrx->signing_keys.valid() ) // already created return; std::weak_ptr mtrx_wp = mtrx; diff --git a/libraries/fc b/libraries/fc index a6bbb25c3d3..d321bf498ba 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit a6bbb25c3d395b8ccc62314311822db89569eb9d +Subproject commit d321bf498ba8a10fc9ed6cee5636004413f7ff7b diff --git a/libraries/testing/CMakeLists.txt b/libraries/testing/CMakeLists.txt index eaf9bf87502..b03c85760d1 100644 --- a/libraries/testing/CMakeLists.txt +++ b/libraries/testing/CMakeLists.txt @@ -11,11 +11,9 @@ target_link_libraries( eosio_testing eosio_chain fc chainbase Logging IR WAST WA target_include_directories( eosio_testing PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include" - "${CMAKE_BINARY_DIR}/contracts" + "${CMAKE_BINARY_DIR}/unittests/include" ) -add_dependencies( eosio_testing eosio.bios ) - if(MSVC) set_source_files_properties( db_init.cpp db_block.cpp database.cpp block_log.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 311a8dc3685..fe492eb5fc9 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -3,11 +3,10 @@ #include #include #include - -#include -#include #include +#include + eosio::chain::asset core_from_string(const std::string& s) { return eosio::chain::asset::from_string(s + " " CORE_SYMBOL_NAME); } @@ -812,10 +811,8 @@ namespace eosio { namespace testing { } void base_tester::push_genesis_block() { - set_code(config::system_account_name, eosio_bios_wast); - - set_abi(config::system_account_name, eosio_bios_abi); - //produce_block(); + set_code(config::system_account_name, contracts::eosio_bios_wasm()); + set_abi(config::system_account_name, contracts::eosio_bios_abi().data()); } vector base_tester::get_producer_keys( const vector& producer_names )const { diff --git a/plugins/bnet_plugin/bnet_plugin.cpp b/plugins/bnet_plugin/bnet_plugin.cpp index b25631cbabc..a4cd0ebb6a7 100644 --- a/plugins/bnet_plugin/bnet_plugin.cpp +++ b/plugins/bnet_plugin/bnet_plugin.cpp @@ -128,6 +128,7 @@ struct hello { uint32_t last_irr_block_num = 0; vector pending_block_ids; }; +// @swap user, password FC_REFLECT( hello, (peer_id)(network_version)(user)(password)(agent)(protocol_version)(chain_id)(request_transactions)(last_irr_block_num)(pending_block_ids) ) struct hello_extension_irreversible_only {}; @@ -289,7 +290,6 @@ namespace eosio { boost::asio::io_service& _ios; unique_ptr> _ws; boost::asio::strand< boost::asio::io_context::executor_type> _strand; - boost::asio::io_service& _app_ios; methods::get_block_by_number::method_type& _get_block_by_number; @@ -319,7 +319,6 @@ namespace eosio { _ios(socket.get_io_service()), _ws( new ws::stream(move(socket)) ), _strand(_ws->get_executor() ), - _app_ios( app().get_io_service() ), _get_block_by_number( app().get_method() ) { _session_num = next_session_id(); @@ -338,7 +337,6 @@ namespace eosio { _ios(ioc), _ws( new ws::stream(ioc) ), _strand( _ws->get_executor() ), - _app_ios( app().get_io_service() ), _get_block_by_number( app().get_method() ) { _session_num = next_session_id(); @@ -569,10 +567,10 @@ namespace eosio { template void async_get_pending_block_ids( L&& callback ) { /// send peer my head block status which is read from chain plugin - _app_ios.post( [self = shared_from_this(),callback]{ + app().post(priority::low, [self = shared_from_this(),callback]{ auto& control = app().get_plugin().chain(); auto lib = control.last_irreversible_block_num(); - auto head = control.fork_db_head_block_id(); + auto head = control.fork_db_pending_head_block_id(); auto head_num = block_header::num_from_id(head); @@ -594,7 +592,7 @@ namespace eosio { template void async_get_block_num( uint32_t blocknum, L&& callback ) { - _app_ios.post( [self = shared_from_this(), blocknum, callback]{ + app().post(priority::low, [self = shared_from_this(), blocknum, callback]{ auto& control = app().get_plugin().chain(); signed_block_ptr sblockptr; try { @@ -918,9 +916,9 @@ namespace eosio { * the connection from being closed. */ void wait_on_app() { - app().get_io_service().post( - boost::asio::bind_executor( _strand, [self=shared_from_this()]{ self->do_read(); } ) - ); + app().post( priority::medium, [self = shared_from_this()]() { + app().get_io_service().post( boost::asio::bind_executor( self->_strand, [self] { self->do_read(); } ) ); + } ); } void on_message( const bnet_message& msg, fc::datastream& ds ) { @@ -1004,7 +1002,7 @@ namespace eosio { auto id = b->id(); mark_block_status( id, true, true ); - app().get_channel().publish(b); + app().get_channel().publish(priority::high, b); mark_block_transactions_known_by_peer( b ); } @@ -1153,7 +1151,7 @@ namespace eosio { channels::accepted_transaction::channel_type::handle _on_appled_trx_handle; void async_add_session( std::weak_ptr wp ) { - app().get_io_service().post( [wp,this]{ + app().post(priority::low, [wp,this]{ if( auto l = wp.lock() ) { _sessions[l.get()] = wp; } @@ -1161,7 +1159,6 @@ namespace eosio { } void on_session_close( const session* s ) { - verify_strand_in_this_thread(app().get_io_service().get_executor(), __func__, __LINE__); auto itr = _sessions.find(s); if( _sessions.end() != itr ) _sessions.erase(itr); @@ -1169,7 +1166,7 @@ namespace eosio { template void for_each_session( Call callback ) { - app().get_io_service().post([this, callback = callback] { + app().post(priority::low, [this, callback = callback] { for (const auto& item : _sessions) { if (auto ses = item.second.lock()) { ses->_ios.post(boost::asio::bind_executor( @@ -1225,7 +1222,6 @@ namespace eosio { }; void on_reconnect_peers() { - verify_strand_in_this_thread(app().get_io_service().get_executor(), __func__, __LINE__); for( const auto& peer : _connect_to_peers ) { bool found = false; for( const auto& con : _sessions ) { @@ -1253,10 +1249,10 @@ namespace eosio { /// add some random delay so that all my peers don't attempt to reconnect to me /// at the same time after shutting down.. _timer->expires_from_now( boost::posix_time::microseconds( 1000000*(10+rand()%5) ) ); - _timer->async_wait([=](const boost::system::error_code& ec) { + _timer->async_wait(app().get_priority_queue().wrap(priority::low, [=](const boost::system::error_code& ec) { if( ec ) { return; } on_reconnect_peers(); - }); + })); } }; @@ -1448,7 +1444,7 @@ namespace eosio { session::~session() { wlog( "close session ${n}",("n",_session_num) ); std::weak_ptr netp = _net_plugin; - _app_ios.post( [netp,ses=this]{ + app().post(priority::low, [netp,ses=this]{ if( auto net = netp.lock() ) net->on_session_close(ses); }); @@ -1475,7 +1471,7 @@ namespace eosio { } void session::check_for_redundant_connection() { - app().get_io_service().post( [self=shared_from_this()]{ + app().post(priority::low, [self=shared_from_this()]{ self->_net_plugin->for_each_session( [self]( auto ses ){ if( ses != self && ses->_remote_peer_id == self->_remote_peer_id ) { self->do_goodbye( "redundant connection" ); @@ -1557,6 +1553,6 @@ namespace eosio { auto ptr = std::make_shared(p); - app().get_channel().publish(ptr); + app().get_channel().publish(priority::low, ptr); } } /// namespace eosio diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 8b26838e44d..fdfd7cf83ea 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -197,6 +197,8 @@ class chain_plugin_impl { chain_plugin::chain_plugin() :my(new chain_plugin_impl()) { + app().register_config_type(); + app().register_config_type(); } chain_plugin::~chain_plugin(){} @@ -235,12 +237,12 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip ("sender-bypass-whiteblacklist", boost::program_options::value>()->composing()->multitoken(), "Deferred transactions sent by accounts in this list do not have any of the subjective whitelist/blacklist checks applied to them (may specify multiple times)") ("read-mode", boost::program_options::value()->default_value(eosio::chain::db_read_mode::SPECULATIVE), - "Database read mode (\"speculative\", \"head\", or \"read-only\").\n"// or \"irreversible\").\n" + "Database read mode (\"speculative\", \"head\", \"read-only\", \"irreversible\").\n" "In \"speculative\" mode database contains changes done up to the head block plus changes made by transactions not yet included to the blockchain.\n" "In \"head\" mode database contains changes done up to the current head block.\n" - "In \"read-only\" mode database contains incoming block changes but no speculative transaction processing.\n" + "In \"read-only\" mode database contains changes done up to the current head block and transactions cannot be pushed to the chain API.\n" + "In \"irreversible\" mode database contains changes done up to the last irreversible block and transactions cannot be pushed to the chain API.\n" ) - //"In \"irreversible\" mode database contains changes done up the current irreversible block.\n") ("validation-mode", boost::program_options::value()->default_value(eosio::chain::validation_mode::FULL), "Chain validation mode (\"full\" or \"light\").\n" "In \"full\" mode all incoming blocks will be fully validated.\n" @@ -627,7 +629,6 @@ void chain_plugin::plugin_initialize(const variables_map& options) { if ( options.count("read-mode") ) { my->chain_config->read_mode = options.at("read-mode").as(); - EOS_ASSERT( my->chain_config->read_mode != db_read_mode::IRREVERSIBLE, plugin_config_exception, "irreversible mode not currently supported." ); } if ( options.count("validation-mode") ) { @@ -668,30 +669,30 @@ void chain_plugin::plugin_initialize(const variables_map& options) { ); } - my->pre_accepted_block_channel.publish(blk); + my->pre_accepted_block_channel.publish(priority::medium, blk); }); my->accepted_block_header_connection = my->chain->accepted_block_header.connect( [this]( const block_state_ptr& blk ) { - my->accepted_block_header_channel.publish( blk ); + my->accepted_block_header_channel.publish( priority::medium, blk ); } ); my->accepted_block_connection = my->chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { - my->accepted_block_channel.publish( blk ); + my->accepted_block_channel.publish( priority::high, blk ); } ); my->irreversible_block_connection = my->chain->irreversible_block.connect( [this]( const block_state_ptr& blk ) { - my->irreversible_block_channel.publish( blk ); + my->irreversible_block_channel.publish( priority::low, blk ); } ); my->accepted_transaction_connection = my->chain->accepted_transaction.connect( [this]( const transaction_metadata_ptr& meta ) { - my->accepted_transaction_channel.publish( meta ); + my->accepted_transaction_channel.publish( priority::low, meta ); } ); my->applied_transaction_connection = my->chain->applied_transaction.connect( [this]( const transaction_trace_ptr& trace ) { - my->applied_transaction_channel.publish( trace ); + my->applied_transaction_channel.publish( priority::low, trace ); } ); my->chain->add_indices(); @@ -1022,12 +1023,12 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params return { itoh(static_cast(app().version())), db.get_chain_id(), - db.fork_db_head_block_num(), + db.head_block_num(), db.last_irreversible_block_num(), db.last_irreversible_block_id(), - db.fork_db_head_block_id(), - db.fork_db_head_block_time(), - db.fork_db_head_block_producer(), + db.head_block_id(), + db.head_block_time(), + db.head_block_producer(), rm.get_virtual_block_cpu_limit(), rm.get_virtual_block_net_limit(), rm.get_block_cpu_limit(), @@ -1035,6 +1036,8 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params //std::bitset<64>(db.get_dynamic_global_properties().recent_slots_filled).to_string(), //__builtin_popcountll(db.get_dynamic_global_properties().recent_slots_filled) / 64.0, app().version_string(), + db.fork_db_pending_head_block_num(), + db.fork_db_pending_head_block_id() }; } @@ -1632,7 +1635,7 @@ read_only::get_code_results read_only::get_code( const get_code_params& params ) if( accnt.code.size() ) { result.wasm = string(accnt.code.begin(), accnt.code.end()); - result.code_hash = fc::sha256::hash( accnt.code.data(), accnt.code.size() ); + result.code_hash = accnt.code_version; } abi_def abi; @@ -1650,7 +1653,7 @@ read_only::get_code_hash_results read_only::get_code_hash( const get_code_hash_p const auto& accnt = d.get( params.account_name ); if( accnt.code.size() ) { - result.code_hash = fc::sha256::hash( accnt.code.data(), accnt.code.size() ); + result.code_hash = accnt.code_version; } return result; @@ -1675,7 +1678,7 @@ read_only::get_raw_abi_results read_only::get_raw_abi( const get_raw_abi_params& const auto& d = db.db(); const auto& accnt = d.get(params.account_name); result.abi_hash = fc::sha256::hash( accnt.abi.data(), accnt.abi.size() ); - result.code_hash = fc::sha256::hash( accnt.code.data(), accnt.code.size() ); + result.code_hash = accnt.code_version; if( !params.abi_hash || *params.abi_hash != result.abi_hash ) result.abi = blob{{accnt.abi.begin(), accnt.abi.end()}}; diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 4a41d99455c..9fad2e2c7b6 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -104,6 +104,8 @@ class read_only { //string recent_slots; //double participation_rate = 0; optional server_version_string; + optional fork_db_head_block_num = 0; + optional fork_db_head_block_id; }; get_info_results get_info(const get_info_params&) const; @@ -705,7 +707,7 @@ class chain_plugin : public plugin { FC_REFLECT( eosio::chain_apis::permission, (perm_name)(parent)(required_auth) ) FC_REFLECT(eosio::chain_apis::empty, ) FC_REFLECT(eosio::chain_apis::read_only::get_info_results, -(server_version)(chain_id)(head_block_num)(last_irreversible_block_num)(last_irreversible_block_id)(head_block_id)(head_block_time)(head_block_producer)(virtual_block_cpu_limit)(virtual_block_net_limit)(block_cpu_limit)(block_net_limit)(server_version_string) ) +(server_version)(chain_id)(head_block_num)(last_irreversible_block_num)(last_irreversible_block_id)(head_block_id)(head_block_time)(head_block_producer)(virtual_block_cpu_limit)(virtual_block_net_limit)(block_cpu_limit)(block_net_limit)(server_version_string)(fork_db_head_block_num)(fork_db_head_block_id) ) FC_REFLECT(eosio::chain_apis::read_only::get_block_params, (block_num_or_id)) FC_REFLECT(eosio::chain_apis::read_only::get_block_header_state_params, (block_num_or_id)) @@ -735,6 +737,7 @@ FC_REFLECT( eosio::chain_apis::read_only::get_account_results, (account_name)(head_block_num)(head_block_time)(privileged)(last_code_update)(created) (core_liquid_balance)(ram_quota)(net_weight)(cpu_weight)(net_limit)(cpu_limit)(ram_usage)(permissions) (total_resources)(self_delegated_bandwidth)(refund_request)(voter_info) ) +// @swap code_hash FC_REFLECT( eosio::chain_apis::read_only::get_code_results, (account_name)(code_hash)(wast)(wasm)(abi) ) FC_REFLECT( eosio::chain_apis::read_only::get_code_hash_results, (account_name)(code_hash) ) FC_REFLECT( eosio::chain_apis::read_only::get_abi_results, (account_name)(abi) ) diff --git a/plugins/http_plugin/http_plugin.cpp b/plugins/http_plugin/http_plugin.cpp index c808c5bb99f..ffa6d8fb823 100644 --- a/plugins/http_plugin/http_plugin.cpp +++ b/plugins/http_plugin/http_plugin.cpp @@ -150,10 +150,6 @@ namespace eosio { bool validate_host; set valid_hosts; - string unix_socket_path_option_name = "unix-socket-path"; - string http_server_address_option_name = "http-server-address"; - string https_server_address_option_name = "https-server-address"; - bool host_port_is_valid( const std::string& header_host_port, const string& endpoint_local_host_port ) { return !validate_host || header_host_port == endpoint_local_host_port || valid_hosts.find(header_host_port) != valid_hosts.end(); } @@ -286,10 +282,16 @@ namespace eosio { auto handler_itr = url_handlers.find( resource ); if( handler_itr != url_handlers.end()) { con->defer_http_response(); - handler_itr->second( resource, body, [con]( auto code, auto&& body ) { - con->set_body( std::move( body )); - con->set_status( websocketpp::http::status_code::value( code )); - con->send_http_response(); + app().post( appbase::priority::low, [handler_itr, resource, body, con]() { + try { + handler_itr->second( resource, body, [con]( auto code, auto&& body ) { + con->set_body( std::move( body ) ); + con->set_status( websocketpp::http::status_code::value( code ) ); + con->send_http_response(); + } ); + } catch( ... ) { + handle_exception( con ); + } } ); } else { @@ -328,14 +330,6 @@ namespace eosio { valid_hosts.emplace(host + ":" + port); valid_hosts.emplace(host + ":" + resolved_port_str); } - - void mangle_option_names() { - if(current_http_plugin_defaults.address_config_prefix.empty()) - return; - unix_socket_path_option_name.insert(0, current_http_plugin_defaults.address_config_prefix+"-"); - http_server_address_option_name.insert(0, current_http_plugin_defaults.address_config_prefix+"-"); - https_server_address_option_name.insert(0, current_http_plugin_defaults.address_config_prefix+"-"); - } }; template<> @@ -347,23 +341,22 @@ namespace eosio { http_plugin::~http_plugin(){} void http_plugin::set_program_options(options_description&, options_description& cfg) { - my->mangle_option_names(); if(current_http_plugin_defaults.default_unix_socket_path.length()) cfg.add_options() - (my->unix_socket_path_option_name.c_str(), bpo::value()->default_value(current_http_plugin_defaults.default_unix_socket_path), + ("unix-socket-path", bpo::value()->default_value(current_http_plugin_defaults.default_unix_socket_path), "The filename (relative to data-dir) to create a unix socket for HTTP RPC; set blank to disable."); if(current_http_plugin_defaults.default_http_port) cfg.add_options() - (my->http_server_address_option_name.c_str(), bpo::value()->default_value("127.0.0.1:" + std::to_string(current_http_plugin_defaults.default_http_port)), + ("http-server-address", bpo::value()->default_value("127.0.0.1:" + std::to_string(current_http_plugin_defaults.default_http_port)), "The local IP and port to listen for incoming http connections; set blank to disable."); else cfg.add_options() - (my->http_server_address_option_name.c_str(), bpo::value(), + ("http-server-address", bpo::value(), "The local IP and port to listen for incoming http connections; leave blank to disable."); cfg.add_options() - (my->https_server_address_option_name.c_str(), bpo::value(), + ("https-server-address", bpo::value(), "The local IP and port to listen for incoming https connections; leave blank to disable.") ("https-certificate-chain-file", bpo::value(), @@ -412,8 +405,8 @@ namespace eosio { } tcp::resolver resolver( app().get_io_service()); - if( options.count( my->http_server_address_option_name ) && options.at( my->http_server_address_option_name ).as().length()) { - string lipstr = options.at( my->http_server_address_option_name ).as(); + if( options.count( "http-server-address" ) && options.at( "http-server-address" ).as().length()) { + string lipstr = options.at( "http-server-address" ).as(); string host = lipstr.substr( 0, lipstr.find( ':' )); string port = lipstr.substr( host.size() + 1, lipstr.size()); tcp::resolver::query query( tcp::v4(), host.c_str(), port.c_str()); @@ -431,14 +424,14 @@ namespace eosio { } } - if( options.count( my->unix_socket_path_option_name ) && !options.at( my->unix_socket_path_option_name ).as().empty()) { - boost::filesystem::path sock_path = options.at(my->unix_socket_path_option_name).as(); + if( options.count( "unix-socket-path" ) && !options.at( "unix-socket-path" ).as().empty()) { + boost::filesystem::path sock_path = options.at("unix-socket-path").as(); if (sock_path.is_relative()) sock_path = app().data_dir() / sock_path; my->unix_endpoint = asio::local::stream_protocol::endpoint(sock_path.string()); } - if( options.count( my->https_server_address_option_name ) && options.at( my->https_server_address_option_name ).as().length()) { + if( options.count( "https-server-address" ) && options.at( "https-server-address" ).as().length()) { if( !options.count( "https-certificate-chain-file" ) || options.at( "https-certificate-chain-file" ).as().empty()) { elog( "https-certificate-chain-file is required for HTTPS" ); @@ -450,7 +443,7 @@ namespace eosio { return; } - string lipstr = options.at( my->https_server_address_option_name ).as(); + string lipstr = options.at( "https-server-address" ).as(); string host = lipstr.substr( 0, lipstr.find( ':' )); string port = lipstr.substr( host.size() + 1, lipstr.size()); tcp::resolver::query query( tcp::v4(), host.c_str(), port.c_str()); @@ -541,6 +534,19 @@ namespace eosio { throw; } } + + add_api({{ + std::string("/v1/node/get_supported_apis"), + [&](string, string body, url_response_callback cb) mutable { + try { + if (body.empty()) body = "{}"; + auto result = (*this).get_supported_apis(); + cb(200, fc::json::to_string(result)); + } catch (...) { + handle_exception("node", "get_supported_apis", body, cb); + } + } + }}); } void http_plugin::plugin_shutdown() { @@ -554,7 +560,7 @@ namespace eosio { void http_plugin::add_handler(const string& url, const url_handler& handler) { ilog( "add api url: ${c}", ("c",url) ); - app().get_io_service().post([=](){ + app().post(priority::low, [=](){ my->url_handlers.insert(std::make_pair(url,handler)); }); } @@ -615,4 +621,14 @@ namespace eosio { return verbose_http_errors; } + http_plugin::get_supported_apis_result http_plugin::get_supported_apis()const { + get_supported_apis_result result; + + for (const auto& handler : my->url_handlers) { + if (handler.first != "/v1/node/get_supported_apis") + result.apis.emplace_back(handler.first); + } + + return result; + } } diff --git a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp index c7bc1ebb2b6..f77387e83f0 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp @@ -41,9 +41,6 @@ namespace eosio { using api_description = std::map; struct http_plugin_defaults { - //If not empty, this string is prepended on to the various configuration - // items for setting listen addresses - string address_config_prefix; //If empty, unix socket support will be completely disabled. If not empty, // unix socket support is enabled with the given default path (treated relative // to the datadir) @@ -97,6 +94,12 @@ namespace eosio { bool verbose_errors()const; + struct get_supported_apis_result { + vector apis; + }; + + get_supported_apis_result get_supported_apis()const; + private: std::unique_ptr my; }; @@ -152,3 +155,4 @@ namespace eosio { FC_REFLECT(eosio::error_results::error_info::error_detail, (message)(file)(line_number)(method)) FC_REFLECT(eosio::error_results::error_info, (code)(name)(what)(details)) FC_REFLECT(eosio::error_results, (code)(message)(error)) +FC_REFLECT(eosio::http_plugin::get_supported_apis_result, (apis)) diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 70327c3d96b..ee22c65c7cc 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -652,6 +652,18 @@ optional mongo_db_plugin_impl::get_abi_serializer( account_name } } } + // mongo does not like empty json keys + // make abi_serializer use empty_name instead of "" for the action data + for( auto& s : abi.structs ) { + if( s.name.empty() ) { + s.name = "empty_struct_name"; + } + for( auto& f : s.fields ) { + if( f.name.empty() ) { + f.name = "empty_field_name"; + } + } + } abis.set_abi( abi, abi_serializer_max_time ); entry.serializer.emplace( std::move( abis ) ); abi_cache_index.insert( entry ); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 0c00495c48d..3204793b701 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -45,6 +45,7 @@ namespace eosio { using fc::time_point; using fc::time_point_sec; using eosio::chain::transaction_id_type; + using eosio::chain::sha256_less; class connection; @@ -66,14 +67,6 @@ namespace eosio { struct by_expiry; struct by_block_num; - struct sha256_less { - bool operator()( const sha256& lhs, const sha256& rhs ) const { - return - std::tie(lhs._hash[0], lhs._hash[1], lhs._hash[2], lhs._hash[3]) < - std::tie(rhs._hash[0], rhs._hash[1], rhs._hash[2], rhs._hash[3]); - } - }; - typedef multi_index_container< node_transaction_state, indexed_by< @@ -165,7 +158,7 @@ namespace eosio { size_t count_open_sockets() const; template - void send_all( const std::shared_ptr>& send_buffer, VerifierFunc verify ); + void send_transaction_to_all( const std::shared_ptr>& send_buffer, VerifierFunc verify ); void accepted_block(const block_state_ptr&); void transaction_ack(const std::pair&); @@ -341,17 +334,8 @@ namespace eosio { struct peer_block_state { block_id_type id; uint32_t block_num; - bool is_known; - bool is_noticed; - time_point requested_time; }; - struct update_request_time { - void operator() (struct eosio::peer_block_state &bs) { - bs.requested_time = time_point::now(); - } - } set_request_time; - typedef multi_index_container< eosio::peer_block_state, indexed_by< @@ -361,13 +345,6 @@ namespace eosio { > peer_block_state_index; - struct update_known_by_peer { - void operator() (eosio::peer_block_state& bs) { - bs.is_known = true; - } - } set_is_known; - - struct update_block_num { uint32_t new_bnum; update_block_num(uint32_t bnum) : new_bnum(bnum) {} @@ -377,9 +354,6 @@ namespace eosio { void operator() (transaction_state& ts) { ts.block_num = new_bnum; } - void operator() (peer_block_state& pbs) { - pbs.block_num = new_bnum; - } }; /** @@ -502,7 +476,8 @@ namespace eosio { void enqueue( const net_message &msg, bool trigger_send = true ); void enqueue_block( const signed_block_ptr& sb, bool trigger_send = true ); - void enqueue_buffer( const std::shared_ptr>& send_buffer, bool trigger_send, go_away_reason close_after_send ); + void enqueue_buffer( const std::shared_ptr>& send_buffer, + bool trigger_send, int priority, go_away_reason close_after_send ); void cancel_sync(go_away_reason); void flush_queues(); bool enqueue_sync_block(); @@ -516,8 +491,9 @@ namespace eosio { void queue_write(const std::shared_ptr>& buff, bool trigger_send, + int priority, std::function callback); - void do_queue_write(); + void do_queue_write(int priority); /** \brief Process the next message from the pending message buffer * @@ -530,7 +506,7 @@ namespace eosio { */ bool process_next_message(net_plugin_impl& impl, uint32_t message_length); - bool add_peer_block(const peer_block_state &pbs); + void add_peer_block(const peer_block_state& pbs); fc::optional _logger_variant; const fc::variant_object& get_logger_variant() { @@ -748,7 +724,7 @@ namespace eosio { for(auto tx = my_impl->local_txns.begin(); tx != my_impl->local_txns.end(); ++tx ){ const bool found = known_ids.find( tx->id ) != known_ids.cend(); if( !found ) { - queue_write( tx->serialized_txn, true, []( boost::system::error_code ec, std::size_t ) {} ); + queue_write( tx->serialized_txn, true, priority::low, []( boost::system::error_code ec, std::size_t ) {} ); } } } @@ -757,14 +733,14 @@ namespace eosio { for(const auto& t : ids) { auto tx = my_impl->local_txns.get().find(t); if( tx != my_impl->local_txns.end() ) { - queue_write( tx->serialized_txn, true, []( boost::system::error_code ec, std::size_t ) {} ); + queue_write( tx->serialized_txn, true, priority::low, []( boost::system::error_code ec, std::size_t ) {} ); } } } void connection::blk_send_branch() { controller& cc = my_impl->chain_plug->chain(); - uint32_t head_num = cc.fork_db_head_block_num(); + uint32_t head_num = cc.fork_db_pending_head_block_num(); notice_message note; note.known_blocks.mode = normal; note.known_blocks.pending = 0; @@ -791,7 +767,7 @@ namespace eosio { } else { lib_id = cc.last_irreversible_block_id(); } - head_id = cc.fork_db_head_block_id(); + head_id = cc.fork_db_pending_head_block_id(); } catch (const assert_exception& ex) { elog( "unable to retrieve block info: ${n} for ${p}",("n",ex.to_string())("p",peer_name())); @@ -905,13 +881,14 @@ namespace eosio { void connection::queue_write(const std::shared_ptr>& buff, bool trigger_send, + int priority, std::function callback) { write_queue.push_back({buff, callback}); if(out_queue.empty() && trigger_send) - do_queue_write(); + do_queue_write( priority ); } - void connection::do_queue_write() { + void connection::do_queue_write(int priority) { if(write_queue.empty() || !out_queue.empty()) return; connection_wptr c(shared_from_this()); @@ -927,7 +904,8 @@ namespace eosio { out_queue.push_back(m); write_queue.pop_front(); } - boost::asio::async_write(*socket, bufs, [c](boost::system::error_code ec, std::size_t w) { + boost::asio::async_write(*socket, bufs, + app().get_priority_queue().wrap(priority, [c, priority](boost::system::error_code ec, std::size_t w) { try { auto conn = c.lock(); if(!conn) @@ -952,7 +930,7 @@ namespace eosio { conn->out_queue.pop_front(); } conn->enqueue_sync_block(); - conn->do_queue_write(); + conn->do_queue_write( priority ); } catch(const std::exception &ex) { auto conn = c.lock(); @@ -969,7 +947,7 @@ namespace eosio { string pname = conn ? conn->peer_name() : "no connection name"; elog("Exception in do_queue_write to ${p}", ("p",pname) ); } - }); + })); } void connection::cancel_sync(go_away_reason reason) { @@ -1028,10 +1006,10 @@ namespace eosio { ds.write( header, header_size ); fc::raw::pack( ds, m ); - enqueue_buffer( send_buffer, trigger_send, close_after_send ); + enqueue_buffer( send_buffer, trigger_send, priority::low, close_after_send ); } - void connection::enqueue_block( const signed_block_ptr& sb, bool trigger_send ) { + static std::shared_ptr> create_send_buffer( const signed_block_ptr& sb ) { // this implementation is to avoid copy of signed_block to net_message int which = 7; // matches which of net_message for signed_block @@ -1048,12 +1026,18 @@ namespace eosio { fc::raw::pack( ds, unsigned_int( which )); fc::raw::pack( ds, *sb ); - enqueue_buffer( send_buffer, trigger_send, no_reason ); + return send_buffer; } - void connection::enqueue_buffer( const std::shared_ptr>& send_buffer, bool trigger_send, go_away_reason close_after_send ) { + void connection::enqueue_block( const signed_block_ptr& sb, bool trigger_send ) { + enqueue_buffer( create_send_buffer( sb ), trigger_send, priority::low, no_reason ); + } + + void connection::enqueue_buffer( const std::shared_ptr>& send_buffer, + bool trigger_send, int priority, go_away_reason close_after_send ) + { connection_wptr weak_this = shared_from_this(); - queue_write(send_buffer,trigger_send, + queue_write(send_buffer,trigger_send, priority, [weak_this, close_after_send](boost::system::error_code ec, std::size_t ) { connection_ptr conn = weak_this.lock(); if (conn) { @@ -1076,7 +1060,7 @@ namespace eosio { void connection::sync_wait() { response_expected->expires_from_now( my_impl->resp_expected_period); connection_wptr c(shared_from_this()); - response_expected->async_wait( [c]( boost::system::error_code ec){ + response_expected->async_wait( app().get_priority_queue().wrap(priority::low, [c]( boost::system::error_code ec){ connection_ptr conn = c.lock(); if (!conn) { // connection was destroyed before this lambda was delivered @@ -1084,13 +1068,13 @@ namespace eosio { } conn->sync_timeout(ec); - } ); + } ) ); } void connection::fetch_wait() { response_expected->expires_from_now( my_impl->resp_expected_period); connection_wptr c(shared_from_this()); - response_expected->async_wait( [c]( boost::system::error_code ec){ + response_expected->async_wait( app().get_priority_queue().wrap(priority::low, [c]( boost::system::error_code ec){ connection_ptr conn = c.lock(); if (!conn) { // connection was destroyed before this lambda was delivered @@ -1098,7 +1082,7 @@ namespace eosio { } conn->fetch_timeout(ec); - } ); + } ) ); } void connection::sync_timeout( boost::system::error_code ec ) { @@ -1165,22 +1149,17 @@ namespace eosio { return true; } - bool connection::add_peer_block(const peer_block_state &entry) { + void connection::add_peer_block(const peer_block_state& entry) { auto bptr = blk_state.get().find(entry.id); bool added = (bptr == blk_state.end()); if (added){ blk_state.insert(entry); + } else { + blk_state.modify(bptr, [&entry](auto& e){ + e.id = entry.id; + e.block_num = entry.block_num; + }); } - else { - blk_state.modify(bptr,set_is_known); - if (entry.block_num == 0) { - blk_state.modify(bptr,update_block_num(entry.block_num)); - } - else { - blk_state.modify(bptr,set_request_time); - } - } - return added; } //----------------------------------------------------------- @@ -1219,7 +1198,7 @@ namespace eosio { bool fhset = c->fork_head != block_id_type(); fc_dlog(logger, "fork_head_num = ${fn} fork_head set = ${s}", ("fn", c->fork_head_num)("s", fhset)); - return c->fork_head != block_id_type() && c->fork_head_num < chain_plug->chain().fork_db_head_block_num(); + return c->fork_head != block_id_type() && c->fork_head_num < chain_plug->chain().fork_db_pending_head_block_num(); } return state != in_sync; } @@ -1240,14 +1219,14 @@ namespace eosio { bool sync_manager::sync_required() { fc_dlog(logger, "last req = ${req}, last recv = ${recv} known = ${known} our head = ${head}", - ("req",sync_last_requested_num)("recv",sync_next_expected_num)("known",sync_known_lib_num)("head",chain_plug->chain().fork_db_head_block_num())); + ("req",sync_last_requested_num)("recv",sync_next_expected_num)("known",sync_known_lib_num)("head",chain_plug->chain().fork_db_pending_head_block_num())); return( sync_last_requested_num < sync_known_lib_num || - chain_plug->chain().fork_db_head_block_num() < sync_last_requested_num ); + chain_plug->chain().fork_db_pending_head_block_num() < sync_last_requested_num ); } void sync_manager::request_next_chunk( const connection_ptr& conn ) { - uint32_t head_block = chain_plug->chain().fork_db_head_block_num(); + uint32_t head_block = chain_plug->chain().fork_db_pending_head_block_num(); if (head_block < sync_last_requested_num && source && source->current()) { fc_ilog(logger, "ignoring request, head is ${h} last req = ${r} source is ${p}", @@ -1345,7 +1324,7 @@ namespace eosio { if (!sync_required()) { uint32_t bnum = chain_plug->chain().last_irreversible_block_num(); - uint32_t hnum = chain_plug->chain().fork_db_head_block_num(); + uint32_t hnum = chain_plug->chain().fork_db_pending_head_block_num(); fc_dlog( logger, "We are already caught up, my irr = ${b}, head = ${h}, target = ${t}", ("b",bnum)("h",hnum)("t",target)); return; @@ -1387,13 +1366,13 @@ namespace eosio { // 1. my head block num < peer lib - start sync locally // 2. my lib > peer head num - send an last_irr_catch_up notice if not the first generation // - // 3 my head block num <= peer head block num - update sync state and send a catchup request - // 4 my head block num > peer block num send a notice catchup if this is not the first generation + // 3 my head block num < peer head block num - update sync state and send a catchup request + // 4 my head block num >= peer block num send a notice catchup if this is not the first generation // //----------------------------- - uint32_t head = cc.fork_db_head_block_num(); - block_id_type head_id = cc.fork_db_head_block_id(); + uint32_t head = cc.fork_db_pending_head_block_num(); + block_id_type head_id = cc.fork_db_pending_head_block_id(); if (head_id == msg.head_id) { fc_dlog(logger, "sync check state 0"); // notify peer of our pending transactions @@ -1426,7 +1405,7 @@ namespace eosio { return; } - if (head <= msg.head_num ) { + if (head < msg.head_num ) { fc_dlog(logger, "sync check state 3"); verify_catchup(c, msg.head_num, msg.head_id); return; @@ -1556,11 +1535,10 @@ namespace eosio { } received_blocks.erase(range.first, range.second); - block_id_type bid = bs->id; uint32_t bnum = bs->block_num; - peer_block_state pbstate = {bid, bnum, false, true, time_point()}; + peer_block_state pbstate{bs->id, bnum}; - pbstate.is_known = true; + std::shared_ptr> send_buffer; for( auto& cp : my_impl->connections ) { if( skips.find( cp ) != skips.end() || !cp->current() ) { continue; @@ -1569,7 +1547,10 @@ namespace eosio { if( !has_block ) { fc_dlog(logger, "bcast block ${b} to ${p}", ("b", bnum)("p", cp->peer_name())); cp->add_peer_block( pbstate ); - cp->enqueue_block( bs->block ); + if( !send_buffer ) { + send_buffer = create_send_buffer( bs->block ); + } + cp->enqueue_buffer( send_buffer, true, priority::high, no_reason ); } } @@ -1584,7 +1565,6 @@ namespace eosio { c->last_req->req_blocks.ids.back() == id) { c->last_req.reset(); } - c->add_peer_block({id, bnum, false,true,time_point()}); fc_dlog(logger, "canceling wait on ${p}", ("p",c->peer_name())); c->cancel_wait(); @@ -1633,7 +1613,7 @@ namespace eosio { node_transaction_state nts = {id, trx_expiration, 0, buff}; my_impl->local_txns.insert(std::move(nts)); - my_impl->send_all( buff, [&id, &skips, trx_expiration](const connection_ptr& c) -> bool { + my_impl->send_transaction_to_all( buff, [&id, &skips, trx_expiration](const connection_ptr& c) -> bool { if( skips.find(c) != skips.end() || c->syncing ) { return false; } @@ -1687,11 +1667,11 @@ namespace eosio { controller& cc = my_impl->chain_plug->chain(); for( const auto& blkid : msg.known_blocks.ids) { signed_block_ptr b; - peer_block_state entry = {blkid,0,true,true,fc::time_point()}; try { b = cc.fetch_block_by_id(blkid); - if(b) - entry.block_num = b->block_num(); + if(b) { + c->add_peer_block({blkid, b->block_num()}); + } } catch (const assert_exception &ex) { ilog( "caught assert on fetch_block_by_id, ${ex}",("ex",ex.what())); // keep going, client can ask another peer @@ -1701,9 +1681,7 @@ namespace eosio { if (!b) { send_req = true; req.req_blocks.ids.push_back( blkid ); - entry.requested_time = fc::time_point::now(); } - c->add_peer_block(entry); } } else if (msg.known_blocks.mode != none) { @@ -1749,7 +1727,7 @@ namespace eosio { } else { auto blk = conn->blk_state.get().find(bid); - sendit = blk != conn->blk_state.end() && blk->is_known; + sendit = blk != conn->blk_state.end(); } if (sendit) { conn->enqueue(*c->last_req); @@ -1797,6 +1775,7 @@ namespace eosio { // Note: need to add support for IPv6 too resolver->async_resolve( query, + app().get_priority_queue().wrap( priority::low, [weak_conn, this]( const boost::system::error_code& err, tcp::resolver::iterator endpoint_itr ){ auto c = weak_conn.lock(); @@ -1807,7 +1786,7 @@ namespace eosio { elog( "Unable to resolve ${peer_addr}: ${error}", ( "peer_addr", c->peer_name() )("error", err.message() ) ); } - }); + })); } void net_plugin_impl::connect(const connection_ptr& c, tcp::resolver::iterator endpoint_itr) { @@ -1819,7 +1798,9 @@ namespace eosio { ++endpoint_itr; c->connecting = true; connection_wptr weak_conn = c; - c->socket->async_connect( current_endpoint, [weak_conn, endpoint_itr, this] ( const boost::system::error_code& err ) { + c->socket->async_connect( current_endpoint, + app().get_priority_queue().wrap( priority::low, + [weak_conn, endpoint_itr, this] ( const boost::system::error_code& err ) { auto c = weak_conn.lock(); if (!c) return; if( !err && c->socket->is_open() ) { @@ -1838,7 +1819,7 @@ namespace eosio { my_impl->close(c); } } - } ); + })); } bool net_plugin_impl::start_session(const connection_ptr& con) { @@ -1865,7 +1846,8 @@ namespace eosio { void net_plugin_impl::start_listen_loop() { auto socket = std::make_shared( std::ref( app().get_io_service() ) ); - acceptor->async_accept( *socket, [socket,this]( boost::system::error_code ec ) { + acceptor->async_accept( *socket, + app().get_priority_queue().wrap(priority::low, [socket,this]( boost::system::error_code ec ) { if( !ec ) { uint32_t visitors = 0; uint32_t from_addr = 0; @@ -1924,7 +1906,7 @@ namespace eosio { } } start_listen_loop(); - }); + })); } void net_plugin_impl::start_read_message(const connection_ptr& conn) { @@ -1954,6 +1936,7 @@ namespace eosio { boost::asio::async_read(*conn->socket, conn->pending_message_buffer.get_buffer_sequence_for_boost_async_read(), completion_handler, + app().get_priority_queue().wrap( priority::medium, [this,weak_conn]( boost::system::error_code ec, std::size_t bytes_transferred ) { auto conn = weak_conn.lock(); if (!conn) { @@ -2033,7 +2016,7 @@ namespace eosio { elog( "Undefined exception hanlding the read data from connection ${p}",( "p",pname)); close( conn ); } - } ); + })); } catch (...) { string pname = conn ? conn->peer_name() : "no connection name"; elog( "Undefined exception handling reading ${p}",("p",pname) ); @@ -2053,10 +2036,10 @@ namespace eosio { template - void net_plugin_impl::send_all(const std::shared_ptr>& send_buffer, VerifierFunc verify) { + void net_plugin_impl::send_transaction_to_all(const std::shared_ptr>& send_buffer, VerifierFunc verify) { for( auto &c : connections) { if( c->current() && verify( c )) { - c->enqueue_buffer( send_buffer, true, no_reason ); + c->enqueue_buffer( send_buffer, true, priority::low, no_reason ); } } } @@ -2363,7 +2346,6 @@ namespace eosio { auto ptrx = std::make_shared( trx ); const auto& tid = ptrx->id; - c->cancel_wait(); if(local_txns.get().find(tid) != local_txns.end()) { fc_dlog(logger, "got a duplicate transaction - dropping"); return; @@ -2454,7 +2436,7 @@ namespace eosio { void net_plugin_impl::start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection) { connector_check->expires_from_now( du); - connector_check->async_wait( [this, from_connection](boost::system::error_code ec) { + connector_check->async_wait(app().get_priority_queue().wrap(priority::low, [this, from_connection](boost::system::error_code ec) { if( !ec) { connection_monitor(from_connection); } @@ -2462,12 +2444,13 @@ namespace eosio { elog( "Error from connection check monitor: ${m}",( "m", ec.message())); start_conn_timer( connector_period, std::weak_ptr()); } - }); + })); } void net_plugin_impl::start_txn_timer() { transaction_check->expires_from_now( txn_exp_period); - transaction_check->async_wait( [this](boost::system::error_code ec) { + int lower_than_low = priority::low - 1; + transaction_check->async_wait(app().get_priority_queue().wrap(lower_than_low, [this](boost::system::error_code ec) { if( !ec) { expire_txns(); } @@ -2475,12 +2458,12 @@ namespace eosio { elog( "Error from transaction check monitor: ${m}",( "m", ec.message())); start_txn_timer(); } - }); + })); } void net_plugin_impl::ticker() { keepalive_timer->expires_from_now(keepalive_interval); - keepalive_timer->async_wait([this](boost::system::error_code ec) { + keepalive_timer->async_wait(app().get_priority_queue().wrap(priority::low, [this](boost::system::error_code ec) { ticker(); if (ec) { wlog("Peer keepalive ticked sooner than expected: ${m}", ("m", ec.message())); @@ -2490,7 +2473,7 @@ namespace eosio { c->send_time(); } } - }); + })); } void net_plugin_impl::start_monitors() { @@ -2692,7 +2675,7 @@ namespace eosio { controller& cc = my_impl->chain_plug->chain(); hello.head_id = fc::sha256(); hello.last_irreversible_block_id = fc::sha256(); - hello.head_num = cc.fork_db_head_block_num(); + hello.head_num = cc.fork_db_pending_head_block_num(); hello.last_irreversible_block_num = cc.last_irreversible_block_num(); if( hello.last_irreversible_block_num ) { try { diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index 7fc653d2034..1c61e35974b 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -23,6 +23,7 @@ class producer_plugin : public appbase::plugin { fc::optional max_irreversible_block_age; fc::optional produce_time_offset_us; fc::optional last_block_time_offset_us; + fc::optional max_scheduled_transaction_time_per_block_ms; fc::optional subjective_cpu_leeway_us; fc::optional incoming_defer_ratio; }; @@ -88,7 +89,7 @@ class producer_plugin : public appbase::plugin { } //eosio -FC_REFLECT(eosio::producer_plugin::runtime_options, (max_transaction_time)(max_irreversible_block_age)(produce_time_offset_us)(last_block_time_offset_us)(subjective_cpu_leeway_us)(incoming_defer_ratio)); +FC_REFLECT(eosio::producer_plugin::runtime_options, (max_transaction_time)(max_irreversible_block_age)(produce_time_offset_us)(last_block_time_offset_us)(max_scheduled_transaction_time_per_block_ms)(subjective_cpu_leeway_us)(incoming_defer_ratio)); FC_REFLECT(eosio::producer_plugin::greylist_params, (accounts)); FC_REFLECT(eosio::producer_plugin::whitelist_blacklist, (actor_whitelist)(actor_blacklist)(contract_whitelist)(contract_blacklist)(action_blacklist)(key_blacklist) ) FC_REFLECT(eosio::producer_plugin::integrity_hash_information, (head_block_id)(integrity_hash)) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 8ead8107b11..e7d0600deac 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -137,6 +137,7 @@ class producer_plugin_impl : public std::enable_shared_from_this().publish( block ); + app().get_channel().publish( priority::medium, block ); return; } @@ -350,7 +351,7 @@ class producer_plugin_impl : public std::enable_shared_from_thissigning_keys_future.valid() ) trx->signing_keys_future.wait(); - app().get_io_service().post( [self, trx, persist_until_expired, next]() { + app().post(priority::low, [self, trx, persist_until_expired, next]() { self->process_incoming_transaction_async( trx, persist_until_expired, next ); }); }); @@ -368,7 +369,7 @@ class producer_plugin_impl : public std::enable_shared_from_this& response) { next(response); if (response.contains()) { - _transaction_ack_channel.publish(std::pair(response.get(), trx)); + _transaction_ack_channel.publish(priority::low, std::pair(response.get(), trx)); if (_pending_block_mode == pending_block_mode::producing) { fc_dlog(_trx_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is REJECTING tx: ${txid} : ${why} ", ("block_num", chain.head_block_num() + 1) @@ -381,7 +382,7 @@ class producer_plugin_impl : public std::enable_shared_from_this()->what())); } } else { - _transaction_ack_channel.publish(std::pair(nullptr, trx)); + _transaction_ack_channel.publish(priority::low, std::pair(nullptr, trx)); if (_pending_block_mode == pending_block_mode::producing) { fc_dlog(_trx_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is ACCEPTING tx: ${txid}", ("block_num", chain.head_block_num() + 1) @@ -407,9 +408,10 @@ class producer_plugin_impl : public std::enable_shared_from_this& weak_this, const block_timestamp_type& current_block_time); }; @@ -538,6 +541,8 @@ void producer_plugin::set_program_options( "offset of non last block producing time in microseconds. Negative number results in blocks to go out sooner, and positive number results in blocks to go out later") ("last-block-time-offset-us", boost::program_options::value()->default_value(0), "offset of last block producing time in microseconds. Negative number results in blocks to go out sooner, and positive number results in blocks to go out later") + ("max-scheduled-transaction-time-per-block-ms", boost::program_options::value()->default_value(100), + "Maximum wall-clock time, in milliseconds, spent retiring scheduled transactions in any block before returning to normal transaction processing.") ("incoming-defer-ratio", bpo::value()->default_value(1.0), "ratio between incoming transations and deferred transactions when both are exhausted") ("producer-threads", bpo::value()->default_value(config::default_controller_thread_pool_size), @@ -668,6 +673,8 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->_last_block_time_offset_us = options.at("last-block-time-offset-us").as(); + my->_max_scheduled_transaction_time_per_block_ms = options.at("max-scheduled-transaction-time-per-block-ms").as(); + my->_max_transaction_time_ms = options.at("max-transaction-time").as(); my->_max_irreversible_block_age_us = fc::seconds(options.at("max-irreversible-block-age").as()); @@ -828,6 +835,10 @@ void producer_plugin::update_runtime_options(const runtime_options& options) { my->_last_block_time_offset_us = *options.last_block_time_offset_us; } + if (options.max_scheduled_transaction_time_per_block_ms) { + my->_max_scheduled_transaction_time_per_block_ms = *options.max_scheduled_transaction_time_per_block_ms; + } + if (options.incoming_defer_ratio) { my->_incoming_defer_ratio = *options.incoming_defer_ratio; } @@ -849,7 +860,8 @@ producer_plugin::runtime_options producer_plugin::get_runtime_options() const { my->_max_transaction_time_ms, my->_max_irreversible_block_age_us.count() < 0 ? -1 : my->_max_irreversible_block_age_us.count() / 1'000'000, my->_produce_time_offset_us, - my->_last_block_time_offset_us + my->_last_block_time_offset_us, + my->_max_scheduled_transaction_time_per_block_ms }; } @@ -1018,6 +1030,11 @@ fc::time_point producer_plugin_impl::calculate_pending_block_time() const { return block_time; } +fc::time_point producer_plugin_impl::calculate_block_deadline( const fc::time_point& block_time ) const { + bool last_block = ((block_timestamp_type(block_time).slot % config::producer_repetitions) == config::producer_repetitions - 1); + return block_time + fc::microseconds(last_block ? _last_block_time_offset_us : _produce_time_offset_us); +} + enum class tx_category { PERSISTED, UNEXPIRED_UNPERSISTED, @@ -1025,12 +1042,14 @@ enum class tx_category { }; -producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool &last_block) { +producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { chain::controller& chain = chain_plug->chain(); if( chain.get_read_mode() == chain::db_read_mode::READ_ONLY ) return start_block_result::waiting; + fc_dlog(_log, "Starting block at ${time}", ("time", fc::time_point::now())); + const auto& hbs = chain.head_block_state(); //Schedule for the next second's tick regardless of chain state @@ -1041,7 +1060,6 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool _pending_block_mode = pending_block_mode::producing; // Not our turn - last_block = ((block_timestamp_type(block_time).slot % config::producer_repetitions) == config::producer_repetitions - 1); const auto& scheduled_producer = hbs->get_scheduled_producer(block_time); auto currrent_watermark_itr = _producer_watermarks.find(scheduled_producer.producer_name); auto signature_provider_itr = _signature_providers.find(scheduled_producer.block_signing_key); @@ -1104,10 +1122,10 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool chain.start_block(block_time, blocks_to_confirm); } FC_LOG_AND_DROP(); - if( chain.is_building_block() ) { auto pending_block_time = chain.pending_block_time(); auto pending_block_signing_key = chain.pending_block_signing_key(); + const fc::time_point preprocess_deadline = calculate_block_deadline(block_time); if (_pending_block_mode == pending_block_mode::producing && pending_block_signing_key != scheduled_producer.block_signing_key) { elog("Block Signing Key is not expected value, reverting to speculative mode! [expected: \"${expected}\", actual: \"${actual\"", ("expected", scheduled_producer.block_signing_key)("actual", pending_block_signing_key)); @@ -1190,7 +1208,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool int num_processed = 0; for (const auto& trx: apply_trxs) { - if (block_time <= fc::time_point::now()) exhausted = true; + if (preprocess_deadline <= fc::time_point::now()) exhausted = true; if (exhausted) { break; } @@ -1200,9 +1218,9 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool try { auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); bool deadline_is_subjective = false; - if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && block_time < deadline)) { + if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && preprocess_deadline < deadline)) { deadline_is_subjective = true; - deadline = block_time; + deadline = preprocess_deadline; } auto trace = chain.push_transaction(trx, deadline); @@ -1255,8 +1273,16 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool int num_failed = 0; int num_processed = 0; + auto scheduled_trx_deadline = preprocess_deadline; + if (_max_scheduled_transaction_time_per_block_ms >= 0) { + scheduled_trx_deadline = std::min( + scheduled_trx_deadline, + fc::time_point::now() + fc::milliseconds(_max_scheduled_transaction_time_per_block_ms) + ); + } + for (const auto& trx : scheduled_trxs) { - if (block_time <= fc::time_point::now()) exhausted = true; + if (scheduled_trx_deadline <= fc::time_point::now()) exhausted = true; if (exhausted) { break; } @@ -1265,6 +1291,8 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool // configurable ratio of incoming txns vs deferred txns while (_incoming_trx_weight >= 1.0 && orig_pending_txn_size && _pending_incoming_transactions.size()) { + if (scheduled_trx_deadline <= fc::time_point::now()) break; + auto e = _pending_incoming_transactions.front(); _pending_incoming_transactions.pop_front(); --orig_pending_txn_size; @@ -1272,7 +1300,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool process_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); } - if (block_time <= fc::time_point::now()) { + if (scheduled_trx_deadline <= fc::time_point::now()) { exhausted = true; break; } @@ -1284,9 +1312,9 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool try { auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); bool deadline_is_subjective = false; - if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && block_time < deadline)) { + if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && scheduled_trx_deadline < deadline)) { deadline_is_subjective = true; - deadline = block_time; + deadline = scheduled_trx_deadline; } auto trace = chain.push_scheduled_transaction(trx, deadline); @@ -1320,20 +1348,20 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool } } - if (exhausted || block_time <= fc::time_point::now()) { + if (exhausted || preprocess_deadline <= fc::time_point::now()) { return start_block_result::exhausted; } else { // attempt to apply any pending incoming transactions _incoming_trx_weight = 0.0; if (!_pending_incoming_transactions.empty()) { - fc_dlog(_log, "Processing ${n} pending transactions"); + fc_dlog(_log, "Processing ${n} pending transactions", ("n", _pending_incoming_transactions.size())); while (orig_pending_txn_size && _pending_incoming_transactions.size()) { auto e = _pending_incoming_transactions.front(); _pending_incoming_transactions.pop_front(); --orig_pending_txn_size; process_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); - if (block_time <= fc::time_point::now()) return start_block_result::exhausted; + if (preprocess_deadline <= fc::time_point::now()) return start_block_result::exhausted; } } return start_block_result::succeeded; @@ -1354,20 +1382,20 @@ void producer_plugin_impl::schedule_production_loop() { _timer.cancel(); std::weak_ptr weak_this = shared_from_this(); - bool last_block; - auto result = start_block(last_block); + auto result = start_block(); if (result == start_block_result::failed) { elog("Failed to start a pending block, will try again later"); _timer.expires_from_now( boost::posix_time::microseconds( config::block_interval_us / 10 )); // we failed to start a block, so try again later? - _timer.async_wait([weak_this,cid=++_timer_corelation_id](const boost::system::error_code& ec) { - auto self = weak_this.lock(); - if (self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id) { - self->schedule_production_loop(); - } - }); + _timer.async_wait( app().get_priority_queue().wrap( priority::high, + [weak_this, cid = ++_timer_corelation_id]( const boost::system::error_code& ec ) { + auto self = weak_this.lock(); + if( self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id ) { + self->schedule_production_loop(); + } + } ) ); } else if (result == start_block_result::waiting){ if (!_producers.empty() && !production_disabled_by_policy()) { fc_dlog(_log, "Waiting till another block is received and scheduling Speculative/Production Change"); @@ -1381,36 +1409,42 @@ void producer_plugin_impl::schedule_production_loop() { // we succeeded but block may be exhausted static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); - if (result == start_block_result::succeeded) { + auto deadline = calculate_block_deadline(chain.pending_block_time()); + + if (deadline > fc::time_point::now()) { // ship this block off no later than its deadline EOS_ASSERT( chain.is_building_block(), missing_pending_block_state, "producing without pending_block_state, start_block succeeded" ); - auto deadline = chain.pending_block_time().time_since_epoch().count() + (last_block ? _last_block_time_offset_us : _produce_time_offset_us); - _timer.expires_at( epoch + boost::posix_time::microseconds( deadline )); - fc_dlog(_log, "Scheduling Block Production on Normal Block #${num} for ${time}", ("num", chain.head_block_num()+1)("time",deadline)); + _timer.expires_at( epoch + boost::posix_time::microseconds( deadline.time_since_epoch().count() )); + fc_dlog(_log, "Scheduling Block Production on Normal Block #${num} for ${time}", + ("num", chain.head_block_num()+1)("time",deadline)); } else { EOS_ASSERT( chain.is_building_block(), missing_pending_block_state, "producing without pending_block_state" ); auto expect_time = chain.pending_block_time() - fc::microseconds(config::block_interval_us); // ship this block off up to 1 block time earlier or immediately if (fc::time_point::now() >= expect_time) { _timer.expires_from_now( boost::posix_time::microseconds( 0 )); - fc_dlog(_log, "Scheduling Block Production on Exhausted Block #${num} immediately", ("num", chain.head_block_num()+1)); + fc_dlog(_log, "Scheduling Block Production on Exhausted Block #${num} immediately", + ("num", chain.head_block_num()+1)); } else { _timer.expires_at(epoch + boost::posix_time::microseconds(expect_time.time_since_epoch().count())); - fc_dlog(_log, "Scheduling Block Production on Exhausted Block #${num} at ${time}", ("num", chain.head_block_num()+1)("time",expect_time)); + fc_dlog(_log, "Scheduling Block Production on Exhausted Block #${num} at ${time}", + ("num", chain.head_block_num()+1)("time",expect_time)); } } - _timer.async_wait([&chain,weak_this,cid=++_timer_corelation_id](const boost::system::error_code& ec) { - auto self = weak_this.lock(); - if (self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id) { - // pending_block_state expected, but can't assert inside async_wait - auto block_num = chain.is_building_block() ? chain.head_block_num() + 1 : 0; - auto res = self->maybe_produce_block(); - fc_dlog(_log, "Producing Block #${num} returned: ${res}", ("num", block_num)("res", res)); - } - }); + _timer.async_wait( app().get_priority_queue().wrap( priority::high, + [&chain,weak_this,cid=++_timer_corelation_id](const boost::system::error_code& ec) { + auto self = weak_this.lock(); + if( self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id ) { + fc_dlog( _log, "Produce block timer running at ${time}", ("time", fc::time_point::now()) ); + // pending_block_state expected, but can't assert inside async_wait + auto block_num = chain.is_building_block() ? chain.head_block_num() + 1 : 0; + auto res = self->maybe_produce_block(); + fc_dlog( _log, "Producing Block #${num} returned: ${res}", ("num", block_num)( "res", res ) ); + } + } ) ); } else if (_pending_block_mode == pending_block_mode::speculating && !_producers.empty() && !production_disabled_by_policy()){ - fc_dlog(_log, "Specualtive Block Created; Scheduling Speculative/Production Change"); + fc_dlog(_log, "Speculative Block Created; Scheduling Speculative/Production Change"); EOS_ASSERT( chain.is_building_block(), missing_pending_block_state, "speculating without pending_block_state" ); schedule_delayed_production_loop(weak_this, chain.pending_block_time()); } else { @@ -1438,12 +1472,13 @@ void producer_plugin_impl::schedule_delayed_production_loop(const std::weak_ptr< fc_dlog(_log, "Scheduling Speculative/Production Change at ${time}", ("time", wake_up_time)); static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); _timer.expires_at(epoch + boost::posix_time::microseconds(wake_up_time->time_since_epoch().count())); - _timer.async_wait([weak_this,cid=++_timer_corelation_id](const boost::system::error_code& ec) { - auto self = weak_this.lock(); - if (self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id) { - self->schedule_production_loop(); - } - }); + _timer.async_wait( app().get_priority_queue().wrap( priority::high, + [weak_this,cid=++_timer_corelation_id](const boost::system::error_code& ec) { + auto self = weak_this.lock(); + if( self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id ) { + self->schedule_production_loop(); + } + } ) ); } else { fc_dlog(_log, "Not Scheduling Speculative/Production, no local producers had valid wake up times"); } diff --git a/plugins/txn_test_gen_plugin/CMakeLists.txt b/plugins/txn_test_gen_plugin/CMakeLists.txt index e765f3478e6..5d7ca913ba8 100644 --- a/plugins/txn_test_gen_plugin/CMakeLists.txt +++ b/plugins/txn_test_gen_plugin/CMakeLists.txt @@ -2,9 +2,8 @@ file(GLOB HEADERS "include/eosio/txn_test_gen_plugin/*.hpp") add_library( txn_test_gen_plugin txn_test_gen_plugin.cpp ${HEADERS} ) - -add_dependencies(txn_test_gen_plugin eosio.token) - -target_link_libraries( txn_test_gen_plugin appbase fc http_plugin chain_plugin ) -target_include_directories( txn_test_gen_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) -target_include_directories( txn_test_gen_plugin PUBLIC ${CMAKE_BINARY_DIR}/contracts ) + +target_link_libraries( txn_test_gen_plugin appbase fc http_plugin chain_plugin eosio_testing ) +target_include_directories( txn_test_gen_plugin PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include + txn_test_gen_plugin PUBLIC ${CMAKE_SOURCE_DIR}/libraries/testing/include + txn_test_gen_plugin PUBLIC ${CMAKE_BINARY_DIR}/unittests/include ) diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index 707f75bd9de..712a35a2d0f 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -22,8 +22,9 @@ #include #include -#include -#include +#include + +using namespace eosio::testing; namespace eosio { namespace detail { struct txn_test_gen_empty {}; @@ -136,13 +137,13 @@ struct txn_test_gen_plugin_impl { name newaccountC("txn.test.t"); name creator(init_name); - abi_def currency_abi_def = fc::json::from_string(eosio_token_abi).as(); + abi_def currency_abi_def = fc::json::from_string(contracts::eosio_token_abi().data()).as(); controller& cc = app().get_plugin().chain(); auto chainid = app().get_plugin().get_chain_id(); auto abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); - abi_serializer eosio_token_serializer{fc::json::from_string(eosio_token_abi).as(), abi_serializer_max_time}; + abi_serializer eosio_token_serializer{fc::json::from_string(contracts::eosio_token_abi().data()).as(), abi_serializer_max_time}; fc::crypto::private_key txn_test_receiver_A_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); fc::crypto::private_key txn_test_receiver_B_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); @@ -188,7 +189,7 @@ struct txn_test_gen_plugin_impl { { signed_transaction trx; - vector wasm = wast_to_wasm(std::string(eosio_token_wast)); + vector wasm = contracts::eosio_token_wasm(); setcode handler; handler.account = newaccountC; @@ -199,7 +200,7 @@ struct txn_test_gen_plugin_impl { { setabi handler; handler.account = newaccountC; - handler.abi = fc::raw::pack(json::from_string(eosio_token_abi).as()); + handler.abi = fc::raw::pack(json::from_string(contracts::eosio_token_abi().data()).as()); trx.actions.emplace_back( vector{{newaccountC,"active"}}, handler); } @@ -264,7 +265,7 @@ struct txn_test_gen_plugin_impl { controller& cc = app().get_plugin().chain(); auto abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); - abi_serializer eosio_token_serializer{fc::json::from_string(eosio_token_abi).as(), abi_serializer_max_time}; + abi_serializer eosio_token_serializer{fc::json::from_string(contracts::eosio_token_abi().data()).as(), abi_serializer_max_time}; //create the actions here act_a_to_b.account = N(txn.test.t); act_a_to_b.name = N(transfer); diff --git a/programs/cleos/CMakeLists.txt b/programs/cleos/CMakeLists.txt index e748581d849..0d98fdcf63d 100644 --- a/programs/cleos/CMakeLists.txt +++ b/programs/cleos/CMakeLists.txt @@ -40,9 +40,5 @@ target_link_libraries( ${CLI_CLIENT_EXECUTABLE_NAME} copy_bin( ${CLI_CLIENT_EXECUTABLE_NAME} ) install( TARGETS - ${CLI_CLIENT_EXECUTABLE_NAME} - - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ${CLI_CLIENT_EXECUTABLE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT base ) diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 7abce5f79da..9150a7fcafb 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -84,6 +84,7 @@ Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey #include #include #include +#include #include #include @@ -133,6 +134,7 @@ using namespace eosio::client::http; using namespace eosio::client::localize; using namespace eosio::client::config; using namespace boost::filesystem; +using auth_type = fc::static_variant; FC_DECLARE_EXCEPTION( explained_exception, 9000000, "explained exception, see error log" ); FC_DECLARE_EXCEPTION( localized_exception, 10000000, "an error occured" ); @@ -512,14 +514,19 @@ void send_transaction( signed_transaction& trx, int32_t extra_kcpu, packed_trans } } -chain::action create_newaccount(const name& creator, const name& newaccount, public_key_type owner, public_key_type active) { +chain::permission_level to_permission_level(const std::string& s) { + auto at_pos = s.find('@'); + return permission_level { s.substr(0, at_pos), s.substr(at_pos + 1) }; +} + +chain::action create_newaccount(const name& creator, const name& newaccount, auth_type owner, auth_type active) { return action { get_account_permissions(tx_permission, {creator,config::active_name}), eosio::chain::newaccount{ .creator = creator, .name = newaccount, - .owner = eosio::chain::authority{1, {{owner, 1}}, {}}, - .active = eosio::chain::authority{1, {{active, 1}}, {}} + .owner = owner.contains() ? authority(owner.get()) : authority(owner.get()), + .active = active.contains() ? authority(active.get()) : authority(active.get()) } }; } @@ -987,8 +994,8 @@ struct create_account_subcommand { ); createAccount->add_option("creator", creator, localized("The name of the account creating the new account"))->required(); createAccount->add_option("name", account_name, localized("The name of the new account"))->required(); - createAccount->add_option("OwnerKey", owner_key_str, localized("The owner public key for the new account"))->required(); - createAccount->add_option("ActiveKey", active_key_str, localized("The active public key for the new account")); + createAccount->add_option("OwnerKey", owner_key_str, localized("The owner public key or permission level for the new account"))->required(); + createAccount->add_option("ActiveKey", active_key_str, localized("The active public key or permission level for the new account")); if (!simple) { createAccount->add_option("--stake-net", stake_net, @@ -1008,16 +1015,31 @@ struct create_account_subcommand { add_standard_transaction_options(createAccount, "creator@active"); createAccount->set_callback([this] { - if( !active_key_str.size() ) - active_key_str = owner_key_str; - public_key_type owner_key, active_key; - try { - owner_key = public_key_type(owner_key_str); - } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid owner public key: ${public_key}", ("public_key", owner_key_str)); - try { - active_key = public_key_type(active_key_str); - } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid active public key: ${public_key}", ("public_key", active_key_str)); - auto create = create_newaccount(creator, account_name, owner_key, active_key); + auth_type owner, active; + + if( owner_key_str.find('@') != string::npos ) { + try { + owner = to_permission_level(owner_key_str); + } EOS_RETHROW_EXCEPTIONS( explained_exception, "Invalid owner permission level: ${permission}", ("permission", owner_key_str) ) + } else { + try { + owner = public_key_type(owner_key_str); + } EOS_RETHROW_EXCEPTIONS( public_key_type_exception, "Invalid owner public key: ${public_key}", ("public_key", owner_key_str) ); + } + + if( active_key_str.empty() ) { + active = owner; + } else if( active_key_str.find('@') != string::npos ) { + try { + active = to_permission_level(active_key_str); + } EOS_RETHROW_EXCEPTIONS( explained_exception, "Invalid active permission level: ${permission}", ("permission", active_key_str) ) + } else { + try { + active = public_key_type(active_key_str); + } EOS_RETHROW_EXCEPTIONS( public_key_type_exception, "Invalid active public key: ${public_key}", ("public_key", active_key_str) ); + } + + auto create = create_newaccount(creator, account_name, owner, active); if (!simple) { EOSC_ASSERT( buy_ram_eos.size() || buy_ram_bytes_in_kbytes || buy_ram_bytes, "ERROR: One of --buy-ram, --buy-ram-kbytes or --buy-ram-bytes should have non-zero value" ); EOSC_ASSERT( !buy_ram_bytes_in_kbytes || !buy_ram_bytes, "ERROR: --buy-ram-kbytes and --buy-ram-bytes cannot be set at the same time" ); diff --git a/programs/eosio-launcher/main.cpp b/programs/eosio-launcher/main.cpp index 55a027b6928..aca800eb604 100644 --- a/programs/eosio-launcher/main.cpp +++ b/programs/eosio-launcher/main.cpp @@ -2006,7 +2006,7 @@ int main (int argc, char *argv[]) { //------------------------------------------------------------- - +// @ignore local_config_file FC_REFLECT( remote_deploy, (ssh_cmd)(scp_cmd)(ssh_identity)(ssh_args) ) @@ -2016,16 +2016,20 @@ FC_REFLECT( prodkey_def, FC_REFLECT( producer_set_def, (schedule)) +// @ignore listen_addr, p2p_count, http_count, dot_label_str FC_REFLECT( host_def, (genesis)(ssh_identity)(ssh_args)(eosio_home) (host_name)(public_name) (base_p2p_port)(base_http_port)(def_file_size) (instances) ) +// @ignore node, dot_label_str FC_REFLECT( eosd_def, - (name)(config_dir_name)(data_dir_name)(has_db) - (p2p_port)(http_port)(file_size) ) + (config_dir_name)(data_dir_name)(p2p_port) + (http_port)(file_size)(has_db)(name)(host) + (p2p_endpoint) ) +// @ignore instance, gelf_endpoint FC_REFLECT( tn_node_def, (name)(keys)(peers)(producers) ) FC_REFLECT( testnet_def, (name)(ssh_helper)(nodes) ) diff --git a/programs/keosd/CMakeLists.txt b/programs/keosd/CMakeLists.txt index 1c294329387..3c806fbed39 100644 --- a/programs/keosd/CMakeLists.txt +++ b/programs/keosd/CMakeLists.txt @@ -22,9 +22,5 @@ mas_sign(${KEY_STORE_EXECUTABLE_NAME}) copy_bin( ${KEY_STORE_EXECUTABLE_NAME} ) install( TARGETS - ${KEY_STORE_EXECUTABLE_NAME} - - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ${KEY_STORE_EXECUTABLE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT base ) diff --git a/programs/keosd/main.cpp b/programs/keosd/main.cpp index efbf2d567f2..57e2a0c8b40 100644 --- a/programs/keosd/main.cpp +++ b/programs/keosd/main.cpp @@ -41,7 +41,6 @@ int main(int argc, char** argv) app().set_default_data_dir(home / "eosio-wallet"); app().set_default_config_dir(home / "eosio-wallet"); http_plugin::set_defaults({ - .address_config_prefix = "", .default_unix_socket_path = keosd::config::key_store_executable_name + ".sock", .default_http_port = 0 }); diff --git a/programs/nodeos/CMakeLists.txt b/programs/nodeos/CMakeLists.txt index 6bddeacb848..d9fb90ee45d 100644 --- a/programs/nodeos/CMakeLists.txt +++ b/programs/nodeos/CMakeLists.txt @@ -75,11 +75,7 @@ include(additionalPlugins) copy_bin( ${NODE_EXECUTABLE_NAME} ) install( TARGETS - ${NODE_EXECUTABLE_NAME} - - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ${NODE_EXECUTABLE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} COMPONENT base ) install(DIRECTORY DESTINATION ${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/log/eosio DIRECTORY_PERMISSIONS OWNER_READ diff --git a/programs/nodeos/main.cpp b/programs/nodeos/main.cpp index 52eb9a0e9ab..b858db748dd 100644 --- a/programs/nodeos/main.cpp +++ b/programs/nodeos/main.cpp @@ -97,7 +97,6 @@ int main(int argc, char** argv) app().set_default_data_dir(root / "eosio/nodeos/data" ); app().set_default_config_dir(root / "eosio/nodeos/config" ); http_plugin::set_defaults({ - .address_config_prefix = "", .default_unix_socket_path = "", .default_http_port = 8888 }); diff --git a/scripts/clean_old_install.sh b/scripts/clean_old_install.sh index 03315ff744b..6e04edf92d5 100755 --- a/scripts/clean_old_install.sh +++ b/scripts/clean_old_install.sh @@ -17,7 +17,7 @@ if [ -d "/usr/local/include/eosio" ]; then popd &> /dev/null pushd bin &> /dev/null - rm cleos eosio-abigen eosio-applesdemo eosio-launcher eosio-s2wasm eosio-wast2wasm eosiocpp keosd nodeos &> /dev/null + rm cleos eosio-abigen eosio-applesedemo eosio-launcher eosio-s2wasm eosio-wast2wasm eosiocpp keosd nodeos &> /dev/null popd &> /dev/null libraries=(libeosio_testing diff --git a/scripts/eosio_build_darwin.sh b/scripts/eosio_build_darwin.sh index a91e1611d44..d1f5894b60a 100644 --- a/scripts/eosio_build_darwin.sh +++ b/scripts/eosio_build_darwin.sh @@ -398,87 +398,6 @@ printf "\\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\\n" fi - printf "\\n\\tChecking LLVM with WASM support.\\n" - if [ ! -d /usr/local/wasm/bin ]; then - if ! cd "${TEMP_DIR}" - then - printf "\\tUnable to enter directory %s.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! mkdir "${TEMP_DIR}/wasm-compiler" - then - printf "\\tUnable to create directory %s/wasm-compiler.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/wasm-compiler" - then - printf "\\tUnable to enter directory %s/wasm-compiler.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git - then - printf "\\tUnable to clone llvm repo @ https://github.com/llvm-mirror/llvm.git.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/wasm-compiler/llvm/tools" - then - printf "\\tUnable to enter directory %s/wasm-compiler/llvm/tools.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git - then - printf "\\tUnable to clone clang repo @ https://github.com/llvm-mirror/clang.git.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/wasm-compiler/llvm" - then - printf "\\tUnable to enter directory %s/wasm-compiler/llvm.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! mkdir "${TEMP_DIR}/wasm-compiler/llvm/build" - then - printf "\\tUnable to create directory %s/wasm-compiler/llvm/build.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/wasm-compiler/llvm/build" - then - printf "\\tUnable to enter directory %s/wasm-compiler/llvm/build.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/usr/local/wasm \ - -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly \ - -DCMAKE_BUILD_TYPE=Release ../ - then - printf "\\tError compiling LLVM/Clang with WASM support.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! sudo make -j"${CPU_CORE}" install - then - printf "\\tCompiling LLVM/Clang with WASM support has exited with the error above.\\n" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - if ! sudo rm -rf "${TEMP_DIR}/wasm-compiler" - then - printf "\\tUnable to remove directory %s/wasm-compiler.\\n" "${TEMP_DIR}" - printf "\\tExiting now.\\n\\n" - exit 1; - fi - printf "\\tSuccessfully installed LLVM/Clang with WASM support @ /usr/local/wasm/bin/.\\n" - else - printf "\\tWASM found at /usr/local/wasm/bin/.\\n" - fi - function print_instructions() { printf "\\n\\t%s -f %s &\\n" "$( command -v mongod )" "${MONGOD_CONF}" diff --git a/scripts/eosio_build_ubuntu.sh b/scripts/eosio_build_ubuntu.sh index 4c9873a60a1..84b28a2701b 100644 --- a/scripts/eosio_build_ubuntu.sh +++ b/scripts/eosio_build_ubuntu.sh @@ -421,88 +421,6 @@ mongodconf printf "\\tMongo C++ driver found at /usr/local/lib/libmongocxx-static.a.\\n" fi - printf "\\n\\tChecking for LLVM with WASM support.\\n" - if [ ! -d "${HOME}/opt/wasm/bin" ]; then - # Build LLVM and clang with WASM support: - printf "\\tInstalling LLVM with WASM\\n" - if ! cd "${TEMP_DIR}" - then - printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! mkdir "${TEMP_DIR}/llvm-compiler" 2>/dev/null - then - printf "\\n\\tUnable to create directory %s/llvm-compiler.\\n" "${TEMP_DIR}" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/llvm-compiler" - then - printf "\\n\\tUnable to enter directory %s/llvm-compiler.\\n" "${TEMP_DIR}" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git - then - printf "\\tUnable to clone llvm repo @ https://github.com/llvm-mirror/llvm.git.\\n" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/llvm-compiler/llvm/tools" - then - printf "\\tUnable to enter directory %s/llvm-compiler/llvm/tools.\\n" "${TEMP_DIR}" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git - then - printf "\\tUnable to clone clang repo @ https://github.com/llvm-mirror/clang.git.\\n" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/llvm-compiler/llvm" - then - printf "\\tUnable to enter directory %s/llvm-compiler/llvm.\\n" "${TEMP_DIR}" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! mkdir "${TEMP_DIR}/llvm-compiler/llvm/build" - then - printf "\\tUnable to create directory %s/llvm-compiler/llvm/build.\\n" "${TEMP_DIR}" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! cd "${TEMP_DIR}/llvm-compiler/llvm/build" - then - printf "\\tUnable to enter directory %s/llvm-compiler/llvm/build.\\n" "${TEMP_DIR}" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="${HOME}/opt/wasm" -DLLVM_TARGETS_TO_BUILD= \ - -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../ - then - printf "\\tError compiling LLVM and clang with EXPERIMENTAL WASM support.0\\n" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! make -j"${JOBS}" install - then - printf "\\tError compiling LLVM and clang with EXPERIMENTAL WASM support.1\\n" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - if ! rm -rf "${TEMP_DIR}/llvm-compiler" - then - printf "\\tUnable to remove directory %s/llvm-compiler.\\n" "${TEMP_DIR}" - printf "\\n\\tExiting now.\\n" - exit 1; - fi - printf "\\n\\tWASM successffully installed @ %s/opt/wasm/bin.\\n\\n" "${HOME}" - else - printf "\\tWASM found at %s/opt/wasm/bin.\\n" "${HOME}" - fi - function print_instructions() { printf '\n\texport PATH=${HOME}/opt/mongodb/bin:$PATH\n' diff --git a/scripts/generate_deb.sh b/scripts/generate_deb.sh index c4d50132847..9af16c069f3 100644 --- a/scripts/generate_deb.sh +++ b/scripts/generate_deb.sh @@ -13,19 +13,16 @@ fi NAME="${PROJECT}_${VERSION_NO_SUFFIX}-${RELEASE}_amd64" -DEPS_STR="" -for dep in "${DEPS[@]}"; do - DEPS_STR="${DEPS_STR} Depends: ${dep}" -done mkdir -p ${PROJECT}/DEBIAN -echo "Package: ${PROJECT} +chmod 0755 ${PROJECT}/DEBIAN +echo "Package: ${PROJECT} Version: ${VERSION_NO_SUFFIX}-${RELEASE} Section: devel Priority: optional -Depends: libbz2-dev (>= 1.0), libssl-dev (>= 1.0), libgmp3-dev, build-essential, libicu-dev, zlib1g-dev +Depends: libbz2-dev (>= 1.0), libssl-dev (>= 1.0), libgmp3-dev, build-essential, libicu-dev, zlib1g-dev, libtinfo5 Architecture: amd64 -Homepage: ${URL} -Maintainer: ${EMAIL} +Homepage: ${URL} +Maintainer: ${EMAIL} Description: ${DESC}" &> ${PROJECT}/DEBIAN/control export PREFIX @@ -35,8 +32,8 @@ export SSUBPREFIX bash generate_tarball.sh ${NAME}.tar.gz -tar -xvzf ${NAME}.tar.gz -C ${PROJECT} -dpkg-deb --build ${PROJECT} +tar -xvzf ${NAME}.tar.gz -C ${PROJECT} +dpkg-deb --build ${PROJECT} BUILDSTATUS=$? mv ${PROJECT}.deb ${NAME}.deb rm -r ${PROJECT} diff --git a/testnet.template b/testnet.template index dab3cc5b37f..f9e793a5c89 100644 --- a/testnet.template +++ b/testnet.template @@ -75,7 +75,7 @@ wcmd create --to-console -n ignition # ------ DO NOT ALTER THE NEXT LINE ------- ###INSERT prodkeys -ecmd set contract eosio contracts/eosio.bios eosio.bios.wasm eosio.bios.abi +ecmd set contract eosio unittests/contracts/eosio.bios eosio.bios.wasm eosio.bios.abi # Create required system accounts ecmd create key --to-console @@ -92,11 +92,11 @@ ecmd create account eosio eosio.saving $pubsyskey $pubsyskey ecmd create account eosio eosio.stake $pubsyskey $pubsyskey ecmd create account eosio eosio.token $pubsyskey $pubsyskey ecmd create account eosio eosio.vpay $pubsyskey $pubsyskey -ecmd create account eosio eosio.sudo $pubsyskey $pubsyskey +ecmd create account eosio eosio.wrap $pubsyskey $pubsyskey -ecmd set contract eosio.token contracts/eosio.token eosio.token.wasm eosio.token.abi -ecmd set contract eosio.msig contracts/eosio.msig eosio.msig.wasm eosio.msig.abi -ecmd set contract eosio.sudo contracts/eosio.sudo eosio.sudo.wasm eosio.sudo.abi +ecmd set contract eosio.token unittests/contracts/eosio.token eosio.token.wasm eosio.token.abi +ecmd set contract eosio.msig unittests/contracts/eosio.msig eosio.msig.wasm eosio.msig.abi +ecmd set contract eosio.wrap unittests/contracts/eosio.wrap eosio.wrap.wasm eosio.wrap.abi echo ===== Start: $step ============ >> $logfile echo executing: cleos --wallet-url $wdurl --url http://$bioshost:$biosport push action eosio.token create '[ "eosio", "10000000000.0000 SYS" ]' -p eosio.token | tee -a $logfile @@ -107,7 +107,8 @@ programs/cleos/cleos --wallet-url $wdurl --url http://$bioshost:$biosport push a echo ==== End: $step ============== >> $logfile step=$(($step + 1)) -ecmd set contract eosio contracts/eosio.system eosio.system.wasm eosio.system.abi +ecmd set contract eosio unittests/contracts/eosio.system eosio.system.wasm eosio.system.abi +programs/cleos/cleos --wallet-url $wdurl --url http://$bioshost:$biosport push action eosio init '[0, "4,SYS"]' -p eosio >> $logfile 2>&1 # Manual deployers, add a series of lines below this block that looks like: # cacmd $PRODNAME[0] $OWNERKEY[0] $ACTIVEKEY[0] diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c88caa1f995..9f545c378b2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,9 +20,9 @@ target_link_libraries( plugin_test eosio_testing eosio_chain chainbase chain_plu target_include_directories( plugin_test PUBLIC ${CMAKE_SOURCE_DIR}/plugins/net_plugin/include - ${CMAKE_SOURCE_DIR}/plugins/chain_plugin/include ) - -# + ${CMAKE_SOURCE_DIR}/plugins/chain_plugin/include + ${CMAKE_BINARY_DIR}/unittests/include/ ) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/core_symbol.py.in ${CMAKE_CURRENT_BINARY_DIR}/core_symbol.py) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testUtils.py ${CMAKE_CURRENT_BINARY_DIR}/testUtils.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/WalletMgr.py ${CMAKE_CURRENT_BINARY_DIR}/WalletMgr.py COPYONLY) diff --git a/tests/Cluster.py b/tests/Cluster.py index 06a5357e9af..ac513475d8b 100644 --- a/tests/Cluster.py +++ b/tests/Cluster.py @@ -961,7 +961,7 @@ def bootstrap(totalNodes, prodCount, totalProducers, biosHost, biosPort, walletM return None contract="eosio.bios" - contractDir="contracts/%s" % (contract) + contractDir="unittests/contracts/%s" % (contract) wasmFile="%s.wasm" % (contract) abiFile="%s.abi" % (contract) Utils.Print("Publish %s contract" % (contract)) @@ -1085,7 +1085,7 @@ def bootstrap(totalNodes, prodCount, totalProducers, biosHost, biosPort, walletM return None contract="eosio.token" - contractDir="contracts/%s" % (contract) + contractDir="unittests/contracts/%s" % (contract) wasmFile="%s.wasm" % (contract) abiFile="%s.abi" % (contract) Utils.Print("Publish %s contract" % (contract)) @@ -1140,7 +1140,7 @@ def bootstrap(totalNodes, prodCount, totalProducers, biosHost, biosPort, walletM return None contract="eosio.system" - contractDir="contracts/%s" % (contract) + contractDir="unittests/contracts/%s" % (contract) wasmFile="%s.wasm" % (contract) abiFile="%s.abi" % (contract) Utils.Print("Publish %s contract" % (contract)) @@ -1171,7 +1171,10 @@ def bootstrap(totalNodes, prodCount, totalProducers, biosHost, biosPort, walletM if not biosNode.waitForTransInBlock(transId): Utils.Print("ERROR: Failed to validate transaction %s got rolled into a block on server port %d." % (transId, biosNode.port)) return None - + action="init" + data="{\"version\":0,\"core\":\"4,%s\"}" % (CORE_SYMBOL) + opts="--permission %s@active" % (eosioAccount.name) + trans=biosNode.pushMessage(eosioAccount.name, action, data, opts) Utils.Print("Cluster bootstrap done.") return biosNode diff --git a/tests/Node.py b/tests/Node.py index 5fc4e95dcce..55ecbb0be22 100644 --- a/tests/Node.py +++ b/tests/Node.py @@ -6,6 +6,7 @@ import re import datetime import json +import signal from core_symbol import CORE_SYMBOL from testUtils import Utils @@ -51,6 +52,7 @@ def __init__(self, host, port, pid=None, cmd=None, walletMgr=None, enableMongo=F self.transCache={} self.walletMgr=walletMgr self.missingTransaction=False + self.popenProc=None # initial process is started by launcher, this will only be set on relaunch if self.enableMongo: self.mongoEndpointArgs += "--host %s --port %d %s" % (mongoHost, mongoPort, mongoDb) @@ -547,14 +549,16 @@ def createAccount(self, account, creatorAccount, stakedDeposit=1000, waitForTran return self.waitForTransBlockIfNeeded(trans, waitForTransBlock, exitOnError=exitOnError) - def getEosAccount(self, name, exitOnError=False): + def getEosAccount(self, name, exitOnError=False, returnType=ReturnType.json, avoidMongo=False): assert(isinstance(name, str)) - if not self.enableMongo: + if not self.enableMongo or avoidMongo: cmdDesc="get account" - cmd="%s -j %s" % (cmdDesc, name) + jsonFlag="-j" if returnType==ReturnType.json else "" + cmd="%s %s %s" % (cmdDesc, jsonFlag, name) msg="( getEosAccount(name=%s) )" % (name); - return self.processCleosCmd(cmd, cmdDesc, silentErrors=False, exitOnError=exitOnError, exitMsg=msg) + return self.processCleosCmd(cmd, cmdDesc, silentErrors=False, exitOnError=exitOnError, exitMsg=msg, returnType=returnType) else: + assert returnType == ReturnType.json, "MongoDB only supports a returnType of ReturnType.json" return self.getEosAccountFromDb(name, exitOnError=exitOnError) def getEosAccountFromDb(self, name, exitOnError=False): @@ -1048,7 +1052,7 @@ def processCleosCmd(self, cmd, cmdDesc, silentErrors=True, exitOnError=False, ex if exitOnError and trans is None: Utils.cmdError("could not \"%s\". %s" % (cmdDesc,exitMsg)) - errorExit("Failed to \"%s\"" % (cmdDesc)) + Utils.errorExit("Failed to \"%s\"" % (cmdDesc)) return trans @@ -1203,6 +1207,16 @@ def myFunc(): self.killed=True return True + def interruptAndVerifyExitStatus(self): + if Utils.Debug: Utils.Print("terminating node: %s" % (self.cmd)) + assert self.popenProc is not None, "node: \"%s\" does not have a popenProc, this may be because it is only set after a relaunch." % (self.cmd) + self.popenProc.send_signal(signal.SIGINT) + try: + outs, _ = self.popenProc.communicate(timeout=1) + assert self.popenProc.returncode == 0, "Expected terminating \"%s\" to have an exit status of 0, but got %d" % (self.cmd, self.popenProc.returncode) + except subprocess.TimeoutExpired: + Utils.errorExit("Terminate call failed on node: %s" % (self.cmd)) + def verifyAlive(self, silent=False): if not silent and Utils.Debug: Utils.Print("Checking if node(pid=%s) is alive(killed=%s): %s" % (self.pid, self.killed, self.cmd)) if self.killed or self.pid is None: @@ -1227,7 +1241,7 @@ def getBlockProducerByNum(self, blockNum, timeout=None, waitForBlock=True, exitO blockProducer=block["producer"] if blockProducer is None and exitOnError: Utils.cmdError("could not get producer for block number %s" % (blockNum)) - errorExit("Failed to get block's producer") + Utils.errorExit("Failed to get block's producer") return blockProducer def getBlockProducer(self, timeout=None, waitForBlock=True, exitOnError=True, blockType=BlockType.head): @@ -1236,7 +1250,7 @@ def getBlockProducer(self, timeout=None, waitForBlock=True, exitOnError=True, bl blockProducer=block["producer"] if blockProducer is None and exitOnError: Utils.cmdError("could not get producer for block number %s" % (blockNum)) - errorExit("Failed to get block's producer") + Utils.errorExit("Failed to get block's producer") return blockProducer def getNextCleanProductionCycle(self, trans): @@ -1312,8 +1326,8 @@ def relaunch(self, nodeId, chainArg, newChain=False, timeout=Utils.systemWaitTim with open(stdoutFile, 'w') as sout, open(stderrFile, 'w') as serr: cmd=myCmd + ("" if chainArg is None else (" " + chainArg)) Utils.Print("cmd: %s" % (cmd)) - popen=subprocess.Popen(cmd.split(), stdout=sout, stderr=serr) - self.pid=popen.pid + self.popenProc=subprocess.Popen(cmd.split(), stdout=sout, stderr=serr) + self.pid=self.popenProc.pid if Utils.Debug: Utils.Print("restart Node host=%s, port=%s, pid=%s, cmd=%s" % (self.host, self.port, self.pid, self.cmd)) def isNodeAlive(): diff --git a/tests/chain_plugin_tests.cpp b/tests/chain_plugin_tests.cpp index 5a489c255b4..4b4caa45311 100644 --- a/tests/chain_plugin_tests.cpp +++ b/tests/chain_plugin_tests.cpp @@ -1,3 +1,7 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #include #include @@ -9,8 +13,7 @@ #include #include -#include -#include +#include #include @@ -42,8 +45,8 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, TESTER ) try { produce_block(); // setup contract and abi - set_code(N(asserter), asserter_wast); - set_abi(N(asserter), asserter_abi); + set_code( N(asserter), contracts::asserter_wasm() ); + set_abi( N(asserter), contracts::asserter_abi().data() ); produce_blocks(1); auto resolver = [&,this]( const account_name& name ) -> optional { @@ -100,7 +103,7 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, TESTER ) try { BOOST_TEST(block_str.find("011253686f756c64204e6f742041737365727421") != std::string::npos); //action data // set an invalid abi (int8->xxxx) - std::string abi2 = asserter_abi; + std::string abi2 = contracts::asserter_abi().data(); auto pos = abi2.find("int8"); BOOST_TEST(pos != std::string::npos); abi2.replace(pos, 4, "xxxx"); @@ -120,4 +123,3 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, TESTER ) try { } FC_LOG_AND_RETHROW() /// get_block_with_invalid_abi BOOST_AUTO_TEST_SUITE_END() - diff --git a/tests/get_table_tests.cpp b/tests/get_table_tests.cpp index bb332b9a000..ca5ff408e43 100644 --- a/tests/get_table_tests.cpp +++ b/tests/get_table_tests.cpp @@ -1,3 +1,7 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #include #include @@ -9,14 +13,7 @@ #include #include -#include -#include - -#include -#include - -#include -#include +#include #include @@ -51,8 +48,8 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { create_accounts(accs); produce_block(); - set_code( N(eosio.token), eosio_token_wast ); - set_abi( N(eosio.token), eosio_token_abi ); + set_code( N(eosio.token), contracts::eosio_token_wasm() ); + set_abi( N(eosio.token), contracts::eosio_token_abi().data() ); produce_blocks(1); // create currency @@ -127,8 +124,8 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { create_accounts(accs); produce_block(); - set_code( N(eosio.token), eosio_token_wast ); - set_abi( N(eosio.token), eosio_token_abi ); + set_code( N(eosio.token), contracts::eosio_token_wasm() ); + set_abi( N(eosio.token), contracts::eosio_token_abi().data() ); produce_blocks(1); // create currency @@ -322,8 +319,8 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { create_accounts(accs); produce_block(); - set_code( N(eosio.token), eosio_token_wast ); - set_abi( N(eosio.token), eosio_token_abi ); + set_code( N(eosio.token), contracts::eosio_token_wasm() ); + set_abi( N(eosio.token), contracts::eosio_token_abi().data() ); produce_blocks(1); // create currency @@ -341,9 +338,14 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { ); } produce_blocks(1); - - set_code( config::system_account_name, eosio_system_wast ); - set_abi( config::system_account_name, eosio_system_abi ); + + set_code( config::system_account_name, contracts::eosio_system_wasm() ); + set_abi( config::system_account_name, contracts::eosio_system_abi().data() ); + + base_tester::push_action(config::system_account_name, N(init), + config::system_account_name, mutable_variant_object() + ("version", 0) + ("core", CORE_SYM_STR)); // bidname auto bidname = [this]( const account_name& bidder, const account_name& newname, const asset& bid ) { diff --git a/tests/nodeos_forked_chain_test.py b/tests/nodeos_forked_chain_test.py index 1ef2079e878..33914240157 100755 --- a/tests/nodeos_forked_chain_test.py +++ b/tests/nodeos_forked_chain_test.py @@ -97,7 +97,7 @@ def analyzeBPs(bps0, bps1, expectDivergence): if errorInDivergence: msg="Failed analyzing block producers - " if expectDivergence: - msg+="nodes indicate different block producers for the same blocks, but did not expect them to diverge." + msg+="nodes do not indicate different block producers for the same blocks, but they are expected to diverge at some point." else: msg+="did not expect nodes to indicate different block producers for the same blocks." msg+="\n Matching Blocks= %s \n Diverging branch node0= %s \n Diverging branch node1= %s" % (bpsStr,bpsStr0,bpsStr1) @@ -314,7 +314,7 @@ def getMinHeadAndLib(prodNodes): blockProducers1=[] libs0=[] libs1=[] - lastBlockNum=max([preKillBlockNum,postKillBlockNum])+maxActiveProducers*inRowCountPerProducer + lastBlockNum=max([preKillBlockNum,postKillBlockNum])+2*maxActiveProducers*inRowCountPerProducer actualLastBlockNum=None prodChanged=False nextProdChange=False @@ -348,8 +348,12 @@ def getMinHeadAndLib(prodNodes): if blockProducer0!=blockProducer1: Utils.errorExit("Groups reported different block producers for block number %d. %s != %s." % (blockNum,blockProducer0,blockProducer1)) + #verify that the non producing node is not alive (and populate the producer nodes with current getInfo data to report if + #an error occurs) + if nonProdNode.verifyAlive(): + Utils.errorExit("Expected the non-producing node to have shutdown.") - # *** Analyze the producers leading up to the block after killing the non-producing node *** + Print("Analyzing the producers leading up to the block after killing the non-producing node") firstDivergence=analyzeBPs(blockProducers0, blockProducers1, expectDivergence=True) # Nodes should not have diverged till the last block @@ -358,15 +362,11 @@ def getMinHeadAndLib(prodNodes): blockProducers0=[] blockProducers1=[] - #verify that the non producing node is not alive (and populate the producer nodes with current getInfo data to report if - #an error occurs) - if nonProdNode.verifyAlive(): - Utils.errorExit("Expected the non-producing node to have shutdown.") for prodNode in prodNodes: prodNode.getInfo() - # *** Track the blocks from the divergence till there are 10*12 blocks on one chain and 10*12+1 on the other *** + Print("Tracking the blocks from the divergence till there are 10*12 blocks on one chain and 10*12+1 on the other") killBlockNum=blockNum lastBlockNum=killBlockNum+(maxActiveProducers - 1)*inRowCountPerProducer+1 # allow 1st testnet group to produce just 1 more block than the 2nd @@ -377,7 +377,7 @@ def getMinHeadAndLib(prodNodes): blockProducers1.append({"blockNum":blockNum, "prod":blockProducer1}) - # *** Analyze the producers from the divergence to the lastBlockNum and verify they stay diverged *** + Print("Analyzing the producers from the divergence to the lastBlockNum and verify they stay diverged") firstDivergence=analyzeBPs(blockProducers0, blockProducers1, expectDivergence=True) if firstDivergence!=killBlockNum: @@ -386,13 +386,13 @@ def getMinHeadAndLib(prodNodes): blockProducers1=[] - # *** Relaunch the non-producing bridge node to connect the producing nodes again *** + Print("Relaunching the non-producing bridge node to connect the producing nodes again") if not nonProdNode.relaunch(nonProdNode.nodeNum, None): errorExit("Failure - (non-production) node %d should have restarted" % (nonProdNode.nodeNum)) - # *** Identify the producers from the saved LIB to the current highest head *** + Print("Identifying the producers from the saved LIB to the current highest head") #ensure that the nodes have enough time to get in concensus, so wait for 3 producers to produce their complete round time.sleep(inRowCountPerProducer * 3 / 2) @@ -407,7 +407,7 @@ def getMinHeadAndLib(prodNodes): blockProducers1.append({"blockNum":blockNum, "prod":blockProducer1}) - # *** Analyze the producers from the saved LIB to the current highest head and verify they match now *** + Print("Analyzing the producers from the saved LIB to the current highest head and verify they match now") analyzeBPs(blockProducers0, blockProducers1, expectDivergence=False) diff --git a/tests/nodeos_run_test.py b/tests/nodeos_run_test.py index 4196eb58a2b..1563450d81a 100755 --- a/tests/nodeos_run_test.py +++ b/tests/nodeos_run_test.py @@ -4,6 +4,7 @@ from Cluster import Cluster from WalletMgr import WalletMgr from Node import Node +from Node import ReturnType from TestHelper import TestHelper import decimal @@ -320,7 +321,7 @@ if hashNum != 0: errorExit("FAILURE - get code currency1111 failed", raw=True) - contractDir="contracts/eosio.token" + contractDir="unittests/contracts/eosio.token" wasmFile="eosio.token.wasm" abiFile="eosio.token.abi" Print("Publish contract") @@ -344,7 +345,7 @@ abiName=account["abi"]["structs"][0]["name"] abiActionName=account["abi"]["actions"][0]["name"] abiType=account["abi"]["actions"][0]["type"] - if abiName != "transfer" or abiActionName != "transfer" or abiType != "transfer": + if abiName != "account" or abiActionName != "close" or abiType != "close": errorExit("FAILURE - get EOS account failed", raw=True) Print("push create action to currency1111 contract") @@ -644,6 +645,12 @@ cmdError("%s wallet unlock test" % (ClientName)) errorExit("Failed to unlock wallet %s" % (testWallet.name)) + if not enableMongo: + Print("Verify non-JSON call works") + rawAccount=node.getEosAccount(defproduceraAccount.name, exitOnError=True, returnType=ReturnType.raw) + coreLiquidBalance=account['core_liquid_balance'] + match=re.search(r'\bliquid:\s*%s\s' % (coreLiquidBalance), rawAccount, re.MULTILINE | re.DOTALL) + assert match is not None, "did not find the core liquid balance (\"liquid:\") of %d in \"%s\"" % (coreLiquidBalance, rawAccount) Print("Get head block num.") currentBlockNum=node.getHeadBlockNum() diff --git a/tests/nodeos_under_min_avail_ram.py b/tests/nodeos_under_min_avail_ram.py index 040be402ca3..d4b4a859c14 100755 --- a/tests/nodeos_under_min_avail_ram.py +++ b/tests/nodeos_under_min_avail_ram.py @@ -135,7 +135,7 @@ def setName(self, num): nodes[0].transferFunds(cluster.eosioAccount, contractAccount, transferAmount, "test transfer") trans=nodes[0].delegatebw(contractAccount, 1000000.0000, 88000000.0000, waitForTransBlock=True, exitOnError=True) - contractDir="contracts/integration_test" + contractDir="unittests/test-contracts/integration_test" wasmFile="integration_test.wasm" abiFile="integration_test.abi" Print("Publish contract") diff --git a/tests/restart-scenarios-test.py b/tests/restart-scenarios-test.py index a8ae17d78b7..afb7a12ccdc 100755 --- a/tests/restart-scenarios-test.py +++ b/tests/restart-scenarios-test.py @@ -130,6 +130,14 @@ if not cluster.waitOnClusterSync(): errorExit("Cluster sync wait failed.") + if killEosInstances: + atLeastOne=False + for node in cluster.getNodes(): + if node.popenProc is not None: + atLeastOne=True + node.interruptAndVerifyExitStatus() + assert atLeastOne, "Test is setup to verify that a cleanly interrupted nodeos exits with an exit status of 0, but this test may no longer be setup to do that" + testSuccessful=True finally: TestHelper.shutdown(cluster, walletMgr, testSuccessful, killEosInstances, killEosInstances, keepLogs, killAll, dumpErrorDetails) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6b21397b7db..550b7543589 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,2 +1,3 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/llvm-gcov.sh ${CMAKE_CURRENT_BINARY_DIR}/llvm-gcov.sh COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ctestwrapper.sh ${CMAKE_CURRENT_BINARY_DIR}/ctestwrapper.sh COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/validate_reflection.py ${CMAKE_CURRENT_BINARY_DIR}/validate_reflection.py COPYONLY) diff --git a/tools/validate_reflection.py b/tools/validate_reflection.py index 52cae39bc30..a696fd61df6 100755 --- a/tools/validate_reflection.py +++ b/tools/validate_reflection.py @@ -50,7 +50,7 @@ def close_debug_file(): if args.debug: temp_dir = tempfile.mkdtemp() print("temporary files writen to %s" % (temp_dir)) - debug_file = open(os.path.join(temp_dir, "validate_reflect.debug"), "w") + debug_file = open(os.path.join(temp_dir, "validate_reflection.debug"), "w") else: debug_file = None extensions = [] @@ -66,14 +66,14 @@ def close_debug_file(): ignore_str = "@ignore" swap_str = "@swap" fc_reflect_str = "FC_REFLECT" -fc_reflect_possible_enum_ext = "(?:_ENUM)?" -fc_reflect_derived_ext = "(?:_DERIVED)" +fc_reflect_possible_enum_or_derived_ext = "(?:_ENUM|_DERIVED)?" def debug(debug_str): if debug_file is not None: debug_file.write(debug_str + "\n") class EmptyScope: + multi_word_type_pattern = r'(?:(?:un)?signed\s+)?(?:short\s+|(?:long\s+){1,2}?)?' single_comment_pattern = re.compile(r'//.*\n+') single_comment_ignore_swap_pattern = re.compile(r'//\s*(?:%s|%s)\s' % (ignore_str, swap_str)) multi_line_comment_pattern = re.compile(r'/\*(.*?)\*/', re.MULTILINE | re.DOTALL) @@ -81,6 +81,9 @@ class EmptyScope: strip_extra_pattern = re.compile(r'\n\s*\*\s*') invalid_chars_pattern = re.compile(r'([^\w\s,])') multi_line_comment_ignore_swap_pattern = re.compile(r'(\w+)(?:\s*,\s*)?') + handle_braces_initialization_swap_pattern = re.compile(r'(?:{|;)\s*([^{};=]*?)\s*{([^{};]*)}(?=\s*;)', re.MULTILINE | re.DOTALL) + # pattern to handle fields initialized with {} + possible_end_skip_initialization = re.compile(r'{[^;}]*}\s*;', re.MULTILINE | re.DOTALL) namespace_str = "namespace" struct_str = "struct" class_str = "class" @@ -91,21 +94,21 @@ class EmptyScope: def __init__(self, name, start, content, parent_scope): pname = parent_scope.name if parent_scope is not None else "" - debug("EmptyScope.__init__ %s %d - Parent %s" % (name, start, pname)) + self.indent = parent_scope.indent + " > " if parent_scope is not None else " > " + debug("%sEmptyScope.__init__ %s %d - Parent %s" % (self.indent, name, start, pname)) self.name = name self.content = content self.start = start self.current = start + 1 self.parent_scope = parent_scope self.end = len(content) - 1 if start == 0 else None - self.children = {} - self.children_ordered = [] + self.children = OrderedDict() self.fields = [] - self.usings = {} + self.usings = OrderedDict() self.inherit = None def read(self): - debug("EmptyScope(%s).read - %s" % (self.__class__.__name__, self.name)) + debug("%sEmptyScope(%s).read - %s starting at %s" % (self.indent, self.__class__.__name__, self.name, self.current)) end = len(self.content) - 1 while self.current < end: next_scope = self.next_scope() @@ -115,16 +118,17 @@ def read(self): if self.end is None: self.end = self.content.find(EmptyScope.end_char, self.current, len(self.content)) + debug("%sEmptyScope(%s).read - %s find end current: %s, end: %s" % (self.indent, self.__class__.__name__, self.name, self.current, self.end)) pdesc = str(self.parent_scope) if self.parent_scope is not None else "" assert self.end != -1, "Could not find \"%s\" in \"%s\" - parent scope - %s" % (EmptyScope.end_char, self.content[self.current:], pdesc) - debug("EmptyScope(%s).read - %s - Done at %s" % (self.__class__.__name__, self.name, self.end)) + debug("%sEmptyScope(%s).read - %s - Done at %s" % (self.indent, self.__class__.__name__, self.name, self.end)) def add(self, child): - debug("EmptyScope.add %s (%s) to %s (%s) - DROP" % (child.name, child.__class__.__name__, self.name, self.__class__.__name__)) + debug("%sEmptyScope.add %s (%s) to %s (%s) - DROP" % (self.indent, child.name, child.__class__.__name__, self.name, self.__class__.__name__)) pass def find_scope_start(self, content, start, end, find_str): - debug("EmptyScope.find_scope_start") + debug("%sEmptyScope.find_scope_start" % (self.indent)) loc = content.find(find_str, start, end) if loc == -1: return loc @@ -133,19 +137,28 @@ def find_scope_start(self, content, start, end, find_str): def find_possible_end(self): possible = self.content.find(EmptyScope.end_char, self.current) - debug("EmptyScope.find_possible_end current=%s possible end=%s" % (self.current, possible)) + possible_skip_init = EmptyScope.possible_end_skip_initialization.search(self.content[self.current:]) + if possible_skip_init: + all = possible_skip_init.group(0) + all_start = self.content.find(all, self.current) + all_end = all_start + len(all) + debug("%sEmptyScope.find_possible_end found possible at %s checking skip from %d to %d, all={\n%s\n}" % (self.indent, possible, all_start, all_end, all)) + if possible > all_start and possible < all_end: + possible = self.content.find(EmptyScope.end_char, all_end + 1) + debug("%sEmptyScope.find_possible_end current=%s possible end=%s" % (self.indent, self.current, possible)) return possible def next_scope(self, end = None): if end is None: end = self.find_possible_end() - debug("EmptyScope.next_scope current=%s end=%s" % (self.current, end)) + debug("%sEmptyScope.next_scope current=%s end=%s" % (self.indent, self.current, end)) match = EmptyScope.any_scope_pattern.search(self.content[self.current:end]) if match: start = self.find_scope_start(self.content, self.current, end, EmptyScope.start_char) new_scope = EmptyScope(None, start, self.content, self) new_scope.read() self.current = new_scope.end + 1 + debug("%sEmptyScope.next_scope return EmptyScope current: %s, scope end: %s" % (self.indent, self.current, new_scope.end)) return new_scope return None @@ -158,40 +171,40 @@ def find_class(self, scoped_name): loc += len(scope_separator) child_scoped_name = scoped_name[loc:] if child_name in self.children: - debug("find_class traverse child_name: %s, child_scoped_name: %s" % (child_name, child_scoped_name)) + debug("%sfind_class traverse child_name: %s, child_scoped_name: %s" % (self.indent, child_name, child_scoped_name)) return self.children[child_name].find_class(child_scoped_name) elif self.inherit is not None and scoped_name in self.inherit.children: - debug("find_class found scoped_name: %s in inherited: %s" % (scoped_name, self.inherit.name)) + debug("%sfind_class found scoped_name: %s in inherited: %s" % (self.indent, scoped_name, self.inherit.name)) return self.inherit.children[scoped_name].find_class(child_scoped_name) else: if scoped_name not in self.children: inherit_children = ",".join(self.inherit.children) if self.inherit is not None else "no inheritance" inherit_using = ",".join(self.inherit.usings) if self.inherit is not None else "no inheritance" inherit = self.inherit.name if self.inherit is not None else None - debug("find_class %s not in children, using: %s, inherit: %s - children: %s, using: %s" % (scoped_name, ",".join(self.usings), inherit, inherit_children, inherit_using)) + debug("%sfind_class %s not in children, using: %s, inherit: %s - children: %s, using: %s" % (self.indent, scoped_name, ",".join(self.usings), inherit, inherit_children, inherit_using)) if scoped_name in self.children: - debug("find_class found scoped_name: %s" % (scoped_name)) + debug("%sfind_class found scoped_name: %s" % (self.indent, scoped_name)) return self.children[scoped_name] elif scoped_name in self.usings: using = self.usings[scoped_name] - debug("find_class found scoped_name: %s, using: %s" % (scoped_name, using)) + debug("%sfind_class found scoped_name: %s, using: %s" % (self.indent, scoped_name, using)) return self.find_class(using) elif self.inherit is not None and scoped_name in self.inherit.children: - debug("find_class found scoped_name: %s in inherited: %s" % (scoped_name, self.inherit.name)) + debug("%sfind_class found scoped_name: %s in inherited: %s" % (self.indent, scoped_name, self.inherit.name)) return self.inherit.children[scoped_name] else: - debug("find_class could not find scoped_name: %s, children: %s" % (scoped_name, ",".join(self.children))) + debug("%sfind_class could not find scoped_name: %s, children: %s" % (self.indent, scoped_name, ",".join(self.children))) return None def __str__(self): indent = "" next = self.parent_scope while next is not None: - indent += " " + indent += " > " next = next.parent_scope desc = "%s%s scope type=\"%s\"\n%s children={\n" % (indent, self.name, self.__class__.__name__, indent) - for child in self.children_ordered: + for child in self.children: desc += str(self.children[child]) + "\n" desc += indent + " }\n" desc += indent + " fields={\n" @@ -205,7 +218,8 @@ def __str__(self): return desc def create_scope(type, name, inherit, start, content, parent_scope): - debug("create_scope") + indent = parent_scope.indent + " > " if parent_scope is not None else " > " + debug("%screate_scope" % (indent)) if type == EmptyScope.namespace_str: return Namespace(name, inherit, start, content, parent_scope) elif type == EmptyScope.class_str or type == EmptyScope.struct_str: @@ -216,17 +230,17 @@ def create_scope(type, name, inherit, start, content, parent_scope): assert False, "Script does not account for type = \"%s\" found in \"%s\"" % (type, content[start:]) class ClassStruct(EmptyScope): - field_pattern = re.compile(r'\n\s*?(?:mutable\s+)?(\w[\w:\d<>]*)\s+(\w+)\s*(?:=\s[^;]+;|;|=\s*{)', re.MULTILINE | re.DOTALL) - enum_field_pattern = re.compile(r'\n\s*?(\w+)\s*(?:=\s*[^,}\s]+)?\s*(?:,|})', re.MULTILINE | re.DOTALL) + field_pattern = re.compile(r'\n\s*?(?:mutable\s+)?(%s\w[\w:]*(?:\s*<\s*%s\w[\w:]*\s*(?:\s*<\s*%s\w[\w:]*\s*(?:\s*<\s*%s\w[\w:]*\s*(?:,\s*%s\w[\w:]*\s*)*>\s*)?(?:,\s*%s\w[\w:]*\s*(?:\s*<\s*%s\w[\w:]*\s*(?:,\s*%s\w[\w:]*\s*)*>\s*)?)?>\s*)?(?:,\s*%s\w[\w:]*\s*(?:\s*<\s*%s\w[\w:]*\s*(?:\s*<\s*%s\w[\w:]*\s*(?:,\s*%s\w[\w:]*\s*)*>\s*)?(?:,\s*%s\w[\w:]*\s*(?:\s*<\s*%s\w[\w:]*\s*(?:,\s*%s\w[\w:]*\s*)*>\s*)?)?>\s*)?)?>\s*)?)(?:\*\s+|\s+\*|\s+)(\w+)\s*(?:;|=\s*[-]?\w[\w:]*(?:\s*[-/\*\+]\s*[-]?\w[\w:]*)*\s*;|=\s*(?:\w[\w:]*(?:<[^\n;]>)?)?(?:{|(?:\([^\)]*\)?|(?:\"[^\"]*\")?)\s*;)|\s*{[^\}]*}\s*;)' % (EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern, EmptyScope.multi_word_type_pattern), re.MULTILINE | re.DOTALL) + enum_field_pattern = re.compile(r'[,\{]\s*?(\w+)\s*(?:=\s*[^,}\s]+)?\s*(?:,|})', re.MULTILINE | re.DOTALL) class_pattern = re.compile(r'(%s|%s|%s)\s+(\w+)\s*(:\s*public\s+([^<\s]+)[^{]*)?\s*\{' % (EmptyScope.struct_str, EmptyScope.class_str, EmptyScope.enum_str), re.MULTILINE | re.DOTALL) cb_obj_pattern = re.compile(r'chainbase::object$') obj_pattern = re.compile(r'^object$') using_pattern = re.compile(r'\n\s*?using\s+(\w+)\s*=\s*([\w:]+)(?:<.*>)?;') def __init__(self, name, inherit, start, content, parent_scope, is_enum): - debug("ClassStruct.__init__ %s %d" % (name, start)) EmptyScope.__init__(self, name, start, content, parent_scope) - self.classes = {} + debug("%sClassStruct.__init__ %s %d" % (self.indent, name, start)) + self.classes = OrderedDict() self.pattern = ClassStruct.class_pattern self.is_enum = is_enum self.inherit = None @@ -242,26 +256,28 @@ def __init__(self, name, inherit, start, content, parent_scope, is_enum): while self.inherit is None and next is not None: self.inherit = next.find_class(inherit) next = next.parent_scope - debug("Checking for object, ignore_id: %s, inherit: %s, name: %s" % (self.ignore_id, inherit, name)) + debug("%sChecking for object, ignore_id: %s, inherit: %s, name: %s" % (self.indent, self.ignore_id, inherit, name)) def add(self, child): - debug("ClassStruct.add %s (%s) to %s (%s)" % (child.name, child.__class__.__name__, self.name, self.__class__.__name__)) + debug("%sClassStruct.add %s (%s) to %s (%s) - (existing children: %s)" % (self.indent, child.name, child.__class__.__name__, self.name, self.__class__.__name__, ", ".join(self.children))) if isinstance(child, ClassStruct): - self.classes[child.name] = child - self.children[child.name] = child - self.children_ordered.append(child.name) + if child.name not in self.children: + self.classes[child.name] = child + self.children[child.name] = child def add_fields(self, start, end): - loc = start + loc = start - 1 if start > 0 else 0 while loc < end: - debug("ClassStruct.add_fields -{\n%s\n}" % (self.content[loc:end + 1])) + debug("%sClassStruct.add_fields -{\n%s\n}" % (self.indent, self.content[loc:end + 1])) if self.is_enum: loc = self.add_enum_field(loc, end) else: + debug("%sClassStruct.add_fields - add_field") loc = self.add_field(loc, end) - debug("ClassStruct.add_fields done") + debug("%sClassStruct.add_fields done" % (self.indent)) def add_field(self, loc, end): + debug("%sClassStruct.add_field - %s to %s (%s)" % (self.indent, loc, end + 1, len(self.content))) match = ClassStruct.field_pattern.search(self.content[loc:end + 1]) if match is None: return end @@ -269,7 +285,7 @@ def add_field(self, loc, end): self.fields.append(field) all = match.group(0) loc = self.content.find(all, loc) + len(all) - debug("ClassStruct.add_field - %s (%d) - %s" % (field, len(self.fields), ClassStruct.field_pattern.pattern)) + debug("%sClassStruct.add_field - %s (%d) - loc: %s, pattern: %s, matched: \"%s\"" % (self.indent, field, len(self.fields), loc, ClassStruct.field_pattern.pattern, all)) return loc def add_enum_field(self, loc, end): @@ -279,14 +295,14 @@ def add_enum_field(self, loc, end): field = match.group(1) self.fields.append(field) all = match.group(0) - loc = self.content.find(all, loc) + len(all) - debug("ClassStruct.add_enum_field - %s (%d) - %s" % (field, len(self.fields), ClassStruct.enum_field_pattern.pattern)) + loc = self.content.find(all, loc) + len(all) - 1 # back up one to not match ',' + debug("%sClassStruct.add_enum_field - %s (%d) - %s" % (self.indent, field, len(self.fields), ClassStruct.enum_field_pattern.pattern)) return loc def add_usings(self, start, end): loc = start while loc < end: - debug("ClassStruct.add_usings -{\n%s\n}" % (self.content[loc:end + 1])) + debug("%sClassStruct.add_usings -{\n%s\n}" % (self.indent, self.content[loc:end + 1])) match = ClassStruct.using_pattern.search(self.content[loc:end]) if match is None: break @@ -295,14 +311,14 @@ def add_usings(self, start, end): self.usings[using] = class_struct all = match.group(0) loc = self.content.find(all, loc) + len(all) - debug("ClassStruct.add_usings - %s (%d)" % (using, len(self.usings))) - debug("ClassStruct.add_usings done") + debug("%sClassStruct.add_usings - %s (%d)" % (self.indent, using, len(self.usings))) + debug("%sClassStruct.add_usings done" % (self.indent)) def next_scope(self, end = None): new_scope = None if end is None: end = self.find_possible_end() - debug("ClassStruct.next_scope end=%s on %s\n\npossible scope={\n\"%s\"\n\n\npattern=%s" % (end, self.name, self.content[self.current:end], self.pattern.pattern)) + debug("%sClassStruct.next_scope current=%s end=%s on %s\n\npossible scope={\n\"%s\"\n\n\npattern=%s" % (self.indent, self.current, end, self.name, self.content[self.current:end], self.pattern.pattern)) match = self.pattern.search(self.content[self.current:end]) start = -1 search_str = None @@ -310,29 +326,30 @@ def next_scope(self, end = None): name = None inherit = None if match: - debug("ClassStruct.next_scope match on %s" % (self.name)) + debug("%sClassStruct.next_scope match on %s" % (self.indent, self.name)) search_str = match.group(0) type = match.group(1) name = match.group(2) if len(match.groups()) >= 3: inherit = match.group(4) + debug("%sClassStruct.next_scope match for %s - type: %s, name: %s" % (self.indent, self.name, type, name)) start = self.find_scope_start(self.content, self.current, end, search_str) - debug("all: %s, type: %s, name: %s, start: %s, inherit: %s" % (search_str, type, name, start, inherit)) + debug("%sClassStruct.next_scope all: %s, type: %s, name: %s, start: %s, inherit: %s" % (self.indent, search_str, type, name, start, inherit)) generic_scope_start = self.find_scope_start(self.content, self.current, end, EmptyScope.start_char) if start == -1 and generic_scope_start == -1: - debug("ClassStruct.next_scope end=%s no scopes add_fields and exit" % (end)) + debug("%sClassStruct.next_scope end=%s no scopes add_fields and exit" % (self.indent, end)) self.add_fields(self.current, end) return None - debug("found \"%s\" - \"%s\" - \"%s\" current=%s, start=%s, end=%s, pattern=%s " % (search_str, type, name, self.current, start, end, self.pattern.pattern)) + debug("%sClassStruct.next_scope found \"%s\" - \"%s\" - \"%s\" current=%s, start=%s, end=%s, pattern=%s " % (self.indent, search_str, type, name, self.current, start, end, self.pattern.pattern)) # determine if there is a non-namespace/non-class/non-struct scope before a namespace/class/struct scope if start != -1 and (generic_scope_start == -1 or start <= generic_scope_start): - debug("found %s at %d" % (type, start)) + debug("%sClassStruct.next_scope found %s at %d" % (self.indent, type, start)) new_scope = create_scope(type, name, inherit, start, self.content, self) else: - debug("found EmptyScope (%s) at %d, next scope at %s" % (type, generic_scope_start, start)) + debug("%sClassStruct.next_scope found EmptyScope (%s) at %d, next scope at %s" % (self.indent, type, generic_scope_start, start)) new_scope = EmptyScope("", generic_scope_start, self.content, self) self.add_fields(self.current, new_scope.start) @@ -346,21 +363,21 @@ class Namespace(ClassStruct): namespace_class_pattern = re.compile(r'(%s|%s|%s|%s)\s+(\w+)\s*(:\s*public\s+([^<\s]+)[^{]*)?\s*\{' % (EmptyScope.namespace_str, EmptyScope.struct_str, EmptyScope.class_str, EmptyScope.enum_str), re.MULTILINE | re.DOTALL) def __init__(self, name, inherit, start, content, parent_scope): - debug("Namespace.__init__ %s %d" % (name, start)) assert inherit is None, "namespace %s should not inherit from %s" % (name, inherit) ClassStruct.__init__(self, name, None, start, content, parent_scope, is_enum = False) + debug("%sNamespace.__init__ %s %d" % (self.indent, name, start)) self.namespaces = {} self.pattern = Namespace.namespace_class_pattern def add(self, child): - debug("Namespace.add %s (%s) to %s (%s)" % (child.name, child.__class__.__name__, self.name, self.__class__.__name__)) + debug("%sNamespace.add %s (%s) to %s (%s)" % (self.indent, child.name, child.__class__.__name__, self.name, self.__class__.__name__)) if isinstance(child, ClassStruct): ClassStruct.add(self, child) return if isinstance(child, Namespace): - self.namespaces[child.name] = child - self.children[child.name] = child - self.children_ordered.append(child.name) + if child.name not in self.children: + self.namespaces[child.name] = child + self.children[child.name] = child class Reflection: def __init__(self, name): @@ -376,13 +393,15 @@ def __init__(self, content): self.current = 0 self.end = len(content) self.classes = OrderedDict() - self.with_2_comments = re.compile(r'(//\s*(%s|%s)\s+([^/]*?)\s*\n\s*//\s*(%s|%s)\s+([^/]*?)\s*\n\s*(%s%s\s*\(\s*(\w[^\s<]*))(?:<[^>]*>)?\s*,)' % (ignore_str, swap_str, ignore_str, swap_str, fc_reflect_str, fc_reflect_possible_enum_ext), re.MULTILINE | re.DOTALL) - self.with_comment = re.compile(r'(//\s*(%s|%s)\s+([^/]*?)\s*\n\s*(%s%s\s*\(\s*(\w[^\s<]*))(?:<[^>]*>)?\s*,)' % (ignore_str, swap_str, fc_reflect_str, fc_reflect_possible_enum_ext), re.MULTILINE | re.DOTALL) - self.reflect_pattern = re.compile(r'(\b(%s%s\s*\(\s*(\w[^\s<]*)(?:<[^>]*>)?\s*,)\s*(\(.*?\))\s*\))[^\)]*%s%s\b' % (fc_reflect_str, fc_reflect_possible_enum_ext, fc_reflect_str, fc_reflect_possible_enum_ext), re.MULTILINE | re.DOTALL) + self.with_2_comments = re.compile(r'(//\s*(%s|%s)\s+([^/\n]*?)\s*\n\s*//\s*(%s|%s)\s+([^/]*?)\s*\n\s*(%s%s\s*\(\s*(\w[^\s<]*))(?:\s*<[^>]*>)?\s*,)' % (ignore_str, swap_str, ignore_str, swap_str, fc_reflect_str, fc_reflect_possible_enum_or_derived_ext), re.MULTILINE | re.DOTALL) + self.with_comment = re.compile(r'(//\s*(%s|%s)\s+([^/]*?)\s*\n\s*(%s%s\s*\(\s*(\w[^\s<]*))(?:\s*<[^>]*>)?\s*,)' % (ignore_str, swap_str, fc_reflect_str, fc_reflect_possible_enum_or_derived_ext), re.MULTILINE | re.DOTALL) + self.reflect_pattern = re.compile(r'(\b(%s%s\s*\(\s*(\w[^\s<]*)(?:\s*<[^>]*>)?\s*)(,|,\s*\([^\(\)]+\)\s*,)\s*(\([^,]*?\))\s*\))[^\)]*%s%s\b' % (fc_reflect_str, fc_reflect_possible_enum_or_derived_ext, fc_reflect_str, fc_reflect_possible_enum_or_derived_ext), re.MULTILINE | re.DOTALL) + self.reflect_derived_pattern = re.compile(r',\s*\(\s*(.*)\s*\)\s*,', re.MULTILINE | re.DOTALL) self.field_pattern = re.compile(r'\(([^\)]+)\)', re.MULTILINE | re.DOTALL) self.ignore_swap_pattern = re.compile(r'\b([\w\d]+)\b', re.MULTILINE | re.DOTALL) def read(self): + debug("REMOVE reflect_pattern: \"%s\"" % (self.reflect_pattern.pattern)) while self.current < self.end: match_2_comments = self.with_2_comments.search(self.content[self.current:]) match_comment = self.with_comment.search(self.content[self.current:]) @@ -419,12 +438,12 @@ def read(self): debug(" %s" % g) debug("}") assert len(match_2_comments.groups()) == 7, "match_2_comments wrong size due to regex pattern change" - ignore_or_swap1 = match_2_comments[2] - next_reflect_ignore_swap1 = match_2_comments[3] - ignore_or_swap2 = match_2_comments[4] - next_reflect_ignore_swap2 = match_2_comments[5] - search_string_for_next_reflect_class = match_2_comments[6] - next_reflect_class = match_2_comments[7] + (ignore_or_swap1, + next_reflect_ignore_swap1, + ignore_or_swap2, + next_reflect_ignore_swap2, + search_string_for_next_reflect_class, + next_reflect_class) = match_2_comments.group(*range(2, 8)) self.add_ignore_swaps(next_reflect_class, next_reflect_ignore_swap1, ignore_or_swap1) self.add_ignore_swaps(next_reflect_class, next_reflect_ignore_swap2, ignore_or_swap2) elif match_comment: @@ -435,10 +454,10 @@ def read(self): debug("}") assert len(match_comment.groups()) == 5, "match_comment too short due to regex pattern change" # not using array indices here because for some reason the type of match_2_comments and match_comment are different - ignore_or_swap = match_comment.group(2) - next_reflect_ignore_swap = match_comment.group(3) - search_string_for_next_reflect_class = match_comment.group(4) - next_reflect_class = match_comment.group(5) + (ignore_or_swap, + next_reflect_ignore_swap, + search_string_for_next_reflect_class, + next_reflect_class) = match_comment.group(*range(2, 6)) self.add_ignore_swaps(next_reflect_class, next_reflect_ignore_swap, ignore_or_swap) if match_reflect: @@ -447,11 +466,21 @@ def read(self): for g in match_reflect.groups(): debug(" %s" % g) debug("}") - assert len(match_reflect.groups()) == 4, "match_reflect too short due to regex pattern change" - next_reflect = match_reflect.group(2) - next_reflect_class = match_reflect.group(3) - next_reflect_fields = match_reflect.group(4) - self.add_fields(next_reflect, next_reflect_class, next_reflect_fields) + assert len(match_reflect.groups()) == 5, "match_reflect too short due to regex pattern change" + (next_reflect, + next_reflect_class, + next_reflect_potential_derived, + next_reflect_fields) = match_reflect.group(*range(2, 6)) + derived = None + derived_match = self.reflect_derived_pattern.search(next_reflect_potential_derived) + if derived_match: + derived = derived_match.group(1) + debug("derived class: %s has its own reflection (%s)" % (derived, ",".join(self.classes))) + # if the derived class has its own reflection, then don't add the derived class + if derived in self.classes: + debug("derived class: %s has its own reflection, don't add" % (derived)) + derived = None + self.add_fields(next_reflect, next_reflect_class, next_reflect_fields, derived) else: debug("search for next reflect done") self.current = self.end @@ -463,13 +492,18 @@ def find_or_add(self, reflect_class): self.classes[reflect_class] = Reflection(reflect_class) return self.classes[reflect_class] - def add_fields(self, next_reflect, next_reflect_class, next_reflect_fields): + def add_fields(self, next_reflect, next_reflect_class, next_reflect_fields, derived): old = self.current self.current = self.content.find(next_reflect, self.current) + len(next_reflect) debug("all={\n\n%s\n\nclass=\n\n%s\n\nfields=\n\n%s\n\n" % (next_reflect, next_reflect_class, next_reflect_fields)) fields = re.findall(self.field_pattern, next_reflect_fields) for field in fields: self.add_field(next_reflect_class, field) + if derived: + struct_class = self.classes[derived] + assert struct_class is not None, "%s reflection macro indicates it is derived from %s, but that class/struct can not be found" % (next_reflect_class, derived) + for field in struct_class.fields: + self.add_field(next_reflect_class, field) reflect_class = self.find_or_add(next_reflect_class) debug("add_fields %s done, fields count=%s, ignored count=%s, swapped count=%s" % (next_reflect_class, len(reflect_class.fields), len(reflect_class.ignored), len(reflect_class.swapped))) @@ -483,7 +517,7 @@ def add_ignore_swaps(self, next_reflect_class, next_reflect_ignores_swaps, ignor ignore_swap = ignore_swap_match.group(1) reflect_class = self.find_or_add(next_reflect_class) if (ignore_or_swap == ignore_str): - assert ignore_swap not in reflect_class.ignored, "Reflection for %s repeats %s \"%s\"" % (next_reflect_class, ignore_or_swap) + assert ignore_swap not in reflect_class.ignored, "Reflection for %s repeats %s \"%s\"" % (next_reflect_class, ignore_or_swap, ignore_str) assert ignore_swap not in reflect_class.swapped, "Reflection for %s references field \"%s\" in %s and %s " % (next_reflect_class, ignore_swap, ignore_str, swap_str) reflect_class.ignored.append(ignore_swap) else: @@ -536,12 +570,28 @@ def replace_line_comment(match): else: return "\n" +def replace_braces_initialization(match): + all=match.group(0) + preamble = match.group(1) + init_data = match.group(2) + #check if preamble is the start of an enum declaration + match = ClassStruct.class_pattern.search(all) + if match is None: + repl = all.replace("{%s}" % (init_data), " = {%s}" % (init_data), 1) + debug("replace_braces_initialization replacing \"%s\" with \"%s\"." % (all, repl)) + return repl + debug("replace_braces_initialization matched \"%s\" so no replace." % (match.group(1))) + return all + def validate_file(file): - f = open(file, "r") + f = open(file, "r", encoding="utf-8") contents = "\n" + f.read() # lazy fix for complex regex f.close() + print("analyze %s" % (file)) + debug("analyze %s" % (file)) contents = EmptyScope.multi_line_comment_pattern.sub(replace_multi_line_comment, contents) contents = EmptyScope.single_comment_pattern.sub(replace_line_comment, contents) + contents = EmptyScope.handle_braces_initialization_swap_pattern.sub(replace_braces_initialization, contents) found = re.search(fc_reflect_str, contents) if found is None: return diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 6562505ced3..0d789225f6b 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -1,6 +1,29 @@ -#file(GLOB COMMON_SOURCES "common/*.cpp") - find_package( Gperftools QUIET ) + +### Build contracts with cdt if available +include(ExternalProject) +# if no cdt root is given use default path +if(EOSIO_CDT_ROOT STREQUAL "" OR NOT EOSIO_CDT_ROOT) + set(EOSIO_WASM_OLD_BEHAVIOR "Off") + find_package(eosio.cdt) +endif() + +if (eosio.cdt_FOUND) + ExternalProject_Add( + test_contracts_project + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test-contracts + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/test-contracts + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${EOSIO_CDT_ROOT}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DBoost_INCLUDE_DIRS=${Boost_INCLUDE_DIRS} + UPDATE_COMMAND "" + PATCH_COMMAND "" + TEST_COMMAND "" + INSTALL_COMMAND "" + BUILD_ALWAYS 1 + ) +else() + add_subdirectory(test-contracts) +endif() + if( GPERFTOOLS_FOUND ) message( STATUS "Found gperftools; compiling tests with TCMalloc") list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) @@ -15,20 +38,22 @@ set( CMAKE_CXX_STANDARD 14 ) add_subdirectory(contracts) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/config.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/include/config.hpp ESCAPE_QUOTES) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/contracts.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/include/contracts.hpp ESCAPE_QUOTES) file(GLOB UNIT_TESTS "*.cpp") add_executable( unit_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} ) target_link_libraries( unit_test eosio_chain chainbase eosio_testing fc ${PLATFORM_SPECIFIC_LIBS} ) +target_compile_options(unit_test PUBLIC -DDISABLE_EOSLIB_SERIALIZE) + target_include_directories( unit_test PUBLIC ${CMAKE_SOURCE_DIR}/libraries/testing/include - ${CMAKE_SOURCE_DIR}/contracts + ${CMAKE_SOURCE_DIR}/test-contracts ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_SOURCE_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/include ) -add_dependencies(unit_test asserter test_api test_api_mem test_api_db test_ram_limit test_api_multi_index eosio.token proxy identity identity_test stltest eosio.system eosio.token eosio.bios multi_index_test noop eosio.msig payloadless tic_tac_toe deferred_test snapshot_test) #Manually run unit_test for all supported runtimes #To run unit_test with all log from blockchain displayed, put --verbose after --, i.e. unit_test -- --verbose diff --git a/unittests/abi_tests.cpp b/unittests/abi_tests.cpp index f611fe768ce..440ec5acbfc 100644 --- a/unittests/abi_tests.cpp +++ b/unittests/abi_tests.cpp @@ -2460,6 +2460,30 @@ BOOST_AUTO_TEST_CASE(abi_serialize_json_mismatching_type) } FC_LOG_AND_RETHROW() } +// it is a bit odd to have an empty name for a field, but json seems to allow it +BOOST_AUTO_TEST_CASE(abi_serialize_json_empty_name) +{ + using eosio::testing::fc_exception_message_is; + + auto abi = R"({ + "version": "eosio::abi/1.0", + "structs": [ + {"name": "s1", "base": "", "fields": [ + {"name": "", "type": "int8"}, + ]} + ], + })"; + + try { + abi_serializer abis( fc::json::from_string(abi).as(), max_serialization_time ); + + auto bin = abis.variant_to_binary("s1", fc::json::from_string(R"({"":1})"), max_serialization_time); + + verify_round_trip_conversion(abis, "s1", R"({"":1})", "01"); + + } FC_LOG_AND_RETHROW() +} + BOOST_AUTO_TEST_CASE(abi_serialize_detailed_error_messages) { using eosio::testing::fc_exception_message_is; diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 89c94d6f393..909dd061160 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -39,16 +39,76 @@ #include #include -#include -#include -#include -#include +#include -#include -#include +#define DUMMY_ACTION_DEFAULT_A 0x45 +#define DUMMY_ACTION_DEFAULT_B 0xab11cd1244556677 +#define DUMMY_ACTION_DEFAULT_C 0x7451ae12 -#define DISABLE_EOSLIB_SERIALIZE -#include +static constexpr unsigned int DJBH(const char* cp) +{ + unsigned int hash = 5381; + while (*cp) + hash = 33 * hash ^ (unsigned char) *cp++; + return hash; +} + +static constexpr unsigned long long WASM_TEST_ACTION(const char* cls, const char* method) +{ + return static_cast(DJBH(cls)) << 32 | static_cast(DJBH(method)); +} + +struct dummy_action { + static uint64_t get_name() { + return N(dummyaction); + } + static uint64_t get_account() { + return N(testapi); + } + + char a; //1 + uint64_t b; //8 + int32_t c; //4 +}; + +struct u128_action { + unsigned __int128 values[3]; //16*3 +}; + +struct cf_action { + static uint64_t get_name() { + return N(cfaction); + } + static uint64_t get_account() { + return N(testapi); + } + + uint32_t payload = 100; + uint32_t cfd_idx = 0; // context free data index +}; + +// Deferred Transaction Trigger Action +struct dtt_action { + static uint64_t get_name() { + return WASM_TEST_ACTION("test_transaction", "send_deferred_tx_with_dtt_action"); + } + static uint64_t get_account() { + return N(testapi); + } + + uint64_t payer = N(testapi); + uint64_t deferred_account = N(testapi); + uint64_t deferred_action = WASM_TEST_ACTION("test_transaction", "deferred_print"); + uint64_t permission_name = N(active); + uint32_t delay_sec = 2; +}; + +struct invalid_access_action { + uint64_t code; + uint64_t val; + uint32_t index; + bool store; +}; FC_REFLECT( dummy_action, (a)(b)(c) ) FC_REFLECT( u128_action, (values) ) @@ -174,8 +234,10 @@ transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, test.set_transaction_headers(trx, test.DEFAULT_EXPIRATION_DELTA); auto sigs = trx.sign(test.get_private_key(scope[0], "active"), test.control->get_chain_id()); + flat_set keys; trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); + auto res = test.push_transaction(trx); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); test.produce_block(); @@ -247,15 +309,15 @@ BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { create_account( N(testapi) ); create_account( N(testapi2) ); produce_blocks(10); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); auto res = CALL_TEST_FUNCTION( *this, "test_action", "assert_true", {}); BOOST_REQUIRE_EQUAL(uint32_t(res->action_traces[0].receipt.code_sequence), 1); BOOST_REQUIRE_EQUAL(uint32_t(res->action_traces[0].receipt.abi_sequence), 0); - set_code( N(testapi), test_api_db_wast ); - set_code( config::system_account_name, test_api_db_wast ); + set_code( N(testapi), contracts::test_api_db_wasm() ); + set_code( config::system_account_name, contracts::test_api_db_wasm() ); res = CALL_TEST_FUNCTION( *this, "test_db", "primary_i64_general", {}); BOOST_REQUIRE_EQUAL(uint32_t(res->action_traces[0].receipt.code_sequence), 2); BOOST_REQUIRE_EQUAL(uint32_t(res->action_traces[0].receipt.abi_sequence), 0); @@ -276,11 +338,11 @@ BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { BOOST_REQUIRE_EQUAL(uint32_t(res->action_traces[0].receipt.code_sequence), 2); BOOST_REQUIRE_EQUAL(uint32_t(res->action_traces[0].receipt.abi_sequence), 1); } - set_code( config::system_account_name, eosio_bios_wast ); + set_code( config::system_account_name, contracts::eosio_bios_wasm() ); - set_code( N(testapi), eosio_bios_wast ); - set_abi(N(testapi), eosio_bios_abi); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::eosio_bios_wasm() ); + set_abi(N(testapi), contracts::eosio_bios_abi().data() ); + set_code( N(testapi), contracts::test_api_wasm() ); res = CALL_TEST_FUNCTION( *this, "test_action", "assert_true", {}); BOOST_REQUIRE_EQUAL(uint32_t(res->action_traces[0].receipt.code_sequence), 4); BOOST_REQUIRE_EQUAL(uint32_t(res->action_traces[0].receipt.abi_sequence), 1); @@ -298,7 +360,7 @@ BOOST_FIXTURE_TEST_CASE(action_tests, TESTER) { try { create_account( N(acc3) ); create_account( N(acc4) ); produce_blocks(10); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); // test assert_true @@ -352,6 +414,7 @@ BOOST_FIXTURE_TEST_CASE(action_tests, TESTER) { try { auto res = test.push_transaction(trx); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); }; + BOOST_CHECK_EXCEPTION(test_require_notice(*this, raw_bytes, scope), unsatisfied_authorization, [](const unsatisfied_authorization& e) { return expect_assert_message(e, "transaction declares authority"); @@ -415,14 +478,15 @@ BOOST_FIXTURE_TEST_CASE(action_tests, TESTER) { try { produce_block(); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_action", "test_current_time", fc::raw::pack(now) ), eosio_assert_message_exception, eosio_assert_message_is("tmp == current_time()") ); - + // test test_current_receiver CALL_TEST_FUNCTION( *this, "test_action", "test_current_receiver", fc::raw::pack(N(testapi))); - + // test send_action_sender CALL_TEST_FUNCTION( *this, "test_transaction", "send_action_sender", fc::raw::pack(N(testapi))); + produce_block(); - + // test_publication_time uint64_t pub_time = static_cast( control->head_block_time().time_since_epoch().count() ); pub_time += config::block_interval_us; @@ -446,8 +510,8 @@ BOOST_FIXTURE_TEST_CASE(require_notice_tests, TESTER) { try { create_account( N(testapi) ); create_account( N(acc5) ); produce_blocks(1); - set_code( N(testapi), test_api_wast ); - set_code( N(acc5), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); + set_code( N(acc5), contracts::test_api_wasm() ); produce_blocks(1); // test require_notice @@ -469,9 +533,9 @@ BOOST_FIXTURE_TEST_CASE(ram_billing_in_notify_tests, TESTER) { try { create_account( N(testapi) ); create_account( N(testapi2) ); produce_blocks(10); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); - set_code( N(testapi2), test_api_wast ); + set_code( N(testapi2), contracts::test_api_wasm() ); produce_blocks(1); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_action", "test_ram_billing_in_notify", fc::raw::pack( ((unsigned __int128)N(testapi2) << 64) | N(testapi) ) ), @@ -493,7 +557,7 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { create_account( N(testapi) ); create_account( N(dummy) ); produce_blocks(10); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); cf_action cfa; signed_transaction trx; @@ -504,16 +568,13 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { return expect_assert_message(e, "transaction must have at least one authorization"); } ); - + action act({}, cfa); trx.context_free_actions.push_back(act); trx.context_free_data.emplace_back(fc::raw::pack(100)); // verify payload matches context free data trx.context_free_data.emplace_back(fc::raw::pack(200)); set_transaction_headers(trx); - - // signing a transaction with only context_free_actions should not be allowed - // auto sigs = trx.sign(get_private_key(N(testapi), "active"), control->get_chain_id()); - + BOOST_CHECK_EXCEPTION(push_transaction(trx), tx_no_auths, [](const fc::exception& e) { return expect_assert_message(e, "transaction must have at least one authorization"); @@ -621,7 +682,7 @@ BOOST_FIXTURE_TEST_CASE(cfa_stateful_api, TESTER) try { create_account( N(testapi) ); produce_blocks(1); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); account_name a = N(testapi2); account_name creator = config::system_account_name; @@ -651,7 +712,7 @@ BOOST_FIXTURE_TEST_CASE(deferred_cfa_failed, TESTER) try { create_account( N(testapi) ); produce_blocks(1); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); account_name a = N(testapi2); account_name creator = config::system_account_name; @@ -687,7 +748,7 @@ BOOST_FIXTURE_TEST_CASE(deferred_cfa_success, TESTER) try { create_account( N(testapi) ); produce_blocks(1); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); account_name a = N(testapi2); account_name creator = config::system_account_name; @@ -728,7 +789,7 @@ BOOST_FIXTURE_TEST_CASE(checktime_pass_tests, TESTER) { try { produce_blocks(2); create_account( N(testapi) ); produce_blocks(10); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); // test checktime_pass @@ -738,15 +799,15 @@ BOOST_FIXTURE_TEST_CASE(checktime_pass_tests, TESTER) { try { } FC_LOG_AND_RETHROW() } template -void call_test(TESTER& test, T ac, uint32_t billed_cpu_time_us , uint32_t max_cpu_usage_ms = 200 ) { +void call_test(TESTER& test, T ac, uint32_t billed_cpu_time_us , uint32_t max_cpu_usage_ms = 200, std::vector payload = {} ) { signed_transaction trx; auto pl = vector{{N(testapi), config::active_name}}; action act(pl, ac); + act.data = payload; trx.actions.push_back(act); test.set_transaction_headers(trx); - //trx.max_cpu_usage_ms = max_cpu_usage_ms; auto sigs = trx.sign(test.get_private_key(N(testapi), "active"), test.control->get_chain_id()); flat_set keys; trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); @@ -762,7 +823,7 @@ BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try { ilog( "create account" ); t.create_account( N(testapi) ); ilog( "set code" ); - t.set_code( N(testapi), test_api_wast ); + t.set_code( N(testapi), contracts::test_api_wasm() ); ilog( "produce block" ); t.produce_blocks(1); @@ -773,11 +834,11 @@ BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try { #warning TODO call the contract before testing to cache it, and validate that it was cached BOOST_CHECK_EXCEPTION( call_test( t, test_api_action{}, - 5000 ), + 5000, 200, fc::raw::pack(10000000000000000000ULL) ), deadline_exception, is_deadline_exception ); BOOST_CHECK_EXCEPTION( call_test( t, test_api_action{}, - 0 ), + 0, 200, fc::raw::pack(10000000000000000000ULL) ), tx_cpu_usage_exceeded, is_tx_cpu_usage_exceeded ); uint32_t time_left_in_block_us = config::default_max_block_cpu_usage - config::default_min_transaction_cpu_usage; @@ -788,7 +849,7 @@ BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try { time_left_in_block_us -= increment; } BOOST_CHECK_EXCEPTION( call_test( t, test_api_action{}, - 0 ), + 0, 200, fc::raw::pack(10000000000000000000ULL) ), block_cpu_usage_exceeded, is_block_cpu_usage_exceeded ); BOOST_REQUIRE_EQUAL( t.validate(), true ); @@ -858,7 +919,7 @@ BOOST_FIXTURE_TEST_CASE(checktime_hashing_fail, TESTER) { try { produce_blocks(2); create_account( N(testapi) ); produce_blocks(10); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); //hit deadline exception, but cache the contract @@ -911,7 +972,7 @@ BOOST_FIXTURE_TEST_CASE(compiler_builtins_tests, TESTER) { try { produce_blocks(2); create_account( N(testapi) ); produce_blocks(10); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); // test test_multi3 @@ -970,7 +1031,7 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { produce_blocks(2); create_account( N(testapi) ); produce_blocks(100); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); // test for zero auth @@ -980,7 +1041,7 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { action act({}, tm); trx.actions.push_back(act); - set_transaction_headers(trx); + set_transaction_headers(trx); BOOST_CHECK_EXCEPTION(push_transaction(trx), transaction_exception, [](const fc::exception& e) { return expect_assert_message(e, "transaction must have at least one authorization"); @@ -1036,6 +1097,8 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { // this is a bit rough, but I couldn't figure out a better way to compare the hashes auto tx_trace = CALL_TEST_FUNCTION( *this, "test_transaction", "test_read_transaction", {} ); string sha_expect = tx_trace->id; + BOOST_TEST_MESSAGE( "tx_trace->action_traces.front().console: = " << tx_trace->action_traces.front().console ); + BOOST_TEST_MESSAGE( "sha_expect = " << sha_expect ); BOOST_CHECK_EQUAL(tx_trace->action_traces.front().console == sha_expect, true); // test test_tapos_block_num CALL_TEST_FUNCTION(*this, "test_transaction", "test_tapos_block_num", fc::raw::pack(control->head_block_num()) ); @@ -1056,8 +1119,8 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { produce_blocks(2); create_accounts( {N(testapi), N(testapi2), N(alice)} ); - set_code( N(testapi), test_api_wast ); - set_code( N(testapi2), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); + set_code( N(testapi2), contracts::test_api_wasm() ); produce_blocks(1); //schedule @@ -1277,7 +1340,7 @@ BOOST_FIXTURE_TEST_CASE(chain_tests, TESTER) { try { create_accounts( producers ); set_producers (producers ); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(100); vector prods( control->active_producers().producers.size() ); @@ -1298,8 +1361,8 @@ BOOST_FIXTURE_TEST_CASE(db_tests, TESTER) { try { create_account( N(testapi) ); create_account( N(testapi2) ); produce_blocks(10); - set_code( N(testapi), test_api_db_wast ); - set_code( N(testapi2), test_api_db_wast ); + set_code( N(testapi), contracts::test_api_db_wasm() ); + set_code( N(testapi2), contracts::test_api_db_wasm() ); produce_blocks(1); CALL_TEST_FUNCTION( *this, "test_db", "primary_i64_general", {}); @@ -1385,7 +1448,7 @@ BOOST_FIXTURE_TEST_CASE(multi_index_tests, TESTER) { try { produce_blocks(1); create_account( N(testapi) ); produce_blocks(1); - set_code( N(testapi), test_api_multi_index_wast ); + set_code( N(testapi), contracts::test_api_multi_index_wasm() ); produce_blocks(1); CALL_TEST_FUNCTION( *this, "test_multi_index", "idx64_general", {}); @@ -1449,7 +1512,7 @@ BOOST_FIXTURE_TEST_CASE(fixedpoint_tests, TESTER) { try { produce_blocks(2); create_account( N(testapi) ); produce_blocks(10); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(10); CALL_TEST_FUNCTION( *this, "test_fixedpoint", "create_instances", {}); @@ -1470,7 +1533,7 @@ BOOST_FIXTURE_TEST_CASE(crypto_tests, TESTER) { try { produce_blocks(1000); create_account(N(testapi) ); produce_blocks(1000); - set_code(N(testapi), test_api_wast); + set_code(N(testapi), contracts::test_api_wasm() ); produce_blocks(1000); { signed_transaction trx; @@ -1488,13 +1551,18 @@ BOOST_FIXTURE_TEST_CASE(crypto_tests, TESTER) { try { payload.insert( payload.end(), pk.begin(), pk.end() ); payload.insert( payload.end(), sigs.begin(), sigs.end() ); + //No Error Here CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key", payload ); + return; + // Error Here CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key_assert_true", payload ); payload[payload.size()-1] = 0; BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_crypto", "test_recover_key_assert_false", payload ), crypto_api_exception, fc_exception_message_is("Error expected key different than recovered key") ); } + + CALL_TEST_FUNCTION( *this, "test_crypto", "test_sha1", {} ); CALL_TEST_FUNCTION( *this, "test_crypto", "test_sha256", {} ); CALL_TEST_FUNCTION( *this, "test_crypto", "test_sha512", {} ); @@ -1506,7 +1574,7 @@ BOOST_FIXTURE_TEST_CASE(crypto_tests, TESTER) { try { CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_crypto", "assert_sha256_false", {}, crypto_api_exception, "hash mismatch" ); - + CALL_TEST_FUNCTION( *this, "test_crypto", "assert_sha256_true", {} ); CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_crypto", "assert_sha1_false", {}, @@ -1535,9 +1603,9 @@ BOOST_FIXTURE_TEST_CASE(memory_tests, TESTER) { try { produce_blocks(1000); create_account(N(testapi) ); produce_blocks(1000); - set_code(N(testapi), test_api_mem_wast); + set_code(N(testapi), contracts::test_api_mem_wasm() ); produce_blocks(1000); - + CALL_TEST_FUNCTION( *this, "test_memory", "test_memory_allocs", {} ); produce_blocks(1000); CALL_TEST_FUNCTION( *this, "test_memory", "test_memory_hunk", {} ); @@ -1599,7 +1667,7 @@ BOOST_FIXTURE_TEST_CASE(extended_memory_test_initial_memory, TESTER) { try { produce_blocks(1000); create_account(N(testapi) ); produce_blocks(1000); - set_code(N(testapi), test_api_mem_wast); + set_code(N(testapi), contracts::test_api_mem_wasm() ); produce_blocks(1000); CALL_TEST_FUNCTION( *this, "test_extended_memory", "test_initial_buffer", {} ); @@ -1610,7 +1678,7 @@ BOOST_FIXTURE_TEST_CASE(extended_memory_test_page_memory, TESTER) { try { produce_blocks(1000); create_account(N(testapi) ); produce_blocks(1000); - set_code(N(testapi), test_api_mem_wast); + set_code(N(testapi), contracts::test_api_mem_wasm() ); produce_blocks(1000); CALL_TEST_FUNCTION( *this, "test_extended_memory", "test_page_memory", {} ); @@ -1621,7 +1689,7 @@ BOOST_FIXTURE_TEST_CASE(extended_memory_test_page_memory_exceeded, TESTER) { try produce_blocks(1000); create_account(N(testapi) ); produce_blocks(1000); - set_code(N(testapi), test_api_mem_wast); + set_code(N(testapi), contracts::test_api_mem_wasm() ); produce_blocks(1000); CALL_TEST_FUNCTION( *this, "test_extended_memory", "test_page_memory_exceeded", {} ); @@ -1632,7 +1700,7 @@ BOOST_FIXTURE_TEST_CASE(extended_memory_test_page_memory_negative_bytes, TESTER) produce_blocks(1000); create_account(N(testapi) ); produce_blocks(1000); - set_code(N(testapi), test_api_mem_wast); + set_code(N(testapi), contracts::test_api_mem_wasm() ); produce_blocks(1000); CALL_TEST_FUNCTION( *this, "test_extended_memory", "test_page_memory_negative_bytes", {} ); @@ -1647,7 +1715,7 @@ BOOST_FIXTURE_TEST_CASE(print_tests, TESTER) { try { create_account(N(testapi) ); produce_blocks(1000); - set_code(N(testapi), test_api_wast); + set_code(N(testapi), contracts::test_api_wasm() ); produce_blocks(1000); string captured = ""; @@ -1679,14 +1747,26 @@ BOOST_FIXTURE_TEST_CASE(print_tests, TESTER) { try { // test printn auto tx5_trace = CALL_TEST_FUNCTION( *this, "test_print", "test_printn", {} ); auto tx5_act_cnsl = tx5_trace->action_traces.front().console; - BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(0,5), "abcde" ); - BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(5, 5), "ab.de" ); - BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(10, 6), "1q1q1q"); - BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(16, 11), "abcdefghijk"); - BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(27, 12), "abcdefghijkl"); - BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(39, 13), "abcdefghijkl1"); - BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(52, 13), "abcdefghijkl1"); - BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(65, 13), "abcdefghijkl1"); + + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(0,1), "1" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(1,1), "5" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(2,1), "a" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(3,1), "z" ); + + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(4,3), "abc" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(7,3), "123" ); + + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(10,7), "abc.123" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(17,7), "123.abc" ); + + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(24,13), "12345abcdefgj" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(37,13), "ijklmnopqrstj" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(50,13), "vwxyz.12345aj" ); + + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(63, 13), "111111111111j" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(76, 13), "555555555555j" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(89, 13), "aaaaaaaaaaaaj" ); + BOOST_CHECK_EQUAL( tx5_act_cnsl.substr(102,13), "zzzzzzzzzzzzj" ); // test printi128 auto tx6_trace = CALL_TEST_FUNCTION( *this, "test_print", "test_printi128", {} ); @@ -1761,13 +1841,12 @@ BOOST_FIXTURE_TEST_CASE(types_tests, TESTER) { try { create_account( N(testapi) ); produce_blocks(1000); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1000); CALL_TEST_FUNCTION( *this, "test_types", "types_size", {}); CALL_TEST_FUNCTION( *this, "test_types", "char_to_symbol", {}); CALL_TEST_FUNCTION( *this, "test_types", "string_to_name", {}); - CALL_TEST_FUNCTION( *this, "test_types", "name_class", {}); BOOST_REQUIRE_EQUAL( validate(), true ); } FC_LOG_AND_RETHROW() } @@ -1780,7 +1859,7 @@ BOOST_FIXTURE_TEST_CASE(permission_tests, TESTER) { try { create_account( N(testapi) ); produce_blocks(1); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); auto get_result_int64 = [&]() -> int64_t { @@ -1862,21 +1941,7 @@ BOOST_FIXTURE_TEST_CASE(permission_tests, TESTER) { try { }) ); BOOST_CHECK_EQUAL( int64_t(0), get_result_int64() ); - - /* - BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION( *this, "test_permission", "check_authorization", - fc::raw::pack( check_auth { - .account = N(testapi), - .permission = N(noname), - .pubkeys = { - get_public_key(N(testapi), "active") - } - })), fc::exception, - [](const fc::exception& e) { - return expect_assert_message(e, "unknown key"); - } - ); - */ + } FC_LOG_AND_RETHROW() } #if 0 @@ -1888,7 +1953,7 @@ BOOST_FIXTURE_TEST_CASE(privileged_tests, tester) { try { create_account( N(testapi) ); create_account( N(acc1) ); produce_blocks(100); - set_code( N(testapi), test_api_wast ); + set_code( N(testapi), contracts::test_api_wasm() ); produce_blocks(1); { @@ -1950,7 +2015,7 @@ BOOST_FIXTURE_TEST_CASE(datastream_tests, TESTER) { try { produce_blocks(1000); create_account(N(testapi) ); produce_blocks(1000); - set_code(N(testapi), test_api_wast); + set_code(N(testapi), contracts::test_api_wasm() ); produce_blocks(1000); CALL_TEST_FUNCTION( *this, "test_datastream", "test_basic", {} ); @@ -1966,7 +2031,7 @@ BOOST_FIXTURE_TEST_CASE(new_api_feature_tests, TESTER) { try { produce_blocks(1); create_account(N(testapi) ); produce_blocks(1); - set_code(N(testapi), test_api_wast); + set_code(N(testapi), contracts::test_api_wasm() ); produce_blocks(1); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_transaction", "new_feature", {} ), @@ -2004,7 +2069,7 @@ BOOST_FIXTURE_TEST_CASE(permission_usage_tests, TESTER) { try { produce_block(); create_accounts( {N(testapi), N(alice), N(bob)} ); produce_block(); - set_code(N(testapi), test_api_wast); + set_code(N(testapi), contracts::test_api_wasm() ); produce_block(); push_reqauth( N(alice), {{N(alice), config::active_name}}, {get_private_key(N(alice), "active")} ); @@ -2085,7 +2150,7 @@ BOOST_FIXTURE_TEST_CASE(account_creation_time_tests, TESTER) { try { produce_block(); create_account( N(testapi) ); produce_block(); - set_code(N(testapi), test_api_wast); + set_code(N(testapi), contracts::test_api_wasm() ); produce_block(); create_account( N(alice) ); @@ -2112,7 +2177,7 @@ BOOST_FIXTURE_TEST_CASE(eosio_assert_code_tests, TESTER) { try { produce_block(); create_account( N(testapi) ); produce_block(); - set_code(N(testapi), test_api_wast); + set_code(N(testapi), contracts::test_api_wasm() ); const char* abi_string = R"=====( { diff --git a/unittests/auth_tests.cpp b/unittests/auth_tests.cpp index e54964b87b4..c0566654824 100644 --- a/unittests/auth_tests.cpp +++ b/unittests/auth_tests.cpp @@ -490,7 +490,7 @@ BOOST_AUTO_TEST_CASE( linkauth_special ) { try { chain.create_account(N(tester)); chain.create_account(N(tester2)); chain.produce_blocks(); - + chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") ("permission", "first") diff --git a/unittests/block_tests.cpp b/unittests/block_tests.cpp index 76e5746e1fa..89aceda3ff0 100644 --- a/unittests/block_tests.cpp +++ b/unittests/block_tests.cpp @@ -2,7 +2,6 @@ * @file * @copyright defined in eos/LICENSE */ - #include #include diff --git a/unittests/block_timestamp_tests.cpp b/unittests/block_timestamp_tests.cpp index 5cf998a85aa..d7f9b1289c4 100644 --- a/unittests/block_timestamp_tests.cpp +++ b/unittests/block_timestamp_tests.cpp @@ -2,17 +2,16 @@ * @file * @copyright defined in eos/LICENSE */ +#include #include -#include + #include #include using namespace eosio; using namespace chain; - - BOOST_AUTO_TEST_SUITE(block_timestamp_tests) diff --git a/unittests/bootseq_tests.cpp b/unittests/bootseq_tests.cpp index 05b0f050951..b12978961a2 100644 --- a/unittests/bootseq_tests.cpp +++ b/unittests/bootseq_tests.cpp @@ -1,19 +1,18 @@ -#include -#include +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #include - -#include -#include -// These contracts are still under dev -#include -#include -#include -#include +#include #include #include +#include + +#include + #ifdef NON_VALIDATING_TEST #define TESTER tester #else @@ -34,10 +33,10 @@ struct genesis_account { }; std::vector test_genesis( { - {N(b1), 100'000'000'0000ll}, - {N(whale4), 40'000'000'0000ll}, - {N(whale3), 30'000'000'0000ll}, - {N(whale2), 20'000'000'0000ll}, + {N(b1), 100'000'000'0000ll}, + {N(whale4), 40'000'000'0000ll}, + {N(whale3), 30'000'000'0000ll}, + {N(whale2), 20'000'000'0000ll}, {N(proda), 1'000'000'0000ll}, {N(prodb), 1'000'000'0000ll}, {N(prodc), 1'000'000'0000ll}, @@ -59,23 +58,37 @@ std::vector test_genesis( { {N(prods), 1'000'000'0000ll}, {N(prodt), 1'000'000'0000ll}, {N(produ), 1'000'000'0000ll}, - {N(runnerup1),1'000'000'0000ll}, - {N(runnerup2),1'000'000'0000ll}, - {N(runnerup3),1'000'000'0000ll}, - {N(minow1), 100'0000ll}, - {N(minow2), 1'0000ll}, - {N(minow3), 1'0000ll}, - {N(masses),800'000'000'0000ll} + {N(runnerup1), 1'000'000'0000ll}, + {N(runnerup2), 1'000'000'0000ll}, + {N(runnerup3), 1'000'000'0000ll}, + {N(minow1), 100'0000ll}, + {N(minow2), 1'0000ll}, + {N(minow3), 1'0000ll}, + {N(masses), 800'000'000'0000ll} }); class bootseq_tester : public TESTER { public: + void deploy_contract( bool call_init = true ) { + set_code( config::system_account_name, contracts::eosio_system_wasm() ); + set_abi( config::system_account_name, contracts::eosio_system_abi().data() ); + if( call_init ) { + base_tester::push_action(config::system_account_name, N(init), + config::system_account_name, mutable_variant_object() + ("version", 0) + ("core", CORE_SYM_STR) + ); + } + const auto& accnt = control->db().get( config::system_account_name ); + abi_def abi; + BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); + abi_ser.set_abi(abi, abi_serializer_max_time); + } fc::variant get_global_state() { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global), N(global) ); if (data.empty()) std::cout << "\nData is empty\n" << std::endl; return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state", data, abi_serializer_max_time ); - } auto buyram( name payer, name receiver, asset ram ) { @@ -157,9 +170,9 @@ class bootseq_tester : public TESTER { return get_currency_balance(N(eosio.token), symbol(CORE_SYMBOL), act); } - void set_code_abi(const account_name& account, const char* wast, const char* abi, const private_key_type* signer = nullptr) { + void set_code_abi(const account_name& account, const vector& wasm, const char* abi, const private_key_type* signer = nullptr) { wdump((account)); - set_code(account, wast, signer); + set_code(account, wasm, signer); set_abi(account, abi, signer); if (account == config::system_account_name) { const auto& accnt = control->db().get( account ); @@ -181,13 +194,19 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) { // Create eosio.msig and eosio.token create_accounts({N(eosio.msig), N(eosio.token), N(eosio.ram), N(eosio.ramfee), N(eosio.stake), N(eosio.vpay), N(eosio.bpay), N(eosio.saving) }); - // Set code for the following accounts: // - eosio (code: eosio.bios) (already set by tester constructor) // - eosio.msig (code: eosio.msig) // - eosio.token (code: eosio.token) - set_code_abi(N(eosio.msig), eosio_msig_wast, eosio_msig_abi);//, &eosio_active_pk); - set_code_abi(N(eosio.token), eosio_token_wast, eosio_token_abi); //, &eosio_active_pk); + // set_code_abi(N(eosio.msig), contracts::eosio_msig_wasm(), contracts::eosio_msig_abi().data());//, &eosio_active_pk); + // set_code_abi(N(eosio.token), contracts::eosio_token_wasm(), contracts::eosio_token_abi().data()); //, &eosio_active_pk); + + set_code_abi(N(eosio.msig), + contracts::eosio_msig_wasm(), + contracts::eosio_msig_abi().data());//, &eosio_active_pk); + set_code_abi(N(eosio.token), + contracts::eosio_token_wasm(), + contracts::eosio_token_abi().data()); //, &eosio_active_pk); // Set privileged for eosio.msig and eosio.token set_privileged(N(eosio.msig)); @@ -215,8 +234,7 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) { create_account( a.aname, config::system_account_name ); } - // Set eosio.system to eosio - set_code_abi(config::system_account_name, eosio_system_wast, eosio_system_abi); + deploy_contract(); // Buy ram and stake cpu and net for each genesis accounts for( const auto& a : test_genesis ) { @@ -260,6 +278,8 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) { votepro( N(whale3), {N(proda), N(prodb), N(prodc), N(prodd), N(prode)} ); // Total Stakes = b1 + whale2 + whale3 stake = (100,000,000 - 1,000) + (20,000,000 - 1,000) + (30,000,000 - 1,000) + vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global), N(global) ); + BOOST_TEST(get_global_state()["total_activated_stake"].as() == 1499999997000); // No producers will be set, since the total activated stake is less than 150,000,000 diff --git a/unittests/contracts.hpp.in b/unittests/contracts.hpp.in new file mode 100644 index 00000000000..e04730ec98f --- /dev/null +++ b/unittests/contracts.hpp.in @@ -0,0 +1,55 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once + +#include + +#define CORE_SYM_NAME "${CORE_SYMBOL_NAME}" +#define CORE_SYM_PRECISION 4 + +#define _STRINGIZE1(x) #x +#define _STRINGIZE2(x) _STRINGIZE1(x) + +#define CORE_SYM_STR ( _STRINGIZE2(CORE_SYM_PRECISION) "," CORE_SYM_NAME ) +#define CORE_SYM ( ::eosio::chain::string_to_symbol_c( CORE_SYM_PRECISION, CORE_SYM_NAME ) ) + +struct core_sym { + static inline eosio::chain::asset from_string(const std::string& s) { + return eosio::chain::asset::from_string(s + " " CORE_SYM_NAME); + } +}; + +// CN -> contract C++ name, C -> contract name, D -> top level directory +#define MAKE_READ_WASM_ABI(CN,C, D) \ + static std::vector CN ## _wasm() { return read_wasm("${CMAKE_BINARY_DIR}/unittests/" #D "/" #C "/" #C ".wasm"); } \ + static std::vector CN ## _abi() { return read_abi("${CMAKE_BINARY_DIR}/unittests/" #D "/" #C "/" #C ".abi"); } + +namespace eosio { + namespace testing { + struct contracts { + // Contracts in `eos/unittests/contracts' directory + MAKE_READ_WASM_ABI(eosio_bios, eosio.bios, contracts) + MAKE_READ_WASM_ABI(eosio_msig, eosio.msig, contracts) + MAKE_READ_WASM_ABI(eosio_system, eosio.system, contracts) + MAKE_READ_WASM_ABI(eosio_token, eosio.token, contracts) + MAKE_READ_WASM_ABI(eosio_wrap, eosio.wrap, contracts) + + // Contracts in `eos/unittests/unittests/test-contracts' directory + MAKE_READ_WASM_ABI(deferred_test, deferred_test, test-contracts) + MAKE_READ_WASM_ABI(asserter, asserter, test-contracts) + MAKE_READ_WASM_ABI(integration_test, integration_test, test-contracts) + MAKE_READ_WASM_ABI(multi_index_test, multi_index_test, test-contracts) + MAKE_READ_WASM_ABI(noop, noop, test-contracts) + MAKE_READ_WASM_ABI(payloadless, payloadless, test-contracts) + MAKE_READ_WASM_ABI(proxy, proxy, test-contracts) + MAKE_READ_WASM_ABI(snapshot_test, snapshot_test, test-contracts) + MAKE_READ_WASM_ABI(test_ram_limit, test_ram_limit, test-contracts) + MAKE_READ_WASM_ABI(test_api, test_api, test-contracts) + MAKE_READ_WASM_ABI(test_api_db, test_api_db, test-contracts) + MAKE_READ_WASM_ABI(test_api_multi_index, test_api_multi_index, test-contracts) + MAKE_READ_WASM_ABI(test_api_mem, test_api_mem, test-contracts) + }; + } /// eosio::testing +} /// eosio diff --git a/unittests/contracts/CMakeLists.txt b/unittests/contracts/CMakeLists.txt index 24b1890d9a6..59ea1c1ca26 100644 --- a/unittests/contracts/CMakeLists.txt +++ b/unittests/contracts/CMakeLists.txt @@ -1,7 +1,8 @@ # will be implictly used for any compilation unit if not overrided by SYSTEM_INCLUDE_FOLDERS parameter # these directories go as -isystem to avoid warnings from code of third-party libraries -set(DEFAULT_SYSTEM_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts/libc++/upstream/include ${CMAKE_SOURCE_DIR}/contracts/musl/upstream/include ${Boost_INCLUDE_DIR}) -set(STANDARD_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts ${CMAKE_SOURCE_DIR}/unittests/contracts ${CMAKE_SOURCE_DIR}/externals/magic_get/include) - -add_subdirectory(deferred_test) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/eosio.bios/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/eosio.bios/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/eosio.msig/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/eosio.msig/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/eosio.system/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/eosio.system/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/eosio.token/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/eosio.token/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/eosio.wrap/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/eosio.wrap/) diff --git a/unittests/contracts/deferred_test/CMakeLists.txt b/unittests/contracts/deferred_test/CMakeLists.txt deleted file mode 100644 index 9d0b08a7b4c..00000000000 --- a/unittests/contracts/deferred_test/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET deferred_test - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" ${Boost_INCLUDE_DIR} - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/unittests/contracts/deferred_test/deferred_test.abi b/unittests/contracts/deferred_test/deferred_test.abi deleted file mode 100644 index 802f835642a..00000000000 --- a/unittests/contracts/deferred_test/deferred_test.abi +++ /dev/null @@ -1,61 +0,0 @@ -{ - "version": "eosio::abi/1.0", - "types": [], - "structs": [{ - "name": "defercall", - "base": "", - "fields": [{ - "name": "payer", - "type": "name" - },{ - "name": "sender_id", - "type": "uint64" - },{ - "name": "contract", - "type": "name" - },{ - "name": "payload", - "type": "uint64" - } - ] - },{ - "name": "deferfunc", - "base": "", - "fields": [{ - "name": "payload", - "type": "uint64" - }] - },{ - "name": "inlinecall", - "base": "", - "fields": [{ - "name": "contract", - "type": "name" - },{ - "name": "authorizer", - "type": "name" - },{ - "name": "payload", - "type": "uint64" - }] - } - ], - "actions": [{ - "name": "defercall", - "type": "defercall", - "ricardian_contract": "" - },{ - "name": "deferfunc", - "type": "deferfunc", - "ricardian_contract": "" - },{ - "name": "inlinecall", - "type": "inlinecall", - "ricardian_contract": "" - } - ], - "tables": [], - "ricardian_clauses": [], - "error_messages": [], - "abi_extensions": [] -} diff --git a/unittests/contracts/eosio.bios/eosio.bios.abi b/unittests/contracts/eosio.bios/eosio.bios.abi new file mode 100644 index 00000000000..0d5749b981b --- /dev/null +++ b/unittests/contracts/eosio.bios/eosio.bios.abi @@ -0,0 +1,522 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Mon Dec 3 17:06:17 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "abi_hash", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "hash", + "type": "checksum256" + } + ] + }, + { + "name": "authority", + "base": "", + "fields": [ + { + "name": "threshold", + "type": "uint32" + }, + { + "name": "keys", + "type": "key_weight[]" + }, + { + "name": "accounts", + "type": "permission_level_weight[]" + }, + { + "name": "waits", + "type": "wait_weight[]" + } + ] + }, + { + "name": "blockchain_parameters", + "base": "", + "fields": [ + { + "name": "max_block_net_usage", + "type": "uint64" + }, + { + "name": "target_block_net_usage_pct", + "type": "uint32" + }, + { + "name": "max_transaction_net_usage", + "type": "uint32" + }, + { + "name": "base_per_transaction_net_usage", + "type": "uint32" + }, + { + "name": "net_usage_leeway", + "type": "uint32" + }, + { + "name": "context_free_discount_net_usage_num", + "type": "uint32" + }, + { + "name": "context_free_discount_net_usage_den", + "type": "uint32" + }, + { + "name": "max_block_cpu_usage", + "type": "uint32" + }, + { + "name": "target_block_cpu_usage_pct", + "type": "uint32" + }, + { + "name": "max_transaction_cpu_usage", + "type": "uint32" + }, + { + "name": "min_transaction_cpu_usage", + "type": "uint32" + }, + { + "name": "max_transaction_lifetime", + "type": "uint32" + }, + { + "name": "deferred_trx_expiration_window", + "type": "uint32" + }, + { + "name": "max_transaction_delay", + "type": "uint32" + }, + { + "name": "max_inline_action_size", + "type": "uint32" + }, + { + "name": "max_inline_action_depth", + "type": "uint16" + }, + { + "name": "max_authority_depth", + "type": "uint16" + } + ] + }, + { + "name": "canceldelay", + "base": "", + "fields": [ + { + "name": "canceling_auth", + "type": "permission_level" + }, + { + "name": "trx_id", + "type": "checksum256" + } + ] + }, + { + "name": "deleteauth", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "permission", + "type": "name" + } + ] + }, + { + "name": "key_weight", + "base": "", + "fields": [ + { + "name": "key", + "type": "public_key" + }, + { + "name": "weight", + "type": "uint16" + } + ] + }, + { + "name": "linkauth", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "code", + "type": "name" + }, + { + "name": "type", + "type": "name" + }, + { + "name": "requirement", + "type": "name" + } + ] + }, + { + "name": "newaccount", + "base": "", + "fields": [ + { + "name": "creator", + "type": "name" + }, + { + "name": "name", + "type": "name" + }, + { + "name": "owner", + "type": "authority" + }, + { + "name": "active", + "type": "authority" + } + ] + }, + { + "name": "onerror", + "base": "", + "fields": [ + { + "name": "sender_id", + "type": "uint128" + }, + { + "name": "sent_trx", + "type": "bytes" + } + ] + }, + { + "name": "permission_level", + "base": "", + "fields": [ + { + "name": "actor", + "type": "name" + }, + { + "name": "permission", + "type": "name" + } + ] + }, + { + "name": "permission_level_weight", + "base": "", + "fields": [ + { + "name": "permission", + "type": "permission_level" + }, + { + "name": "weight", + "type": "uint16" + } + ] + }, + { + "name": "producer_key", + "base": "", + "fields": [ + { + "name": "producer_name", + "type": "name" + }, + { + "name": "block_signing_key", + "type": "public_key" + } + ] + }, + { + "name": "reqauth", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + } + ] + }, + { + "name": "setabi", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "abi", + "type": "bytes" + } + ] + }, + { + "name": "setalimits", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "ram_bytes", + "type": "int64" + }, + { + "name": "net_weight", + "type": "int64" + }, + { + "name": "cpu_weight", + "type": "int64" + } + ] + }, + { + "name": "setcode", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "vmtype", + "type": "uint8" + }, + { + "name": "vmversion", + "type": "uint8" + }, + { + "name": "code", + "type": "bytes" + } + ] + }, + { + "name": "setglimits", + "base": "", + "fields": [ + { + "name": "ram", + "type": "uint64" + }, + { + "name": "net", + "type": "uint64" + }, + { + "name": "cpu", + "type": "uint64" + } + ] + }, + { + "name": "setparams", + "base": "", + "fields": [ + { + "name": "params", + "type": "blockchain_parameters" + } + ] + }, + { + "name": "setpriv", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "is_priv", + "type": "uint8" + } + ] + }, + { + "name": "setprods", + "base": "", + "fields": [ + { + "name": "schedule", + "type": "producer_key[]" + } + ] + }, + { + "name": "unlinkauth", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "code", + "type": "name" + }, + { + "name": "type", + "type": "name" + } + ] + }, + { + "name": "updateauth", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "permission", + "type": "name" + }, + { + "name": "parent", + "type": "name" + }, + { + "name": "auth", + "type": "authority" + } + ] + }, + { + "name": "wait_weight", + "base": "", + "fields": [ + { + "name": "wait_sec", + "type": "uint32" + }, + { + "name": "weight", + "type": "uint16" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "canceldelay", + "type": "canceldelay", + "ricardian_contract": "" + }, + { + "name": "deleteauth", + "type": "deleteauth", + "ricardian_contract": "" + }, + { + "name": "linkauth", + "type": "linkauth", + "ricardian_contract": "" + }, + { + "name": "newaccount", + "type": "newaccount", + "ricardian_contract": "" + }, + { + "name": "onerror", + "type": "onerror", + "ricardian_contract": "" + }, + { + "name": "reqauth", + "type": "reqauth", + "ricardian_contract": "" + }, + { + "name": "setabi", + "type": "setabi", + "ricardian_contract": "" + }, + { + "name": "setalimits", + "type": "setalimits", + "ricardian_contract": "" + }, + { + "name": "setcode", + "type": "setcode", + "ricardian_contract": "" + }, + { + "name": "setglimits", + "type": "setglimits", + "ricardian_contract": "" + }, + { + "name": "setparams", + "type": "setparams", + "ricardian_contract": "" + }, + { + "name": "setpriv", + "type": "setpriv", + "ricardian_contract": "" + }, + { + "name": "setprods", + "type": "setprods", + "ricardian_contract": "" + }, + { + "name": "unlinkauth", + "type": "unlinkauth", + "ricardian_contract": "" + }, + { + "name": "updateauth", + "type": "updateauth", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "abihash", + "type": "abi_hash", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/contracts/eosio.bios/eosio.bios.wasm b/unittests/contracts/eosio.bios/eosio.bios.wasm new file mode 100755 index 00000000000..ea62431344e Binary files /dev/null and b/unittests/contracts/eosio.bios/eosio.bios.wasm differ diff --git a/unittests/contracts/eosio.msig/eosio.msig.abi b/unittests/contracts/eosio.msig/eosio.msig.abi new file mode 100644 index 00000000000..7ab2b01eebb --- /dev/null +++ b/unittests/contracts/eosio.msig/eosio.msig.abi @@ -0,0 +1,360 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Thu Nov 15 14:56:36 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "action", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "name", + "type": "name" + }, + { + "name": "authorization", + "type": "permission_level[]" + }, + { + "name": "data", + "type": "bytes" + } + ] + }, + { + "name": "approval", + "base": "", + "fields": [ + { + "name": "level", + "type": "permission_level" + }, + { + "name": "time", + "type": "time_point" + } + ] + }, + { + "name": "approvals_info", + "base": "", + "fields": [ + { + "name": "version", + "type": "uint8" + }, + { + "name": "proposal_name", + "type": "name" + }, + { + "name": "requested_approvals", + "type": "approval[]" + }, + { + "name": "provided_approvals", + "type": "approval[]" + } + ] + }, + { + "name": "approve", + "base": "", + "fields": [ + { + "name": "proposer", + "type": "name" + }, + { + "name": "proposal_name", + "type": "name" + }, + { + "name": "level", + "type": "permission_level" + }, + { + "name": "proposal_hash", + "type": "checksum256$" + } + ] + }, + { + "name": "cancel", + "base": "", + "fields": [ + { + "name": "proposer", + "type": "name" + }, + { + "name": "proposal_name", + "type": "name" + }, + { + "name": "canceler", + "type": "name" + } + ] + }, + { + "name": "exec", + "base": "", + "fields": [ + { + "name": "proposer", + "type": "name" + }, + { + "name": "proposal_name", + "type": "name" + }, + { + "name": "executer", + "type": "name" + } + ] + }, + { + "name": "extension", + "base": "", + "fields": [ + { + "name": "type", + "type": "uint16" + }, + { + "name": "data", + "type": "bytes" + } + ] + }, + { + "name": "invalidate", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + } + ] + }, + { + "name": "invalidation", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "last_invalidation_time", + "type": "time_point" + } + ] + }, + { + "name": "old_approvals_info", + "base": "", + "fields": [ + { + "name": "proposal_name", + "type": "name" + }, + { + "name": "requested_approvals", + "type": "permission_level[]" + }, + { + "name": "provided_approvals", + "type": "permission_level[]" + } + ] + }, + { + "name": "permission_level", + "base": "", + "fields": [ + { + "name": "actor", + "type": "name" + }, + { + "name": "permission", + "type": "name" + } + ] + }, + { + "name": "proposal", + "base": "", + "fields": [ + { + "name": "proposal_name", + "type": "name" + }, + { + "name": "packed_transaction", + "type": "bytes" + } + ] + }, + { + "name": "propose", + "base": "", + "fields": [ + { + "name": "proposer", + "type": "name" + }, + { + "name": "proposal_name", + "type": "name" + }, + { + "name": "requested", + "type": "permission_level[]" + }, + { + "name": "trx", + "type": "transaction" + } + ] + }, + { + "name": "transaction", + "base": "transaction_header", + "fields": [ + { + "name": "context_free_actions", + "type": "action[]" + }, + { + "name": "actions", + "type": "action[]" + }, + { + "name": "transaction_extensions", + "type": "extension[]" + } + ] + }, + { + "name": "transaction_header", + "base": "", + "fields": [ + { + "name": "expiration", + "type": "time_point_sec" + }, + { + "name": "ref_block_num", + "type": "uint16" + }, + { + "name": "ref_block_prefix", + "type": "uint32" + }, + { + "name": "max_net_usage_words", + "type": "varuint32" + }, + { + "name": "max_cpu_usage_ms", + "type": "uint8" + }, + { + "name": "delay_sec", + "type": "varuint32" + } + ] + }, + { + "name": "unapprove", + "base": "", + "fields": [ + { + "name": "proposer", + "type": "name" + }, + { + "name": "proposal_name", + "type": "name" + }, + { + "name": "level", + "type": "permission_level" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "approve", + "type": "approve", + "ricardian_contract": "" + }, + { + "name": "cancel", + "type": "cancel", + "ricardian_contract": "" + }, + { + "name": "exec", + "type": "exec", + "ricardian_contract": "" + }, + { + "name": "invalidate", + "type": "invalidate", + "ricardian_contract": "" + }, + { + "name": "propose", + "type": "propose", + "ricardian_contract": "" + }, + { + "name": "unapprove", + "type": "unapprove", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "approvals", + "type": "old_approvals_info", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "approvals2", + "type": "approvals_info", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "invals", + "type": "invalidation", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "proposal", + "type": "proposal", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/contracts/eosio.msig/eosio.msig.wasm b/unittests/contracts/eosio.msig/eosio.msig.wasm new file mode 100755 index 00000000000..dda2a3434f8 Binary files /dev/null and b/unittests/contracts/eosio.msig/eosio.msig.wasm differ diff --git a/unittests/contracts/eosio.system/eosio.system.abi b/unittests/contracts/eosio.system/eosio.system.abi new file mode 100644 index 00000000000..8820833a31e --- /dev/null +++ b/unittests/contracts/eosio.system/eosio.system.abi @@ -0,0 +1,1833 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Thu Dec 13 12:22:07 2018", + "version": "eosio::abi/1.0", + "structs": [ + { + "name": "abi_hash", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "hash", + "type": "checksum256" + } + ] + }, + { + "name": "authority", + "base": "", + "fields": [ + { + "name": "threshold", + "type": "uint32" + }, + { + "name": "keys", + "type": "key_weight[]" + }, + { + "name": "accounts", + "type": "permission_level_weight[]" + }, + { + "name": "waits", + "type": "wait_weight[]" + } + ] + }, + { + "name": "bid_refund", + "base": "", + "fields": [ + { + "name": "bidder", + "type": "name" + }, + { + "name": "amount", + "type": "asset" + } + ] + }, + { + "name": "bidname", + "base": "", + "fields": [ + { + "name": "bidder", + "type": "name" + }, + { + "name": "newname", + "type": "name" + }, + { + "name": "bid", + "type": "asset" + } + ] + }, + { + "name": "bidrefund", + "base": "", + "fields": [ + { + "name": "bidder", + "type": "name" + }, + { + "name": "newname", + "type": "name" + } + ] + }, + { + "name": "block_header", + "base": "", + "fields": [ + { + "name": "timestamp", + "type": "uint32" + }, + { + "name": "producer", + "type": "name" + }, + { + "name": "confirmed", + "type": "uint16" + }, + { + "name": "previous", + "type": "checksum256" + }, + { + "name": "transaction_mroot", + "type": "checksum256" + }, + { + "name": "action_mroot", + "type": "checksum256" + }, + { + "name": "schedule_version", + "type": "uint32" + }, + { + "name": "new_producers", + "type": "producer_schedule?" + } + ] + }, + { + "name": "blockchain_parameters", + "base": "", + "fields": [ + { + "name": "max_block_net_usage", + "type": "uint64" + }, + { + "name": "target_block_net_usage_pct", + "type": "uint32" + }, + { + "name": "max_transaction_net_usage", + "type": "uint32" + }, + { + "name": "base_per_transaction_net_usage", + "type": "uint32" + }, + { + "name": "net_usage_leeway", + "type": "uint32" + }, + { + "name": "context_free_discount_net_usage_num", + "type": "uint32" + }, + { + "name": "context_free_discount_net_usage_den", + "type": "uint32" + }, + { + "name": "max_block_cpu_usage", + "type": "uint32" + }, + { + "name": "target_block_cpu_usage_pct", + "type": "uint32" + }, + { + "name": "max_transaction_cpu_usage", + "type": "uint32" + }, + { + "name": "min_transaction_cpu_usage", + "type": "uint32" + }, + { + "name": "max_transaction_lifetime", + "type": "uint32" + }, + { + "name": "deferred_trx_expiration_window", + "type": "uint32" + }, + { + "name": "max_transaction_delay", + "type": "uint32" + }, + { + "name": "max_inline_action_size", + "type": "uint32" + }, + { + "name": "max_inline_action_depth", + "type": "uint16" + }, + { + "name": "max_authority_depth", + "type": "uint16" + } + ] + }, + { + "name": "buyram", + "base": "", + "fields": [ + { + "name": "payer", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "quant", + "type": "asset" + } + ] + }, + { + "name": "buyrambytes", + "base": "", + "fields": [ + { + "name": "payer", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "bytes", + "type": "uint32" + } + ] + }, + { + "name": "buyrex", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "amount", + "type": "asset" + } + ] + }, + { + "name": "canceldelay", + "base": "", + "fields": [ + { + "name": "canceling_auth", + "type": "permission_level" + }, + { + "name": "trx_id", + "type": "checksum256" + } + ] + }, + { + "name": "claimrewards", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + } + ] + }, + { + "name": "closerex", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + } + ] + }, + { + "name": "cnclrexorder", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + } + ] + }, + { + "name": "connector", + "base": "", + "fields": [ + { + "name": "balance", + "type": "asset" + }, + { + "name": "weight", + "type": "float64" + } + ] + }, + { + "name": "consolidate", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + } + ] + }, + { + "name": "defcpuloan", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "loan_num", + "type": "uint64" + }, + { + "name": "amount", + "type": "asset" + } + ] + }, + { + "name": "defnetloan", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "loan_num", + "type": "uint64" + }, + { + "name": "amount", + "type": "asset" + } + ] + }, + { + "name": "delegatebw", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "stake_net_quantity", + "type": "asset" + }, + { + "name": "stake_cpu_quantity", + "type": "asset" + }, + { + "name": "transfer", + "type": "bool" + } + ] + }, + { + "name": "delegated_bandwidth", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "to", + "type": "name" + }, + { + "name": "net_weight", + "type": "asset" + }, + { + "name": "cpu_weight", + "type": "asset" + } + ] + }, + { + "name": "deleteauth", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "permission", + "type": "name" + } + ] + }, + { + "name": "deposit", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "amount", + "type": "asset" + } + ] + }, + { + "name": "eosio_global_state", + "base": "blockchain_parameters", + "fields": [ + { + "name": "max_ram_size", + "type": "uint64" + }, + { + "name": "total_ram_bytes_reserved", + "type": "uint64" + }, + { + "name": "total_ram_stake", + "type": "int64" + }, + { + "name": "last_producer_schedule_update", + "type": "block_timestamp_type" + }, + { + "name": "last_pervote_bucket_fill", + "type": "time_point" + }, + { + "name": "pervote_bucket", + "type": "int64" + }, + { + "name": "perblock_bucket", + "type": "int64" + }, + { + "name": "total_unpaid_blocks", + "type": "uint32" + }, + { + "name": "total_activated_stake", + "type": "int64" + }, + { + "name": "thresh_activated_stake_time", + "type": "time_point" + }, + { + "name": "last_producer_schedule_size", + "type": "uint16" + }, + { + "name": "total_producer_vote_weight", + "type": "float64" + }, + { + "name": "last_name_close", + "type": "block_timestamp_type" + } + ] + }, + { + "name": "eosio_global_state2", + "base": "", + "fields": [ + { + "name": "new_ram_per_block", + "type": "uint16" + }, + { + "name": "last_ram_increase", + "type": "block_timestamp_type" + }, + { + "name": "last_block_num", + "type": "block_timestamp_type" + }, + { + "name": "total_producer_votepay_share", + "type": "float64" + }, + { + "name": "revision", + "type": "uint8" + } + ] + }, + { + "name": "eosio_global_state3", + "base": "", + "fields": [ + { + "name": "last_vpay_state_update", + "type": "time_point" + }, + { + "name": "total_vpay_share_change_rate", + "type": "float64" + } + ] + }, + { + "name": "exchange_state", + "base": "", + "fields": [ + { + "name": "supply", + "type": "asset" + }, + { + "name": "base", + "type": "connector" + }, + { + "name": "quote", + "type": "connector" + } + ] + }, + { + "name": "fundcpuloan", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "loan_num", + "type": "uint64" + }, + { + "name": "payment", + "type": "asset" + } + ] + }, + { + "name": "fundnetloan", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "loan_num", + "type": "uint64" + }, + { + "name": "payment", + "type": "asset" + } + ] + }, + { + "name": "init", + "base": "", + "fields": [ + { + "name": "version", + "type": "varuint32" + }, + { + "name": "core", + "type": "symbol" + } + ] + }, + { + "name": "key_weight", + "base": "", + "fields": [ + { + "name": "key", + "type": "public_key" + }, + { + "name": "weight", + "type": "uint16" + } + ] + }, + { + "name": "linkauth", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "code", + "type": "name" + }, + { + "name": "type", + "type": "name" + }, + { + "name": "requirement", + "type": "name" + } + ] + }, + { + "name": "name_bid", + "base": "", + "fields": [ + { + "name": "newname", + "type": "name" + }, + { + "name": "high_bidder", + "type": "name" + }, + { + "name": "high_bid", + "type": "int64" + }, + { + "name": "last_bid_time", + "type": "time_point" + } + ] + }, + { + "name": "newaccount", + "base": "", + "fields": [ + { + "name": "creator", + "type": "name" + }, + { + "name": "name", + "type": "name" + }, + { + "name": "owner", + "type": "authority" + }, + { + "name": "active", + "type": "authority" + } + ] + }, + { + "name": "onblock", + "base": "", + "fields": [ + { + "name": "header", + "type": "block_header" + } + ] + }, + { + "name": "onerror", + "base": "", + "fields": [ + { + "name": "sender_id", + "type": "uint128" + }, + { + "name": "sent_trx", + "type": "bytes" + } + ] + }, + { + "name": "pair_time_point_sec_int64", + "base": "", + "fields": [ + { + "name": "first", + "type": "time_point_sec" + }, + { + "name": "second", + "type": "int64" + } + ] + }, + { + "name": "permission_level", + "base": "", + "fields": [ + { + "name": "actor", + "type": "name" + }, + { + "name": "permission", + "type": "name" + } + ] + }, + { + "name": "permission_level_weight", + "base": "", + "fields": [ + { + "name": "permission", + "type": "permission_level" + }, + { + "name": "weight", + "type": "uint16" + } + ] + }, + { + "name": "producer_info", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "total_votes", + "type": "float64" + }, + { + "name": "producer_key", + "type": "public_key" + }, + { + "name": "is_active", + "type": "bool" + }, + { + "name": "url", + "type": "string" + }, + { + "name": "unpaid_blocks", + "type": "uint32" + }, + { + "name": "last_claim_time", + "type": "time_point" + }, + { + "name": "location", + "type": "uint16" + } + ] + }, + { + "name": "producer_info2", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "votepay_share", + "type": "float64" + }, + { + "name": "last_votepay_share_update", + "type": "time_point" + } + ] + }, + { + "name": "producer_key", + "base": "", + "fields": [ + { + "name": "producer_name", + "type": "name" + }, + { + "name": "block_signing_key", + "type": "public_key" + } + ] + }, + { + "name": "producer_schedule", + "base": "", + "fields": [ + { + "name": "version", + "type": "uint32" + }, + { + "name": "producers", + "type": "producer_key[]" + } + ] + }, + { + "name": "refund", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + } + ] + }, + { + "name": "refund_request", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "request_time", + "type": "time_point_sec" + }, + { + "name": "net_amount", + "type": "asset" + }, + { + "name": "cpu_amount", + "type": "asset" + } + ] + }, + { + "name": "regproducer", + "base": "", + "fields": [ + { + "name": "producer", + "type": "name" + }, + { + "name": "producer_key", + "type": "public_key" + }, + { + "name": "url", + "type": "string" + }, + { + "name": "location", + "type": "uint16" + } + ] + }, + { + "name": "regproxy", + "base": "", + "fields": [ + { + "name": "proxy", + "type": "name" + }, + { + "name": "isproxy", + "type": "bool" + } + ] + }, + { + "name": "rentcpu", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "loan_payment", + "type": "asset" + }, + { + "name": "loan_fund", + "type": "asset" + } + ] + }, + { + "name": "rentnet", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "loan_payment", + "type": "asset" + }, + { + "name": "loan_fund", + "type": "asset" + } + ] + }, + { + "name": "rex_balance", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "vote_stake", + "type": "asset" + }, + { + "name": "rex_balance", + "type": "asset" + }, + { + "name": "matured_rex", + "type": "int64" + }, + { + "name": "rex_maturities", + "type": "pair_time_point_sec_int64[]" + } + ] + }, + { + "name": "rex_fund", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "balance", + "type": "asset" + } + ] + }, + { + "name": "rex_loan", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "payment", + "type": "asset" + }, + { + "name": "balance", + "type": "asset" + }, + { + "name": "total_staked", + "type": "asset" + }, + { + "name": "loan_num", + "type": "uint64" + }, + { + "name": "expiration", + "type": "time_point" + } + ] + }, + { + "name": "rex_order", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "rex_requested", + "type": "asset" + }, + { + "name": "proceeds", + "type": "asset" + }, + { + "name": "stake_change", + "type": "asset" + }, + { + "name": "order_time", + "type": "time_point" + }, + { + "name": "is_open", + "type": "bool" + } + ] + }, + { + "name": "rex_pool", + "base": "", + "fields": [ + { + "name": "total_lent", + "type": "asset" + }, + { + "name": "total_unlent", + "type": "asset" + }, + { + "name": "total_rent", + "type": "asset" + }, + { + "name": "total_lendable", + "type": "asset" + }, + { + "name": "total_rex", + "type": "asset" + }, + { + "name": "namebid_proceeds", + "type": "asset" + }, + { + "name": "loan_num", + "type": "uint64" + } + ] + }, + { + "name": "rexexec", + "base": "", + "fields": [ + { + "name": "user", + "type": "name" + }, + { + "name": "max", + "type": "uint16" + } + ] + }, + { + "name": "rmvproducer", + "base": "", + "fields": [ + { + "name": "producer", + "type": "name" + } + ] + }, + { + "name": "sellram", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "bytes", + "type": "int64" + } + ] + }, + { + "name": "sellrex", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "rex", + "type": "asset" + } + ] + }, + { + "name": "setabi", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "abi", + "type": "bytes" + } + ] + }, + { + "name": "setalimits", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "ram_bytes", + "type": "int64" + }, + { + "name": "net_weight", + "type": "int64" + }, + { + "name": "cpu_weight", + "type": "int64" + } + ] + }, + { + "name": "setcode", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "vmtype", + "type": "uint8" + }, + { + "name": "vmversion", + "type": "uint8" + }, + { + "name": "code", + "type": "bytes" + } + ] + }, + { + "name": "setparams", + "base": "", + "fields": [ + { + "name": "params", + "type": "blockchain_parameters" + } + ] + }, + { + "name": "setpriv", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "is_priv", + "type": "uint8" + } + ] + }, + { + "name": "setram", + "base": "", + "fields": [ + { + "name": "max_ram_size", + "type": "uint64" + } + ] + }, + { + "name": "setramrate", + "base": "", + "fields": [ + { + "name": "bytes_per_block", + "type": "uint16" + } + ] + }, + { + "name": "undelegatebw", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "unstake_net_quantity", + "type": "asset" + }, + { + "name": "unstake_cpu_quantity", + "type": "asset" + } + ] + }, + { + "name": "unlinkauth", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "code", + "type": "name" + }, + { + "name": "type", + "type": "name" + } + ] + }, + { + "name": "unregprod", + "base": "", + "fields": [ + { + "name": "producer", + "type": "name" + } + ] + }, + { + "name": "unstaketorex", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "from_net", + "type": "asset" + }, + { + "name": "from_cpu", + "type": "asset" + } + ] + }, + { + "name": "updateauth", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "permission", + "type": "name" + }, + { + "name": "parent", + "type": "name" + }, + { + "name": "auth", + "type": "authority" + } + ] + }, + { + "name": "updaterex", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + } + ] + }, + { + "name": "updtrevision", + "base": "", + "fields": [ + { + "name": "revision", + "type": "uint8" + } + ] + }, + { + "name": "user_resources", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "net_weight", + "type": "asset" + }, + { + "name": "cpu_weight", + "type": "asset" + }, + { + "name": "ram_bytes", + "type": "int64" + } + ] + }, + { + "name": "voteproducer", + "base": "", + "fields": [ + { + "name": "voter", + "type": "name" + }, + { + "name": "proxy", + "type": "name" + }, + { + "name": "producers", + "type": "name[]" + } + ] + }, + { + "name": "voter_info", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "proxy", + "type": "name" + }, + { + "name": "producers", + "type": "name[]" + }, + { + "name": "staked", + "type": "int64" + }, + { + "name": "last_vote_weight", + "type": "float64" + }, + { + "name": "proxied_vote_weight", + "type": "float64" + }, + { + "name": "is_proxy", + "type": "bool" + }, + { + "name": "reserved1", + "type": "uint32" + }, + { + "name": "reserved2", + "type": "uint32" + }, + { + "name": "reserved3", + "type": "asset" + } + ] + }, + { + "name": "wait_weight", + "base": "", + "fields": [ + { + "name": "wait_sec", + "type": "uint32" + }, + { + "name": "weight", + "type": "uint16" + } + ] + }, + { + "name": "withdraw", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "amount", + "type": "asset" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "bidname", + "type": "bidname", + "ricardian_contract": "" + }, + { + "name": "bidrefund", + "type": "bidrefund", + "ricardian_contract": "" + }, + { + "name": "buyram", + "type": "buyram", + "ricardian_contract": "" + }, + { + "name": "buyrambytes", + "type": "buyrambytes", + "ricardian_contract": "" + }, + { + "name": "buyrex", + "type": "buyrex", + "ricardian_contract": "" + }, + { + "name": "canceldelay", + "type": "canceldelay", + "ricardian_contract": "" + }, + { + "name": "claimrewards", + "type": "claimrewards", + "ricardian_contract": "" + }, + { + "name": "closerex", + "type": "closerex", + "ricardian_contract": "" + }, + { + "name": "cnclrexorder", + "type": "cnclrexorder", + "ricardian_contract": "" + }, + { + "name": "consolidate", + "type": "consolidate", + "ricardian_contract": "" + }, + { + "name": "defcpuloan", + "type": "defcpuloan", + "ricardian_contract": "" + }, + { + "name": "defnetloan", + "type": "defnetloan", + "ricardian_contract": "" + }, + { + "name": "delegatebw", + "type": "delegatebw", + "ricardian_contract": "" + }, + { + "name": "deleteauth", + "type": "deleteauth", + "ricardian_contract": "" + }, + { + "name": "deposit", + "type": "deposit", + "ricardian_contract": "" + }, + { + "name": "fundcpuloan", + "type": "fundcpuloan", + "ricardian_contract": "" + }, + { + "name": "fundnetloan", + "type": "fundnetloan", + "ricardian_contract": "" + }, + { + "name": "init", + "type": "init", + "ricardian_contract": "" + }, + { + "name": "linkauth", + "type": "linkauth", + "ricardian_contract": "" + }, + { + "name": "newaccount", + "type": "newaccount", + "ricardian_contract": "" + }, + { + "name": "onblock", + "type": "onblock", + "ricardian_contract": "" + }, + { + "name": "onerror", + "type": "onerror", + "ricardian_contract": "" + }, + { + "name": "refund", + "type": "refund", + "ricardian_contract": "" + }, + { + "name": "regproducer", + "type": "regproducer", + "ricardian_contract": "" + }, + { + "name": "regproxy", + "type": "regproxy", + "ricardian_contract": "" + }, + { + "name": "rentcpu", + "type": "rentcpu", + "ricardian_contract": "" + }, + { + "name": "rentnet", + "type": "rentnet", + "ricardian_contract": "" + }, + { + "name": "rexexec", + "type": "rexexec", + "ricardian_contract": "" + }, + { + "name": "rmvproducer", + "type": "rmvproducer", + "ricardian_contract": "" + }, + { + "name": "sellram", + "type": "sellram", + "ricardian_contract": "" + }, + { + "name": "sellrex", + "type": "sellrex", + "ricardian_contract": "" + }, + { + "name": "setabi", + "type": "setabi", + "ricardian_contract": "" + }, + { + "name": "setalimits", + "type": "setalimits", + "ricardian_contract": "" + }, + { + "name": "setcode", + "type": "setcode", + "ricardian_contract": "" + }, + { + "name": "setparams", + "type": "setparams", + "ricardian_contract": "" + }, + { + "name": "setpriv", + "type": "setpriv", + "ricardian_contract": "" + }, + { + "name": "setram", + "type": "setram", + "ricardian_contract": "" + }, + { + "name": "setramrate", + "type": "setramrate", + "ricardian_contract": "" + }, + { + "name": "undelegatebw", + "type": "undelegatebw", + "ricardian_contract": "" + }, + { + "name": "unlinkauth", + "type": "unlinkauth", + "ricardian_contract": "" + }, + { + "name": "unregprod", + "type": "unregprod", + "ricardian_contract": "" + }, + { + "name": "unstaketorex", + "type": "unstaketorex", + "ricardian_contract": "" + }, + { + "name": "updateauth", + "type": "updateauth", + "ricardian_contract": "" + }, + { + "name": "updaterex", + "type": "updaterex", + "ricardian_contract": "" + }, + { + "name": "updtrevision", + "type": "updtrevision", + "ricardian_contract": "" + }, + { + "name": "voteproducer", + "type": "voteproducer", + "ricardian_contract": "" + }, + { + "name": "withdraw", + "type": "withdraw", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "abihash", + "type": "abi_hash", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "bidrefunds", + "type": "bid_refund", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "cpuloan", + "type": "rex_loan", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "delband", + "type": "delegated_bandwidth", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "global", + "type": "eosio_global_state", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "global2", + "type": "eosio_global_state2", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "global3", + "type": "eosio_global_state3", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "namebids", + "type": "name_bid", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "netloan", + "type": "rex_loan", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "producers", + "type": "producer_info", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "producers2", + "type": "producer_info2", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "rammarket", + "type": "exchange_state", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "refunds", + "type": "refund_request", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "rexbal", + "type": "rex_balance", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "rexfund", + "type": "rex_fund", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "rexpool", + "type": "rex_pool", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "rexqueue", + "type": "rex_order", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "userres", + "type": "user_resources", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "voters", + "type": "voter_info", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/contracts/eosio.system/eosio.system.wasm b/unittests/contracts/eosio.system/eosio.system.wasm new file mode 100755 index 00000000000..fffe933c47c Binary files /dev/null and b/unittests/contracts/eosio.system/eosio.system.wasm differ diff --git a/unittests/contracts/eosio.token/eosio.token.abi b/unittests/contracts/eosio.token/eosio.token.abi new file mode 100644 index 00000000000..a5d90710841 --- /dev/null +++ b/unittests/contracts/eosio.token/eosio.token.abi @@ -0,0 +1,186 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Nov 16 11:30:21 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "account", + "base": "", + "fields": [ + { + "name": "balance", + "type": "asset" + } + ] + }, + { + "name": "close", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "symbol", + "type": "symbol" + } + ] + }, + { + "name": "create", + "base": "", + "fields": [ + { + "name": "issuer", + "type": "name" + }, + { + "name": "maximum_supply", + "type": "asset" + } + ] + }, + { + "name": "currency_stats", + "base": "", + "fields": [ + { + "name": "supply", + "type": "asset" + }, + { + "name": "max_supply", + "type": "asset" + }, + { + "name": "issuer", + "type": "name" + } + ] + }, + { + "name": "issue", + "base": "", + "fields": [ + { + "name": "to", + "type": "name" + }, + { + "name": "quantity", + "type": "asset" + }, + { + "name": "memo", + "type": "string" + } + ] + }, + { + "name": "open", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "symbol", + "type": "symbol" + }, + { + "name": "ram_payer", + "type": "name" + } + ] + }, + { + "name": "retire", + "base": "", + "fields": [ + { + "name": "quantity", + "type": "asset" + }, + { + "name": "memo", + "type": "string" + } + ] + }, + { + "name": "transfer", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "to", + "type": "name" + }, + { + "name": "quantity", + "type": "asset" + }, + { + "name": "memo", + "type": "string" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "close", + "type": "close", + "ricardian_contract": "" + }, + { + "name": "create", + "type": "create", + "ricardian_contract": "" + }, + { + "name": "issue", + "type": "issue", + "ricardian_contract": "" + }, + { + "name": "open", + "type": "open", + "ricardian_contract": "" + }, + { + "name": "retire", + "type": "retire", + "ricardian_contract": "" + }, + { + "name": "transfer", + "type": "transfer", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "accounts", + "type": "account", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "stat", + "type": "currency_stats", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/contracts/eosio.token/eosio.token.wasm b/unittests/contracts/eosio.token/eosio.token.wasm new file mode 100755 index 00000000000..a3e02afc75c Binary files /dev/null and b/unittests/contracts/eosio.token/eosio.token.wasm differ diff --git a/unittests/contracts/eosio.wrap/eosio.wrap.abi b/unittests/contracts/eosio.wrap/eosio.wrap.abi new file mode 100644 index 00000000000..3914cfb98e4 --- /dev/null +++ b/unittests/contracts/eosio.wrap/eosio.wrap.abi @@ -0,0 +1,130 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Nov 16 11:30:52 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "action", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "name", + "type": "name" + }, + { + "name": "authorization", + "type": "permission_level[]" + }, + { + "name": "data", + "type": "bytes" + } + ] + }, + { + "name": "exec", + "base": "", + "fields": [ + { + "name": "executer", + "type": "name" + }, + { + "name": "trx", + "type": "transaction" + } + ] + }, + { + "name": "extension", + "base": "", + "fields": [ + { + "name": "type", + "type": "uint16" + }, + { + "name": "data", + "type": "bytes" + } + ] + }, + { + "name": "permission_level", + "base": "", + "fields": [ + { + "name": "actor", + "type": "name" + }, + { + "name": "permission", + "type": "name" + } + ] + }, + { + "name": "transaction", + "base": "transaction_header", + "fields": [ + { + "name": "context_free_actions", + "type": "action[]" + }, + { + "name": "actions", + "type": "action[]" + }, + { + "name": "transaction_extensions", + "type": "extension[]" + } + ] + }, + { + "name": "transaction_header", + "base": "", + "fields": [ + { + "name": "expiration", + "type": "time_point_sec" + }, + { + "name": "ref_block_num", + "type": "uint16" + }, + { + "name": "ref_block_prefix", + "type": "uint32" + }, + { + "name": "max_net_usage_words", + "type": "varuint32" + }, + { + "name": "max_cpu_usage_ms", + "type": "uint8" + }, + { + "name": "delay_sec", + "type": "varuint32" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "exec", + "type": "exec", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/contracts/eosio.wrap/eosio.wrap.wasm b/unittests/contracts/eosio.wrap/eosio.wrap.wasm new file mode 100755 index 00000000000..e9c17cb7a18 Binary files /dev/null and b/unittests/contracts/eosio.wrap/eosio.wrap.wasm differ diff --git a/unittests/contracts/fuzz13.wasm b/unittests/contracts/fuzz13.wasm index d8fc92d022f..8ec5122bce1 100644 Binary files a/unittests/contracts/fuzz13.wasm and b/unittests/contracts/fuzz13.wasm differ diff --git a/unittests/contracts/test_wasts.hpp b/unittests/contracts/test_wasts.hpp index 15fcefde131..b1272a7afef 100644 --- a/unittests/contracts/test_wasts.hpp +++ b/unittests/contracts/test_wasts.hpp @@ -633,3 +633,17 @@ static const char memory_growth_memset_test[] = R"=====( ) ) )====="; + +static const char large_maligned_host_ptr[] = R"=====( +(module + (export "apply" (func $$apply)) + (import "env" "get_active_producers" (func $$get_active_producers (param i32 i32) (result i32))) + (memory $$0 ${MAX_WASM_PAGES}) + (func $$apply (param i64) (param i64) (param i64) + (drop (call $$get_active_producers + (i32.const 1) + (i32.const ${MAX_NAME_ARRAY}) + )) + ) +) +)====="; \ No newline at end of file diff --git a/unittests/currency_tests.cpp b/unittests/currency_tests.cpp index bf909403ff3..2d94d19f30f 100644 --- a/unittests/currency_tests.cpp +++ b/unittests/currency_tests.cpp @@ -1,3 +1,7 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" #include @@ -7,17 +11,13 @@ #include #include -#include -#include - -#include -#include - #include #include #include +#include + #ifdef NON_VALIDATING_TEST #define TESTER tester #else @@ -75,10 +75,10 @@ class currency_tester : public TESTER { } currency_tester() - :TESTER(),abi_ser(json::from_string(eosio_token_abi).as(), abi_serializer_max_time) + :TESTER(),abi_ser(json::from_string(contracts::eosio_token_abi().data()).as(), abi_serializer_max_time) { create_account( N(eosio.token)); - set_code( N(eosio.token), eosio_token_wast ); + set_code( N(eosio.token), contracts::eosio_token_wasm() ); auto result = push_action(N(eosio.token), N(create), mutable_variant_object() ("issuer", eosio_token) @@ -406,10 +406,10 @@ BOOST_FIXTURE_TEST_CASE( test_proxy, currency_tester ) try { create_accounts( {N(alice), N(proxy)} ); produce_block(); - set_code(N(proxy), proxy_wast); + set_code(N(proxy), contracts::proxy_wasm()); produce_blocks(1); - abi_serializer proxy_abi_ser(json::from_string(proxy_abi).as(), abi_serializer_max_time); + abi_serializer proxy_abi_ser(json::from_string(contracts::proxy_abi().data()).as(), abi_serializer_max_time); // set up proxy owner { @@ -424,7 +424,7 @@ BOOST_FIXTURE_TEST_CASE( test_proxy, currency_tester ) try { abi_serializer_max_time ); trx.actions.emplace_back(std::move(setowner_act)); - + set_transaction_headers(trx); trx.sign(get_private_key(N(alice), "active"), control->get_chain_id()); push_transaction(trx); @@ -461,11 +461,11 @@ BOOST_FIXTURE_TEST_CASE( test_deferred_failure, currency_tester ) try { create_accounts( {N(alice), N(bob), N(proxy)} ); produce_block(); - set_code(N(proxy), proxy_wast); - set_code(N(bob), proxy_wast); + set_code(N(proxy), contracts::proxy_wasm()); + set_code(N(bob), contracts::proxy_wasm()); produce_blocks(1); - abi_serializer proxy_abi_ser(json::from_string(proxy_abi).as(), abi_serializer_max_time); + abi_serializer proxy_abi_ser(json::from_string(contracts::proxy_abi().data()).as(), abi_serializer_max_time); // set up proxy owner { @@ -581,7 +581,6 @@ BOOST_FIXTURE_TEST_CASE( test_input_quantity, currency_tester ) try { BOOST_CHECK_EQUAL(1000000, get_balance(N(alice)).get_amount()); } - // transfer using different symbol name fails { BOOST_REQUIRE_THROW(transfer(N(alice), N(carl), "20.50 USD"), eosio_assert_message_exception); diff --git a/unittests/database_tests.cpp b/unittests/database_tests.cpp index 7cb35e85be5..21dabc36c56 100644 --- a/unittests/database_tests.cpp +++ b/unittests/database_tests.cpp @@ -2,9 +2,9 @@ * @file * @copyright defined in eos/LICENSE */ - -#include #include +#include + #include #include @@ -15,7 +15,6 @@ #define TESTER validating_tester #endif - using namespace eosio::chain; using namespace eosio::testing; namespace bfs = boost::filesystem; @@ -100,5 +99,4 @@ BOOST_AUTO_TEST_SUITE(database_tests) } FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/delay_tests.cpp b/unittests/delay_tests.cpp index 9f14de4107c..523555bb936 100644 --- a/unittests/delay_tests.cpp +++ b/unittests/delay_tests.cpp @@ -1,10 +1,15 @@ -#include -#include -#include -#include +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #include -#include -#include +#include +#include +#include + +#include + +#include #ifdef NON_VALIDATING_TEST #define TESTER tester @@ -97,8 +102,8 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -235,8 +240,8 @@ BOOST_AUTO_TEST_CASE(delete_auth_test) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -255,7 +260,7 @@ BOOST_AUTO_TEST_CASE(delete_auth_test) { try { expect_assert_message(e, "permission_query_exception: Permission Query Exception\nFailed to retrieve permission"); return true; }); - + // update auth chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") @@ -372,8 +377,8 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_parent_permission_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -510,8 +515,8 @@ BOOST_AUTO_TEST_CASE( link_delay_direct_walk_parent_permissions_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -654,8 +659,8 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -845,8 +850,8 @@ BOOST_AUTO_TEST_CASE( link_delay_permission_change_with_delay_heirarchy_test ) { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -1042,8 +1047,8 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -1244,8 +1249,8 @@ BOOST_AUTO_TEST_CASE( link_delay_unlink_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -1433,8 +1438,8 @@ BOOST_AUTO_TEST_CASE( link_delay_link_change_heirarchy_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -1624,8 +1629,8 @@ BOOST_AUTO_TEST_CASE( mindelay_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -1756,8 +1761,8 @@ BOOST_AUTO_TEST_CASE( canceldelay_test ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(10); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -1993,8 +1998,8 @@ BOOST_AUTO_TEST_CASE( canceldelay_test2 ) { try { chain.create_account(N(eosio.token)); chain.produce_blocks(); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); @@ -2279,8 +2284,8 @@ BOOST_AUTO_TEST_CASE( max_transaction_delay_execute ) { try { const auto& tester_account = N(tester); chain.create_account(N(eosio.token)); - chain.set_code(N(eosio.token), eosio_token_wast); - chain.set_abi(N(eosio.token), eosio_token_abi); + chain.set_code(N(eosio.token), contracts::eosio_token_wasm()); + chain.set_abi(N(eosio.token), contracts::eosio_token_abi().data()); chain.produce_blocks(); chain.create_account(N(tester)); diff --git a/unittests/eosio.token_tests.cpp b/unittests/eosio.token_tests.cpp new file mode 100644 index 00000000000..41185faae75 --- /dev/null +++ b/unittests/eosio.token_tests.cpp @@ -0,0 +1,272 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include +#include + +#include + +#include + +#include + +#include + +using namespace eosio::testing; +using namespace eosio; +using namespace eosio::chain; +using namespace eosio::testing; +using namespace fc; +using namespace std; + +using mvo = fc::mutable_variant_object; + +class eosio_token_tester : public tester { +public: + + eosio_token_tester() { + produce_blocks( 2 ); + + create_accounts( { N(alice), N(bob), N(carol), N(eosio.token) } ); + produce_blocks( 2 ); + + set_code( N(eosio.token), contracts::eosio_token_wasm() ); + set_abi( N(eosio.token), contracts::eosio_token_abi().data() ); + + produce_blocks(); + + const auto& accnt = control->db().get( N(eosio.token) ); + abi_def abi; + BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); + abi_ser.set_abi(abi, abi_serializer_max_time); + } + + action_result push_action( const account_name& signer, const action_name &name, const variant_object &data ) { + string action_type_name = abi_ser.get_action_type(name); + + action act; + act.account = N(eosio.token); + act.name = name; + act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer_max_time ); + + return base_tester::push_action( std::move(act), uint64_t(signer)); + } + + fc::variant get_stats( const string& symbolname ) + { + auto symb = eosio::chain::symbol::from_string(symbolname); + auto symbol_code = symb.to_symbol_code().value; + vector data = get_row_by_account( N(eosio.token), symbol_code, N(stat), symbol_code ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "currency_stats", data, abi_serializer_max_time ); + } + + fc::variant get_account( account_name acc, const string& symbolname) + { + auto symb = eosio::chain::symbol::from_string(symbolname); + auto symbol_code = symb.to_symbol_code().value; + vector data = get_row_by_account( N(eosio.token), acc, N(accounts), symbol_code ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "account", data, abi_serializer_max_time ); + } + + action_result create( account_name issuer, + asset maximum_supply ) { + + return push_action( N(eosio.token), N(create), mvo() + ( "issuer", issuer) + ( "maximum_supply", maximum_supply) + ); + } + + action_result issue( account_name issuer, account_name to, asset quantity, string memo ) { + return push_action( issuer, N(issue), mvo() + ( "to", to) + ( "quantity", quantity) + ( "memo", memo) + ); + } + + action_result transfer( account_name from, + account_name to, + asset quantity, + string memo ) { + return push_action( from, N(transfer), mvo() + ( "from", from) + ( "to", to) + ( "quantity", quantity) + ( "memo", memo) + ); + } + + abi_serializer abi_ser; +}; + +BOOST_AUTO_TEST_SUITE(eosio_token_tests) + +BOOST_FIXTURE_TEST_CASE( create_tests, eosio_token_tester ) try { + + auto token = create( N(alice), asset::from_string("1000.000 TKN")); + auto stats = get_stats("3,TKN"); + REQUIRE_MATCHING_OBJECT( stats, mvo() + ("supply", "0.000 TKN") + ("max_supply", "1000.000 TKN") + ("issuer", "alice") + ); + produce_blocks(1); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( create_negative_max_supply, eosio_token_tester ) try { + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "max-supply must be positive" ), + create( N(alice), asset::from_string("-1000.000 TKN")) + ); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( symbol_already_exists, eosio_token_tester ) try { + + auto token = create( N(alice), asset::from_string("100 TKN")); + auto stats = get_stats("0,TKN"); + REQUIRE_MATCHING_OBJECT( stats, mvo() + ("supply", "0 TKN") + ("max_supply", "100 TKN") + ("issuer", "alice") + ); + produce_blocks(1); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "token with symbol already exists" ), + create( N(alice), asset::from_string("100 TKN")) + ); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( create_max_supply, eosio_token_tester ) try { + + auto token = create( N(alice), asset::from_string("4611686018427387903 TKN")); + auto stats = get_stats("0,TKN"); + REQUIRE_MATCHING_OBJECT( stats, mvo() + ("supply", "0 TKN") + ("max_supply", "4611686018427387903 TKN") + ("issuer", "alice") + ); + produce_blocks(1); + + asset max(10, symbol(SY(0, NKT))); + share_type amount = 4611686018427387904; + static_assert(sizeof(share_type) <= sizeof(asset), "asset changed so test is no longer valid"); + static_assert(std::is_trivially_copyable::value, "asset is not trivially copyable"); + memcpy(&max, &amount, sizeof(share_type)); // hack in an invalid amount + + BOOST_CHECK_EXCEPTION( create( N(alice), max) , asset_type_exception, [](const asset_type_exception& e) { + return expect_assert_message(e, "magnitude of asset amount must be less than 2^62"); + }); + + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( create_max_decimals, eosio_token_tester ) try { + + auto token = create( N(alice), asset::from_string("1.000000000000000000 TKN")); + auto stats = get_stats("18,TKN"); + REQUIRE_MATCHING_OBJECT( stats, mvo() + ("supply", "0.000000000000000000 TKN") + ("max_supply", "1.000000000000000000 TKN") + ("issuer", "alice") + ); + produce_blocks(1); + + asset max(10, symbol(SY(0, NKT))); + //1.0000000000000000000 => 0x8ac7230489e80000L + share_type amount = 0x8ac7230489e80000L; + static_assert(sizeof(share_type) <= sizeof(asset), "asset changed so test is no longer valid"); + static_assert(std::is_trivially_copyable::value, "asset is not trivially copyable"); + memcpy(&max, &amount, sizeof(share_type)); // hack in an invalid amount + + BOOST_CHECK_EXCEPTION( create( N(alice), max) , asset_type_exception, [](const asset_type_exception& e) { + return expect_assert_message(e, "magnitude of asset amount must be less than 2^62"); + }); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( issue_tests, eosio_token_tester ) try { + + auto token = create( N(alice), asset::from_string("1000.000 TKN")); + produce_blocks(1); + + issue( N(alice), N(alice), asset::from_string("500.000 TKN"), "hola" ); + + auto stats = get_stats("3,TKN"); + REQUIRE_MATCHING_OBJECT( stats, mvo() + ("supply", "500.000 TKN") + ("max_supply", "1000.000 TKN") + ("issuer", "alice") + ); + + auto alice_balance = get_account(N(alice), "3,TKN"); + REQUIRE_MATCHING_OBJECT( alice_balance, mvo() + ("balance", "500.000 TKN") + ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "quantity exceeds available supply" ), + issue( N(alice), N(alice), asset::from_string("500.001 TKN"), "hola" ) + ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "must issue positive quantity" ), + issue( N(alice), N(alice), asset::from_string("-1.000 TKN"), "hola" ) + ); + + BOOST_REQUIRE_EQUAL( success(), + issue( N(alice), N(alice), asset::from_string("1.000 TKN"), "hola" ) + ); + + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( transfer_tests, eosio_token_tester ) try { + + auto token = create( N(alice), asset::from_string("1000 CERO")); + produce_blocks(1); + + issue( N(alice), N(alice), asset::from_string("1000 CERO"), "hola" ); + + auto stats = get_stats("0,CERO"); + REQUIRE_MATCHING_OBJECT( stats, mvo() + ("supply", "1000 CERO") + ("max_supply", "1000 CERO") + ("issuer", "alice") + ); + + auto alice_balance = get_account(N(alice), "0,CERO"); + REQUIRE_MATCHING_OBJECT( alice_balance, mvo() + ("balance", "1000 CERO") + ); + + transfer( N(alice), N(bob), asset::from_string("300 CERO"), "hola" ); + + alice_balance = get_account(N(alice), "0,CERO"); + REQUIRE_MATCHING_OBJECT( alice_balance, mvo() + ("balance", "700 CERO") + ("frozen", 0) + ("whitelist", 1) + ); + + auto bob_balance = get_account(N(bob), "0,CERO"); + REQUIRE_MATCHING_OBJECT( bob_balance, mvo() + ("balance", "300 CERO") + ("frozen", 0) + ("whitelist", 1) + ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "overdrawn balance" ), + transfer( N(alice), N(bob), asset::from_string("701 CERO"), "hola" ) + ); + + BOOST_REQUIRE_EQUAL( wasm_assert_msg( "must transfer positive quantity" ), + transfer( N(alice), N(bob), asset::from_string("-1000 CERO"), "hola" ) + ); + + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/eosio_system_tester.hpp b/unittests/eosio_system_tester.hpp index 194d52330ea..8c06f187910 100644 --- a/unittests/eosio_system_tester.hpp +++ b/unittests/eosio_system_tester.hpp @@ -4,20 +4,13 @@ */ #pragma once -#include #include - -#include -#include - -#include -#include - -#include -#include +#include #include +#include + using namespace eosio::chain; using namespace eosio::testing; using namespace fc; @@ -49,11 +42,10 @@ class eosio_system_tester : public TESTER { create_accounts({ N(eosio.token), N(eosio.ram), N(eosio.ramfee), N(eosio.stake), N(eosio.bpay), N(eosio.vpay), N(eosio.saving), N(eosio.names) }); - produce_blocks( 100 ); - set_code( N(eosio.token), eosio_token_wast ); - set_abi( N(eosio.token), eosio_token_abi ); + set_code( N(eosio.token), contracts::eosio_token_wasm() ); + set_abi( N(eosio.token), contracts::eosio_token_abi().data() ); { const auto& accnt = control->db().get( N(eosio.token) ); @@ -66,8 +58,13 @@ class eosio_system_tester : public TESTER { issue(config::system_account_name, core_from_string("1000000000.0000")); BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance( "eosio" ) ); - set_code( config::system_account_name, eosio_system_wast ); - set_abi( config::system_account_name, eosio_system_abi ); + set_code( config::system_account_name, contracts::eosio_system_wasm() ); + set_abi( config::system_account_name, contracts::eosio_system_abi().data() ); + + base_tester::push_action(config::system_account_name, N(init), + config::system_account_name, mutable_variant_object() + ("version", 0) + ("core", CORE_SYM_STR)); { const auto& accnt = control->db().get( config::system_account_name ); @@ -85,6 +82,15 @@ class eosio_system_tester : public TESTER { BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance("eosio") + get_balance("eosio.ramfee") + get_balance("eosio.stake") + get_balance("eosio.ram") ); } + action_result open( account_name owner, + const string& symbolname, + account_name ram_payer ) { + return push_action( ram_payer, N(open), mvo() + ( "owner", owner ) + ( "symbol", symbolname ) + ( "ram_payer", ram_payer ) + ); + } void create_accounts_with_resources( vector accounts, account_name creator = config::system_account_name ) { for( auto a : accounts ) { @@ -417,8 +423,8 @@ class eosio_system_tester : public TESTER { ("is_priv", 1) ); - set_code( N(eosio.msig), eosio_msig_wast ); - set_abi( N(eosio.msig), eosio_msig_abi ); + set_code( N(eosio.msig), contracts::eosio_msig_wasm() ); + set_abi( N(eosio.msig), contracts::eosio_msig_abi().data() ); produce_blocks(); const auto& accnt = control->db().get( N(eosio.msig) ); @@ -535,7 +541,6 @@ inline fc::mutable_variant_object voter( account_name acct ) { ("proxy", name(0).to_string()) ("producers", variants() ) ("staked", int64_t(0)) - //("last_vote_weight", double(0)) ("proxied_vote_weight", double(0)) ("is_proxy", 0) ; diff --git a/unittests/forked_tests.cpp b/unittests/forked_tests.cpp index 9a07999f7a8..d2981e3249c 100644 --- a/unittests/forked_tests.cpp +++ b/unittests/forked_tests.cpp @@ -1,15 +1,21 @@ -#include -#include +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #include -#include +#include +#include -#include -#include +#include #include #include +#include + +#include + using namespace eosio::chain; using namespace eosio::testing; @@ -21,13 +27,35 @@ public_key_type get_public_key( name keyname, string role ){ return get_private_key( keyname, role ).get_public_key(); } -void push_blocks( tester& from, tester& to ) { - while( to.control->fork_db_head_block_num() < from.control->fork_db_head_block_num() ) { - auto fb = from.control->fetch_block_by_number( to.control->fork_db_head_block_num()+1 ); +void push_blocks( tester& from, tester& to, uint32_t block_num_limit = std::numeric_limits::max() ) { + while( to.control->fork_db_pending_head_block_num() + < std::min( from.control->fork_db_pending_head_block_num(), block_num_limit ) ) + { + auto fb = from.control->fetch_block_by_number( to.control->fork_db_pending_head_block_num()+1 ); to.push_block( fb ); } } +bool produce_empty_blocks_until( tester& t, + account_name last_producer, + account_name next_producer, + uint32_t max_num_blocks_to_produce = std::numeric_limits::max() ) +{ + auto condition_satisfied = [&t, last_producer, next_producer]() { + return t.control->pending_block_producer() == next_producer && t.control->head_block_producer() == last_producer; + }; + + for( uint32_t blocks_produced = 0; + blocks_produced < max_num_blocks_to_produce; + t.produce_block(), ++blocks_produced ) + { + if( condition_satisfied() ) + return true; + } + + return condition_satisfied(); +} + BOOST_AUTO_TEST_SUITE(forked_tests) BOOST_AUTO_TEST_CASE( irrblock ) try { @@ -60,9 +88,7 @@ BOOST_AUTO_TEST_CASE( fork_with_bad_block ) try { auto res = bios.set_producers( {N(a),N(b),N(c),N(d),N(e)} ); // run until the producers are installed and its the start of "a's" round - while( bios.control->pending_block_producer().to_string() != "a" || bios.control->head_block_state()->header.producer.to_string() != "e") { - bios.produce_block(); - } + BOOST_REQUIRE( produce_empty_blocks_until( bios, N(e), N(a) ) ); // sync remote node tester remote; @@ -158,8 +184,8 @@ BOOST_AUTO_TEST_CASE( forking ) try { auto r2 = c.create_accounts( {N(eosio.token)} ); wdump((fc::json::to_pretty_string(r2))); - c.set_code( N(eosio.token), eosio_token_wast ); - c.set_abi( N(eosio.token), eosio_token_abi ); + c.set_code( N(eosio.token), contracts::eosio_token_wasm() ); + c.set_abi( N(eosio.token), contracts::eosio_token_abi().data() ); c.produce_blocks(10); @@ -356,21 +382,133 @@ BOOST_AUTO_TEST_CASE( read_modes ) try { auto res = c.set_producers( {N(dan),N(sam),N(pam)} ); c.produce_blocks(200); auto head_block_num = c.control->head_block_num(); + auto last_irreversible_block_num = c.control->last_irreversible_block_num(); tester head(true, db_read_mode::HEAD); push_blocks(c, head); - BOOST_REQUIRE_EQUAL(head_block_num, head.control->fork_db_head_block_num()); - BOOST_REQUIRE_EQUAL(head_block_num, head.control->head_block_num()); + BOOST_CHECK_EQUAL(head_block_num, head.control->fork_db_head_block_num()); + BOOST_CHECK_EQUAL(head_block_num, head.control->head_block_num()); tester read_only(false, db_read_mode::READ_ONLY); push_blocks(c, read_only); - BOOST_REQUIRE_EQUAL(head_block_num, read_only.control->fork_db_head_block_num()); - BOOST_REQUIRE_EQUAL(head_block_num, read_only.control->head_block_num()); + BOOST_CHECK_EQUAL(head_block_num, read_only.control->fork_db_head_block_num()); + BOOST_CHECK_EQUAL(head_block_num, read_only.control->head_block_num()); tester irreversible(true, db_read_mode::IRREVERSIBLE); push_blocks(c, irreversible); - BOOST_REQUIRE_EQUAL(head_block_num, irreversible.control->fork_db_head_block_num()); - BOOST_REQUIRE_EQUAL(head_block_num - 49, irreversible.control->head_block_num()); + BOOST_CHECK_EQUAL(head_block_num, irreversible.control->fork_db_pending_head_block_num()); + BOOST_CHECK_EQUAL(last_irreversible_block_num, irreversible.control->fork_db_head_block_num()); + BOOST_CHECK_EQUAL(last_irreversible_block_num, irreversible.control->head_block_num()); + +} FC_LOG_AND_RETHROW() + + +BOOST_AUTO_TEST_CASE( irreversible_mode ) try { + auto does_account_exist = []( const tester& t, account_name n ) { + const auto& db = t.control->db(); + return (db.find( n ) != nullptr); + }; + + tester main; + + main.create_accounts( {N(producer1), N(producer2)} ); + main.produce_block(); + main.set_producers( {N(producer1), N(producer2)} ); + main.produce_block(); + BOOST_REQUIRE( produce_empty_blocks_until( main, N(producer1), N(producer2), 26) ); + + main.create_accounts( {N(alice)} ); + main.produce_block(); + auto hbn1 = main.control->head_block_num(); + auto lib1 = main.control->last_irreversible_block_num(); + + BOOST_REQUIRE( produce_empty_blocks_until( main, N(producer2), N(producer1), 11) ); + + auto hbn2 = main.control->head_block_num(); + auto lib2 = main.control->last_irreversible_block_num(); + + BOOST_REQUIRE( lib2 < hbn1 ); + + tester other; + + push_blocks( main, other ); + BOOST_CHECK_EQUAL( other.control->head_block_num(), hbn2 ); + + BOOST_REQUIRE( produce_empty_blocks_until( main, N(producer1), N(producer2), 12) ); + BOOST_REQUIRE( produce_empty_blocks_until( main, N(producer2), N(producer1), 12) ); + + auto hbn3 = main.control->head_block_num(); + auto lib3 = main.control->last_irreversible_block_num(); + + BOOST_REQUIRE( lib3 >= hbn1 ); + + BOOST_CHECK_EQUAL( does_account_exist( main, N(alice) ), true ); + + // other forks away from main after hbn2 + BOOST_REQUIRE_EQUAL( other.control->head_block_producer().to_string(), "producer2" ); + + other.produce_block( fc::milliseconds( 13 * config::block_interval_ms ) ); // skip over producer1's round + BOOST_REQUIRE_EQUAL( other.control->head_block_producer().to_string(), "producer2" ); + auto fork_first_block_id = other.control->head_block_id(); + wlog( "{w}", ("w", fork_first_block_id)); + + BOOST_REQUIRE( produce_empty_blocks_until( other, N(producer2), N(producer1), 11) ); // finish producer2's round + BOOST_REQUIRE_EQUAL( other.control->pending_block_producer().to_string(), "producer1" ); + + // Repeat two more times to ensure other has a longer chain than main + other.produce_block( fc::milliseconds( 13 * config::block_interval_ms ) ); // skip over producer1's round + BOOST_REQUIRE( produce_empty_blocks_until( other, N(producer2), N(producer1), 11) ); // finish producer2's round + + other.produce_block( fc::milliseconds( 13 * config::block_interval_ms ) ); // skip over producer1's round + BOOST_REQUIRE( produce_empty_blocks_until( other, N(producer2), N(producer1), 11) ); // finish producer2's round + + auto hbn4 = other.control->head_block_num(); + auto lib4 = other.control->last_irreversible_block_num(); + + BOOST_REQUIRE( hbn4 > hbn3 ); + BOOST_REQUIRE( lib4 < hbn1 ); + + tester irreversible(false, db_read_mode::IRREVERSIBLE); + + push_blocks( main, irreversible, hbn1 ); + + BOOST_CHECK_EQUAL( irreversible.control->fork_db_pending_head_block_num(), hbn1 ); + BOOST_CHECK_EQUAL( irreversible.control->head_block_num(), lib1 ); + BOOST_CHECK_EQUAL( does_account_exist( irreversible, N(alice) ), false ); + + push_blocks( other, irreversible, hbn4 ); + + BOOST_CHECK_EQUAL( irreversible.control->fork_db_pending_head_block_num(), hbn4 ); + BOOST_CHECK_EQUAL( irreversible.control->head_block_num(), lib4 ); + BOOST_CHECK_EQUAL( does_account_exist( irreversible, N(alice) ), false ); + + // force push blocks from main to irreversible creating a new branch in irreversible's fork database + for( uint32_t n = hbn2 + 1; n <= hbn3; ++n ) { + auto fb = main.control->fetch_block_by_number( n ); + irreversible.push_block( fb ); + } + + BOOST_CHECK_EQUAL( irreversible.control->fork_db_pending_head_block_num(), hbn3 ); + BOOST_CHECK_EQUAL( irreversible.control->head_block_num(), lib3 ); + BOOST_CHECK_EQUAL( does_account_exist( irreversible, N(alice) ), true ); + + { + auto bs = irreversible.control->fetch_block_state_by_id( fork_first_block_id ); + BOOST_REQUIRE( bs && bs->id == fork_first_block_id ); + } + + main.produce_block(); + auto hbn5 = main.control->head_block_num(); + auto lib5 = main.control->last_irreversible_block_num(); + + BOOST_REQUIRE( lib5 > lib3 ); + + push_blocks( main, irreversible, hbn5 ); + + { + auto bs = irreversible.control->fetch_block_state_by_id( fork_first_block_id ); + BOOST_REQUIRE( !bs ); + } } FC_LOG_AND_RETHROW() diff --git a/unittests/fuzz13.wasm b/unittests/fuzz13.wasm deleted file mode 100644 index 8ec5122bce1..00000000000 Binary files a/unittests/fuzz13.wasm and /dev/null differ diff --git a/unittests/identity_tests.cpp b/unittests/identity_tests.cpp deleted file mode 100644 index 0ddbcab3cb1..00000000000 --- a/unittests/identity_tests.cpp +++ /dev/null @@ -1,683 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#ifdef NON_VALIDATING_TEST -#define TESTER tester -#else -#define TESTER validating_tester -#endif - -using namespace eosio; -using namespace eosio::chain; -using namespace eosio::testing; -using namespace fc; - -class identity_tester : public TESTER { -public: - - identity_tester() { - produce_blocks(2); - - create_accounts( {N(identity), N(identitytest), N(alice), N(bob), N(carol)} ); - produce_blocks(1000); - - set_code(N(identity), identity_wast); - set_abi(N(identity), identity_abi); - set_code(N(identitytest), identity_test_wast); - set_abi(N(identitytest), identity_test_abi); - produce_blocks(1); - - const auto& accnt = control->db().get( N(identity) ); - abi_def abi; - BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - abi_ser.set_abi(abi, abi_serializer_max_time); - - const auto& acnt_test = control->db().get( N(identitytest) ); - abi_def abi_test; - BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(acnt_test.abi, abi_test), true); - abi_ser_test.set_abi(abi_test, abi_serializer_max_time); - - const auto& ap = control->active_producers(); - FC_ASSERT(0 < ap.producers.size(), "No producers"); - producer_name = (string)ap.producers.front().producer_name; - } - - uint64_t get_result_uint64() { - const auto& db = control->db(); - const auto* t_id = db.find(boost::make_tuple(N(identitytest), 0, N(result))); - FC_ASSERT(t_id != 0, "Table id not found"); - - const auto& idx = db.get_index(); - - auto itr = idx.lower_bound(boost::make_tuple(t_id->id)); - FC_ASSERT( itr != idx.end() && itr->t_id == t_id->id, "lower_bound failed"); - - FC_ASSERT( N(result) == itr->primary_key, "row with result not found"); - FC_ASSERT( sizeof(uint64_t) == itr->value.size(), "unexpected result size"); - return *reinterpret_cast(itr->value.data()); - } - - uint64_t get_owner_for_identity(uint64_t identity) - { - action get_owner_act; - get_owner_act.account = N(identitytest); - get_owner_act.name = N(getowner); - get_owner_act.data = abi_ser_test.variant_to_binary("getowner", mutable_variant_object() - ("identity", identity), - abi_serializer_max_time - ); - BOOST_REQUIRE_EQUAL(success(), push_action(std::move(get_owner_act), N(alice))); - return get_result_uint64(); - } - - uint64_t get_identity_for_account(const string& account) - { - action get_identity_act; - get_identity_act.account = N(identitytest); - get_identity_act.name = N(getidentity); - get_identity_act.data = abi_ser_test.variant_to_binary("getidentity", mutable_variant_object() - ("account", account), - abi_serializer_max_time - ); - BOOST_REQUIRE_EQUAL(success(), push_action(std::move(get_identity_act), N(alice))); - return get_result_uint64(); - } - - action_result create_identity(const string& account_name, uint64_t identity, bool auth = true) { - action create_act; - create_act.account = N(identity); - create_act.name = N(create); - create_act.data = abi_ser.variant_to_binary("create", mutable_variant_object() - ("creator", account_name) - ("identity", identity), - abi_serializer_max_time - ); - return push_action( std::move(create_act), (auth ? string_to_name(account_name.c_str()) : (string_to_name(account_name.c_str()) == N(bob)) ? N(alice) : N(bob))); - } - - fc::variant get_identity(uint64_t idnt) { - const auto& db = control->db(); - const auto* t_id = db.find(boost::make_tuple(N(identity), N(identity), N(ident))); - FC_ASSERT(t_id != 0, "object not found"); - - const auto& idx = db.get_index(); - - auto itr = idx.lower_bound(boost::make_tuple(t_id->id, idnt)); - FC_ASSERT( itr != idx.end() && itr->t_id == t_id->id, "lower_bound failed"); - BOOST_REQUIRE_EQUAL(idnt, itr->primary_key); - - vector data; - copy_row(*itr, data); - return abi_ser.binary_to_variant("identrow", data, abi_serializer_max_time); - } - - action_result certify(const string& certifier, uint64_t identity, const vector& fields, bool auth = true) { - action cert_act; - cert_act.account = N(identity); - cert_act.name = N(certprop); - cert_act.data = abi_ser.variant_to_binary("certprop", mutable_variant_object() - ("bill_storage_to", certifier) - ("certifier", certifier) - ("identity", identity) - ("value", fields), - abi_serializer_max_time - ); - return push_action( std::move(cert_act), (auth ? string_to_name(certifier.c_str()) : (string_to_name(certifier.c_str()) == N(bob)) ? N(alice) : N(bob))); - } - - fc::variant get_certrow(uint64_t identity, const string& property, uint64_t trusted, const string& certifier) { - const auto& db = control->db(); - const auto* t_id = db.find(boost::make_tuple(N(identity), identity, N( certs ))); - if ( !t_id ) { - return fc::variant(nullptr); - } - - const auto& idx = db.get_index(); - auto key = key256::make_from_word_sequence(string_to_name(property.c_str()), trusted, string_to_name(certifier.c_str())); - - auto itr = idx.lower_bound(boost::make_tuple(t_id->id, key.get_array())); - if (itr != idx.end() && itr->t_id == t_id->id && itr->secondary_key == key.get_array()) { - auto primary_key = itr->primary_key; - const auto& idx = db.get_index(); - - auto itr = idx.lower_bound(boost::make_tuple(t_id->id, primary_key)); - FC_ASSERT( itr != idx.end() && itr->t_id == t_id->id && primary_key == itr->primary_key, - "Record found in secondary index, but not found in primary index." - ); - vector data; - copy_row(*itr, data); - return abi_ser.binary_to_variant("certrow", data, abi_serializer_max_time); - } else { - return fc::variant(nullptr); - } - } - - fc::variant get_accountrow(const string& account) { - const auto& db = control->db(); - uint64_t acnt = string_to_name(account.c_str()); - const auto* t_id = db.find(boost::make_tuple(N(identity), acnt, N(account))); - if (!t_id) { - return fc::variant(nullptr); - } - const auto& idx = db.get_index(); - auto itr = idx.lower_bound(boost::make_tuple(t_id->id, N(account))); - if( itr != idx.end() && itr->t_id == t_id->id && N(account) == itr->primary_key) { - vector data; - copy_row(*itr, data); - return abi_ser.binary_to_variant("accountrow", data, abi_serializer_max_time); - } else { - return fc::variant(nullptr); - } - } - - action_result settrust(const string& trustor, const string& trusting, uint64_t trust, bool auth = true) - { - signed_transaction trx; - action settrust_act; - settrust_act.account = N(identity); - settrust_act.name = N(settrust); - settrust_act.data = abi_ser.variant_to_binary("settrust", mutable_variant_object() - ("trustor", trustor) - ("trusting", trusting) - ("trust", trust), - abi_serializer_max_time - ); - auto tr = string_to_name(trustor.c_str()); - return push_action( std::move(settrust_act), (auth ? tr : 0) ); - } - - bool get_trust(const string& trustor, const string& trusting) { - const auto& db = control->db(); - const auto* t_id = db.find(boost::make_tuple(N(identity), string_to_name(trustor.c_str()), N(trust))); - if (!t_id) { - return false; - } - - uint64_t tng = string_to_name(trusting.c_str()); - const auto& idx = db.get_index(); - auto itr = idx.lower_bound(boost::make_tuple(t_id->id, tng)); - return ( itr != idx.end() && itr->t_id == t_id->id && tng == itr->primary_key ); //true if found - } - -public: - abi_serializer abi_ser; - abi_serializer abi_ser_test; - std::string producer_name; -}; - -constexpr uint64_t identity_val = 0xffffffffffffffff; //64-bit value - -BOOST_AUTO_TEST_SUITE(identity_tests) - -BOOST_FIXTURE_TEST_CASE( identity_create, identity_tester ) try { - - BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); - fc::variant idnt = get_identity(identity_val); - BOOST_REQUIRE_EQUAL( identity_val, idnt["identity"].as_uint64()); - BOOST_REQUIRE_EQUAL( "alice", idnt["creator"].as_string()); - - //attempts to create already existing identity should fail - BOOST_REQUIRE_EQUAL(wasm_assert_msg("identity already exists"), create_identity("alice", identity_val)); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("identity already exists"), create_identity("bob", identity_val)); - - //alice can create more identities - BOOST_REQUIRE_EQUAL(success(), create_identity("alice", 2)); - fc::variant idnt2 = get_identity(2); - BOOST_REQUIRE_EQUAL( 2, idnt2["identity"].as_uint64()); - BOOST_REQUIRE_EQUAL( "alice", idnt2["creator"].as_string()); - - //bob can create an identity as well - BOOST_REQUIRE_EQUAL(success(), create_identity("bob", 1)); - - //identity == 0 has special meaning, should be impossible to create - BOOST_REQUIRE_EQUAL(wasm_assert_msg("identity=0 is not allowed"), create_identity("alice", 0)); - - //creating adentity without authentication is not allowed - BOOST_REQUIRE_EQUAL(error("missing authority of alice"), create_identity("alice", 3, false)); - - fc::variant idnt_bob = get_identity(1); - BOOST_REQUIRE_EQUAL( 1, idnt_bob["identity"].as_uint64()); - BOOST_REQUIRE_EQUAL( "bob", idnt_bob["creator"].as_string()); - - //previously created identity should still exist - idnt = get_identity(identity_val); - BOOST_REQUIRE_EQUAL( identity_val, idnt["identity"].as_uint64()); - - } FC_LOG_AND_RETHROW() //identity_create - -BOOST_FIXTURE_TEST_CASE( certify_decertify, identity_tester ) try { - BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); - - //alice (creator of the identity) certifies 1 property - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "name") - ("type", "string") - ("data", to_uint8_vector("Alice Smith")) - ("memo", "") - ("confidence", 100) - })); - - auto obj = get_certrow(identity_val, "name", 0, "alice"); - BOOST_REQUIRE_EQUAL(true, obj.is_object()); - BOOST_REQUIRE_EQUAL( "name", obj["property"].as_string() ); - BOOST_REQUIRE_EQUAL( 0, obj["trusted"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "alice", obj["certifier"].as_string() ); - BOOST_REQUIRE_EQUAL( 100, obj["confidence"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "string", obj["type"].as_string() ); - BOOST_REQUIRE_EQUAL( "Alice Smith", to_string(obj["data"]) ); - - //check that there is no trusted row with the same data - BOOST_REQUIRE_EQUAL(true, get_certrow(identity_val, "name", 1, "alice").is_null()); - - //bob certifies 2 properties - vector fields = { mutable_variant_object() - ("property", "email") - ("type", "string") - ("data", to_uint8_vector("alice@alice.name")) - ("memo", "official email") - ("confidence", 95), - mutable_variant_object() - ("property", "address") - ("type", "string") - ("data", to_uint8_vector("1750 Kraft Drive SW, Blacksburg, VA 24060")) - ("memo", "official address") - ("confidence", 80) - }; - - //shouldn't be able to certify without authorization - BOOST_REQUIRE_EQUAL(error("missing authority of bob"), certify("bob", identity_val, fields, false)); - - //certifying non-existent identity is not allowed - uint64_t non_existent = 11; - BOOST_REQUIRE_EQUAL(wasm_assert_msg("identity does not exist"), - certify("alice", non_existent, vector{ mutable_variant_object() - ("property", "name") - ("type", "string") - ("data", to_uint8_vector("Alice Smith")) - ("memo", "") - ("confidence", 100) - }) - ); - - //parameter "type" should be not longer than 32 bytes - BOOST_REQUIRE_EQUAL(wasm_assert_msg("certrow::type should be not longer than 32 bytes"), - certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "height") - ("type", "super_long_type_name_wich_is_not_allowed") - ("data", to_uint8_vector("Alice Smith")) - ("memo", "") - ("confidence", 100) - }) - ); - - //bob also should be able to certify - BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, fields)); - - obj = get_certrow(identity_val, "email", 0, "bob"); - BOOST_REQUIRE_EQUAL(true, obj.is_object()); - BOOST_REQUIRE_EQUAL( "email", obj["property"].as_string() ); - BOOST_REQUIRE_EQUAL( 0, obj["trusted"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "bob", obj["certifier"].as_string() ); - BOOST_REQUIRE_EQUAL( 95, obj["confidence"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "string", obj["type"].as_string() ); - BOOST_REQUIRE_EQUAL( "alice@alice.name", to_string(obj["data"]) ); - - obj = get_certrow(identity_val, "address", 0, "bob"); - BOOST_REQUIRE_EQUAL(true, obj.is_object()); - BOOST_REQUIRE_EQUAL( "address", obj["property"].as_string() ); - BOOST_REQUIRE_EQUAL( 0, obj["trusted"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "bob", obj["certifier"].as_string() ); - BOOST_REQUIRE_EQUAL( 80, obj["confidence"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "string", obj["type"].as_string() ); - BOOST_REQUIRE_EQUAL( "1750 Kraft Drive SW, Blacksburg, VA 24060", to_string(obj["data"]) ); - - //now alice certifies another email - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "email") - ("type", "string") - ("data", to_uint8_vector("alice.smith@gmail.com")) - ("memo", "") - ("confidence", 100) - })); - obj = get_certrow(identity_val, "email", 0, "alice"); - BOOST_REQUIRE_EQUAL(true, obj.is_object()); - BOOST_REQUIRE_EQUAL( "email", obj["property"].as_string() ); - BOOST_REQUIRE_EQUAL( 0, obj["trusted"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "alice", obj["certifier"].as_string() ); - BOOST_REQUIRE_EQUAL( 100, obj["confidence"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "string", obj["type"].as_string() ); - BOOST_REQUIRE_EQUAL( "alice.smith@gmail.com", to_string(obj["data"]) ); - - //email certification made by bob should be still in place - obj = get_certrow(identity_val, "email", 0, "bob"); - BOOST_REQUIRE_EQUAL( "bob", obj["certifier"].as_string() ); - BOOST_REQUIRE_EQUAL( "alice@alice.name", to_string(obj["data"]) ); - - //remove email certification made by alice - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "email") - ("type", "string") - ("data", to_uint8_vector("")) - ("memo", "") - ("confidence", 0) - })); - BOOST_REQUIRE_EQUAL(true, get_certrow(identity_val, "email", 0, "alice").is_null()); - - //email certification made by bob should still be in place - obj = get_certrow(identity_val, "email", 0, "bob"); - BOOST_REQUIRE_EQUAL( "bob", obj["certifier"].as_string() ); - BOOST_REQUIRE_EQUAL( "alice@alice.name", to_string(obj["data"]) ); - - //name certification made by alice should still be in place - obj = get_certrow(identity_val, "name", 0, "alice"); - BOOST_REQUIRE_EQUAL(true, obj.is_object()); - BOOST_REQUIRE_EQUAL( "Alice Smith", to_string(obj["data"]) ); - -} FC_LOG_AND_RETHROW() //certify_decertify - -BOOST_FIXTURE_TEST_CASE( trust_untrust, identity_tester ) try { - BOOST_REQUIRE_EQUAL(success(), settrust("bob", "alice", 1)); - BOOST_REQUIRE_EQUAL(true, get_trust("bob", "alice")); - - //relation of trust in opposite direction should not exist - BOOST_REQUIRE_EQUAL(false, get_trust("alice", "bob")); - - //remove trust - BOOST_REQUIRE_EQUAL(success(), settrust("bob", "alice", 0)); - BOOST_REQUIRE_EQUAL(false, get_trust("bob", "alice")); - -} FC_LOG_AND_RETHROW() //trust_untrust - -BOOST_FIXTURE_TEST_CASE( certify_decertify_owner, identity_tester ) try { - BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); - - //bob certifies ownership for alice - BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "claiming onwership") - ("confidence", 100) - })); - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "bob").is_object() ); - //it should not affect "account" singleton in alice's scope since it's not self-certification - BOOST_REQUIRE_EQUAL( true, get_accountrow("alice").is_null() ); - //it also shouldn't affect "account" singleton in bob's scope since he certified not himself - BOOST_REQUIRE_EQUAL( true, get_accountrow("bob").is_null() ); - - // alice certifies her ownership, should populate "account" singleton - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "claiming onwership") - ("confidence", 100) - })); - fc::variant certrow = get_certrow(identity_val, "owner", 0, "alice"); - BOOST_REQUIRE_EQUAL( true, certrow.is_object() ); - BOOST_REQUIRE_EQUAL( "owner", certrow["property"].as_string() ); - BOOST_REQUIRE_EQUAL( 0, certrow["trusted"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "alice", certrow["certifier"].as_string() ); - BOOST_REQUIRE_EQUAL( 100, certrow["confidence"].as_uint64() ); - BOOST_REQUIRE_EQUAL( "account", certrow["type"].as_string() ); - BOOST_REQUIRE_EQUAL( N(alice), to_uint64(certrow["data"]) ); - - //check that singleton "account" in the alice's scope contains the identity - fc::variant acntrow = get_accountrow("alice"); - BOOST_REQUIRE_EQUAL( true, certrow.is_object() ); - BOOST_REQUIRE_EQUAL( identity_val, acntrow["identity"].as_uint64() ); - - // ownership was certified by alice, but not by a block producer or someone trusted by a block producer - BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); - - //remove bob's certification - BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "claiming onwership") - ("confidence", 0) - })); - //singleton "account" in the alice's scope still should contain the identity - acntrow = get_accountrow("alice"); - BOOST_REQUIRE_EQUAL( true, certrow.is_object() ); - BOOST_REQUIRE_EQUAL( identity_val, acntrow["identity"].as_uint64() ); - - //remove owner certification - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "claiming onwership") - ("confidence", 0) - })); - certrow = get_certrow(identity_val, "owner", 0, "alice"); - BOOST_REQUIRE_EQUAL(true, certrow.is_null()); - - //check that singleton "account" in the alice's scope doesn't contain the identity - acntrow = get_accountrow("alice"); - BOOST_REQUIRE_EQUAL(true, certrow.is_null()); - -} FC_LOG_AND_RETHROW() //certify_decertify_owner - -BOOST_FIXTURE_TEST_CASE( owner_certified_by_producer, identity_tester ) try { - BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); - - // certify owner by a block producer, should result in trusted certification - BOOST_REQUIRE_EQUAL(success(), certify( producer_name, identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "") - ("confidence", 100) - })); - fc::variant certrow = get_certrow(identity_val, "owner", 1, producer_name); - BOOST_REQUIRE_EQUAL( true, certrow.is_object() ); - BOOST_REQUIRE_EQUAL( "owner", certrow["property"].as_string() ); - BOOST_REQUIRE_EQUAL( 1, certrow["trusted"].as_uint64() ); - BOOST_REQUIRE_EQUAL( producer_name, certrow["certifier"].as_string() ); - BOOST_REQUIRE_EQUAL( N(alice), to_uint64(certrow["data"]) ); - - //uncertified copy of that row shouldn't exist - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, producer_name).is_null()); - - //alice still has not claimed the identity - she is not the official owner yet - BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); - - - //alice claims it - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "claiming onwership") - ("confidence", 100) - })); - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "alice").is_object()); - - //now alice should be the official owner - BOOST_REQUIRE_EQUAL(N(alice), get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(identity_val, get_identity_for_account("alice")); - - //block producer decertifies ownership - BOOST_REQUIRE_EQUAL(success(), certify(producer_name, identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "") - ("confidence", 0) - })); - //self-certification made by alice still exists - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "alice").is_object()); - //but now she is not official owner - BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); - -} FC_LOG_AND_RETHROW() //owner_certified_by_producer - -BOOST_FIXTURE_TEST_CASE( owner_certified_by_trusted_account, identity_tester ) try { - BOOST_REQUIRE_EQUAL(success(), create_identity("bob", identity_val)); - - //alice claims the identity created by bob - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "claiming onwership") - ("confidence", 100) - })); - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "alice").is_object()); - //alice claimed the identity, but it hasn't been certified yet - she is not the official owner - BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); - - //block producer trusts bob - BOOST_REQUIRE_EQUAL(success(), settrust(producer_name, "bob", 1)); - BOOST_REQUIRE_EQUAL(true, get_trust(producer_name, "bob")); - - // bob (trusted account) certifies alice's ownership, it should result in trusted certification - BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "") - ("confidence", 100) - })); - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, "bob").is_object() ); - //no untrusted row should exist - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "bob").is_null() ); - - //now alice should be the official owner - BOOST_REQUIRE_EQUAL(N(alice), get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(identity_val, get_identity_for_account("alice")); - - //block producer stops trusting bob - BOOST_REQUIRE_EQUAL(success(), settrust(producer_name, "bob", 0)); - BOOST_REQUIRE_EQUAL(false, get_trust(producer_name, "bob")); - - //certification made by bob is still flaged as trusted - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, "bob").is_object() ); - - //but now alice shouldn't be the official owner - BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); - -} FC_LOG_AND_RETHROW() //owner_certified_by_trusted_account - -BOOST_FIXTURE_TEST_CASE( owner_certification_becomes_trusted, identity_tester ) try { - BOOST_REQUIRE_EQUAL(success(), create_identity("bob", identity_val)); - - // bob (not trusted so far) certifies alice's ownership, it should result in untrusted certification - BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "") - ("confidence", 100) - })); - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "bob").is_object() ); - //no trusted row should exist - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, "bob").is_null() ); - - //alice claims the identity created by bob - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "claiming onwership") - ("confidence", 100) - })); - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "alice").is_object()); - //alice claimed the identity, but it is certified by untrusted accounts only - she is not the official owner - BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); - - //block producer trusts bob - BOOST_REQUIRE_EQUAL(success(), settrust(producer_name, "bob", 1)); - BOOST_REQUIRE_EQUAL(true, get_trust(producer_name, "bob")); - - //old certification made by bob still shouldn't be flaged as trusted - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 0, "bob").is_object() ); - - //but effectively bob's certification should became trusted - BOOST_REQUIRE_EQUAL(N(alice), get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(identity_val, get_identity_for_account("alice")); - -} FC_LOG_AND_RETHROW() //owner_certification_becomes_trusted - -BOOST_FIXTURE_TEST_CASE( ownership_contradiction, identity_tester ) try { - BOOST_REQUIRE_EQUAL(success(), create_identity("alice", identity_val)); - - //alice claims identity - BOOST_REQUIRE_EQUAL(success(), certify("alice", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "claiming onwership") - ("confidence", 100) - })); - - // block producer certifies alice's ownership - BOOST_REQUIRE_EQUAL(success(), certify(producer_name, identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(alice))) - ("memo", "") - ("confidence", 100) - })); - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, producer_name).is_object() ); - - //now alice is the official owner of the identity - BOOST_REQUIRE_EQUAL(N(alice), get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(identity_val, get_identity_for_account("alice")); - - //bob claims identity - BOOST_REQUIRE_EQUAL(success(), certify("bob", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(bob))) - ("memo", "claiming onwership") - ("confidence", 100) - })); - - - //block producer trusts carol - BOOST_REQUIRE_EQUAL(success(), settrust(producer_name, "carol", 1)); - BOOST_REQUIRE_EQUAL(true, get_trust(producer_name, "carol")); - - //another trusted delegate certifies bob's identity (to the identity already certified to alice) - BOOST_REQUIRE_EQUAL(success(), certify("carol", identity_val, vector{ mutable_variant_object() - ("property", "owner") - ("type", "account") - ("data", to_uint8_vector(N(bob))) - ("memo", "") - ("confidence", 100) - })); - BOOST_REQUIRE_EQUAL( true, get_certrow(identity_val, "owner", 1, producer_name).is_object() ); - - //now neither alice or bob are official owners, because we have 2 trusted certifications in contradiction to each other - BOOST_REQUIRE_EQUAL(0, get_owner_for_identity(identity_val)); - BOOST_REQUIRE_EQUAL(0, get_identity_for_account("alice")); - -} FC_LOG_AND_RETHROW() //ownership_contradiction - -BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/main.cpp b/unittests/main.cpp index 0644ce80545..00fe71891a1 100644 --- a/unittests/main.cpp +++ b/unittests/main.cpp @@ -3,11 +3,15 @@ * @copyright defined in eos/LICENSE */ #include + #include -#include -#include + #include +#include + +#include + //extern uint32_t EOS_TESTING_GENESIS_TIMESTAMP; void translate_fc_exception(const fc::exception &e) { diff --git a/unittests/message_buffer_tests.cpp b/unittests/message_buffer_tests.cpp index ccb69033e8e..7209bda8ce4 100644 --- a/unittests/message_buffer_tests.cpp +++ b/unittests/message_buffer_tests.cpp @@ -2,11 +2,11 @@ * @file * @copyright defined in eos/LICENSE */ +#include -#include #include -#include +#include namespace eosio { using namespace std; @@ -321,4 +321,3 @@ BOOST_AUTO_TEST_CASE(message_buffer_read_peek_bounds_multi) { BOOST_AUTO_TEST_SUITE_END() } // namespace eosio - diff --git a/unittests/misc_tests.cpp b/unittests/misc_tests.cpp index 563c1922e9e..dcc4560b0f0 100644 --- a/unittests/misc_tests.cpp +++ b/unittests/misc_tests.cpp @@ -2,15 +2,16 @@ * @file * @copyright defined in eos/LICENSE */ -#include -#include +#include #include +#include +#include #include -#include #include #include +#include #include #ifdef NON_VALIDATING_TEST @@ -586,7 +587,9 @@ BOOST_AUTO_TEST_CASE(transaction_test) { try { BOOST_CHECK_EQUAL(0, trx.signatures.size()); ((const signed_transaction &)trx).sign( test.get_private_key( config::system_account_name, "active" ), test.control->get_chain_id()); BOOST_CHECK_EQUAL(0, trx.signatures.size()); - trx.sign( test.get_private_key( config::system_account_name, "active" ), test.control->get_chain_id() ); + auto private_key = test.get_private_key( config::system_account_name, "active" ); + auto public_key = private_key.get_public_key(); + trx.sign( private_key, test.control->get_chain_id() ); BOOST_CHECK_EQUAL(1, trx.signatures.size()); trx.validate(); @@ -603,9 +606,145 @@ BOOST_AUTO_TEST_CASE(transaction_test) { try { bytes raw = pkt.get_raw_transaction(); bytes raw2 = pkt2.get_raw_transaction(); BOOST_CHECK_EQUAL(raw.size(), raw2.size()); + BOOST_CHECK_EQUAL(true, std::equal(raw.begin(), raw.end(), raw2.begin())); + + BOOST_CHECK_EQUAL(pkt.get_signed_transaction().id(), pkt2.get_signed_transaction().id()); + BOOST_CHECK_EQUAL(pkt.get_signed_transaction().id(), pkt2.id()); + + flat_set keys; + auto cpu_time1 = pkt.get_signed_transaction().get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); + BOOST_CHECK_EQUAL(1, keys.size()); + BOOST_CHECK_EQUAL(public_key, *keys.begin()); + keys.clear(); + auto cpu_time2 = pkt.get_signed_transaction().get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); + BOOST_CHECK_EQUAL(1, keys.size()); + BOOST_CHECK_EQUAL(public_key, *keys.begin()); + + BOOST_CHECK(cpu_time1 > fc::microseconds(0)); + BOOST_CHECK(cpu_time2 > fc::microseconds(0)); + + // verify that hitting cache still indicates same billable time + // if we remove cache so that the second is a real time calculation then remove this check + BOOST_CHECK(cpu_time1 == cpu_time2); + + // pack + uint32_t pack_size = fc::raw::pack_size( pkt ); + vector buf(pack_size); + fc::datastream ds(buf.data(), pack_size); + fc::raw::pack( ds, pkt ); + // unpack + ds.seekp(0); + packed_transaction pkt3; + fc::raw::unpack(ds, pkt3); + // pack again + pack_size = fc::raw::pack_size( pkt3 ); + fc::datastream ds2(buf.data(), pack_size); + fc::raw::pack( ds2, pkt3 ); + // unpack + ds2.seekp(0); + packed_transaction pkt4; + fc::raw::unpack(ds2, pkt4); + + bytes raw3 = pkt3.get_raw_transaction(); + bytes raw4 = pkt4.get_raw_transaction(); + BOOST_CHECK_EQUAL(raw.size(), raw3.size()); + BOOST_CHECK_EQUAL(raw3.size(), raw4.size()); + BOOST_CHECK_EQUAL(true, std::equal(raw.begin(), raw.end(), raw3.begin())); + BOOST_CHECK_EQUAL(true, std::equal(raw.begin(), raw.end(), raw4.begin())); + BOOST_CHECK_EQUAL(pkt.get_signed_transaction().id(), pkt3.get_signed_transaction().id()); + BOOST_CHECK_EQUAL(pkt.get_signed_transaction().id(), pkt4.get_signed_transaction().id()); + BOOST_CHECK_EQUAL(pkt.id(), pkt4.get_signed_transaction().id()); + BOOST_CHECK_EQUAL(true, trx.expiration == pkt4.expiration()); + BOOST_CHECK_EQUAL(true, trx.expiration == pkt4.get_signed_transaction().expiration); + keys.clear(); + auto cpu_time3 = pkt4.get_signed_transaction().get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); + BOOST_CHECK_EQUAL(1, keys.size()); + BOOST_CHECK_EQUAL(public_key, *keys.begin()); } FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_CASE(transaction_metadata_test) { try { + + testing::TESTER test; + signed_transaction trx; + + variant pretty_trx = fc::mutable_variant_object() + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", "eosio") + ("name", "reqauth") + ("authorization", fc::variants({ + fc::mutable_variant_object() + ("actor", "eosio") + ("permission", "active") + })) + ("data", fc::mutable_variant_object() + ("from", "eosio") + ) + }) + ) + ("context_free_actions", fc::variants({ + fc::mutable_variant_object() + ("account", "eosio") + ("name", "nonce") + ("data", fc::raw::pack(std::string("dummy data"))) + }) + ); + + abi_serializer::from_variant(pretty_trx, trx, test.get_resolver(), test.abi_serializer_max_time); + + test.set_transaction_headers(trx); + trx.expiration = fc::time_point::now(); + + auto private_key = test.get_private_key( config::system_account_name, "active" ); + auto public_key = private_key.get_public_key(); + trx.sign( private_key, test.control->get_chain_id() ); + BOOST_CHECK_EQUAL(1, trx.signatures.size()); + + packed_transaction pkt(trx, packed_transaction::none); + packed_transaction pkt2(trx, packed_transaction::zlib); + + transaction_metadata_ptr mtrx = std::make_shared( std::make_shared( trx, packed_transaction::none) ); + transaction_metadata_ptr mtrx2 = std::make_shared( std::make_shared( trx, packed_transaction::zlib) ); + + BOOST_CHECK_EQUAL(trx.id(), pkt.id()); + BOOST_CHECK_EQUAL(trx.id(), pkt2.id()); + BOOST_CHECK_EQUAL(trx.id(), mtrx->id); + BOOST_CHECK_EQUAL(trx.id(), mtrx2->id); + + boost::asio::thread_pool thread_pool(5); + + BOOST_CHECK( !mtrx->signing_keys_future.valid() ); + BOOST_CHECK( !mtrx2->signing_keys_future.valid() ); + + transaction_metadata::create_signing_keys_future( mtrx, thread_pool, test.control->get_chain_id(), fc::microseconds::maximum() ); + transaction_metadata::create_signing_keys_future( mtrx2, thread_pool, test.control->get_chain_id(), fc::microseconds::maximum() ); + + BOOST_CHECK( mtrx->signing_keys_future.valid() ); + BOOST_CHECK( mtrx2->signing_keys_future.valid() ); + + // no-op + transaction_metadata::create_signing_keys_future( mtrx, thread_pool, test.control->get_chain_id(), fc::microseconds::maximum() ); + transaction_metadata::create_signing_keys_future( mtrx2, thread_pool, test.control->get_chain_id(), fc::microseconds::maximum() ); + + auto keys = mtrx->recover_keys( test.control->get_chain_id() ); + BOOST_CHECK_EQUAL(1, keys.size()); + BOOST_CHECK_EQUAL(public_key, *keys.begin()); + + // again + keys = mtrx->recover_keys( test.control->get_chain_id() ); + BOOST_CHECK_EQUAL(1, keys.size()); + BOOST_CHECK_EQUAL(public_key, *keys.begin()); + + auto keys2 = mtrx2->recover_keys( test.control->get_chain_id() ); + BOOST_CHECK_EQUAL(1, keys.size()); + BOOST_CHECK_EQUAL(public_key, *keys.begin()); + + +} FC_LOG_AND_RETHROW() } + + BOOST_AUTO_TEST_SUITE_END() } // namespace eosio diff --git a/unittests/multi_index_tests.cpp b/unittests/multi_index_tests.cpp index 37fd9c70a66..821e187ffd1 100644 --- a/unittests/multi_index_tests.cpp +++ b/unittests/multi_index_tests.cpp @@ -1,13 +1,16 @@ -#include +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #include - -#include -#include - #include -#include #include +#include + +#include + +#include #ifdef NON_VALIDATING_TEST #define TESTER tester @@ -25,39 +28,42 @@ BOOST_FIXTURE_TEST_CASE( multi_index_load, TESTER ) try { create_accounts( {N(multitest)} ); produce_blocks(2); - set_code( N(multitest), multi_index_test_wast ); - set_abi( N(multitest), multi_index_test_abi ); + set_code( N(multitest), contracts::multi_index_test_wasm() ); + set_abi( N(multitest), contracts::multi_index_test_abi().data() ); produce_blocks(1); - abi_serializer abi_ser(json::from_string(multi_index_test_abi).as(), abi_serializer_max_time); + auto abi_string = std::string(contracts::multi_index_test_abi().data()); + + abi_serializer abi_ser(json::from_string(abi_string).as(), abi_serializer_max_time); signed_transaction trx1; { auto& trx = trx1; action trigger_act; trigger_act.account = N(multitest); - trigger_act.name = N(trigger); + trigger_act.name = N(multitest); trigger_act.authorization = vector{{N(multitest), config::active_name}}; - trigger_act.data = abi_ser.variant_to_binary("trigger", mutable_variant_object() + trigger_act.data = abi_ser.variant_to_binary("multitest", mutable_variant_object() ("what", 0), abi_serializer_max_time ); + trx.actions.emplace_back(std::move(trigger_act)); set_transaction_headers(trx); trx.sign(get_private_key(N(multitest), "active"), control->get_chain_id()); push_transaction(trx); } - + signed_transaction trx2; { auto& trx = trx2; action trigger_act; trigger_act.account = N(multitest); - trigger_act.name = N(trigger); + trigger_act.name = N(multitest); trigger_act.authorization = vector{{N(multitest), config::active_name}}; - trigger_act.data = abi_ser.variant_to_binary("trigger", mutable_variant_object() + trigger_act.data = abi_ser.variant_to_binary("multitest", mutable_variant_object() ("what", 1), abi_serializer_max_time ); diff --git a/unittests/multisig_tests.cpp b/unittests/multisig_tests.cpp new file mode 100644 index 00000000000..246f6aae745 --- /dev/null +++ b/unittests/multisig_tests.cpp @@ -0,0 +1,632 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include +#include +#include +#include + +#include + +#include + +#include + +using namespace eosio::testing; +using namespace eosio; +using namespace eosio::chain; +using namespace eosio::testing; +using namespace fc; + +using mvo = fc::mutable_variant_object; + +class eosio_msig_tester : public tester { +public: + + eosio_msig_tester() { + create_accounts( { N(eosio.msig), N(eosio.stake), N(eosio.ram), N(eosio.ramfee), N(alice), N(bob), N(carol) } ); + produce_block(); + + auto trace = base_tester::push_action(config::system_account_name, N(setpriv), + config::system_account_name, mutable_variant_object() + ("account", "eosio.msig") + ("is_priv", 1) + ); + + set_code( N(eosio.msig), contracts::eosio_msig_wasm() ); + set_abi( N(eosio.msig), contracts::eosio_msig_abi().data() ); + + produce_blocks(); + const auto& accnt = control->db().get( N(eosio.msig) ); + abi_def abi; + BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); + abi_ser.set_abi(abi, abi_serializer_max_time); + } + + transaction_trace_ptr create_account_with_resources( account_name a, account_name creator, asset ramfunds, bool multisig, + asset net = core_from_string("10.0000"), asset cpu = core_from_string("10.0000") ) { + signed_transaction trx; + set_transaction_headers(trx); + + authority owner_auth; + if (multisig) { + // multisig between account's owner key and creators active permission + owner_auth = authority(2, {key_weight{get_public_key( a, "owner" ), 1}}, {permission_level_weight{{creator, config::active_name}, 1}}); + } else { + owner_auth = authority( get_public_key( a, "owner" ) ); + } + + trx.actions.emplace_back( vector{{creator,config::active_name}}, + newaccount{ + .creator = creator, + .name = a, + .owner = owner_auth, + .active = authority( get_public_key( a, "active" ) ) + }); + + trx.actions.emplace_back( get_action( config::system_account_name, N(buyram), vector{{creator,config::active_name}}, + mvo() + ("payer", creator) + ("receiver", a) + ("quant", ramfunds) ) + ); + + trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{{creator,config::active_name}}, + mvo() + ("from", creator) + ("receiver", a) + ("stake_net_quantity", net ) + ("stake_cpu_quantity", cpu ) + ("transfer", 0 ) + ) + ); + + set_transaction_headers(trx); + trx.sign( get_private_key( creator, "active" ), control->get_chain_id() ); + return push_transaction( trx ); + } + void create_currency( name contract, name manager, asset maxsupply ) { + auto act = mutable_variant_object() + ("issuer", manager ) + ("maximum_supply", maxsupply ); + + base_tester::push_action(contract, N(create), contract, act ); + } + void issue( name to, const asset& amount, name manager = config::system_account_name ) { + base_tester::push_action( N(eosio.token), N(issue), manager, mutable_variant_object() + ("to", to ) + ("quantity", amount ) + ("memo", "") + ); + } + void transfer( name from, name to, const string& amount, name manager = config::system_account_name ) { + base_tester::push_action( N(eosio.token), N(transfer), manager, mutable_variant_object() + ("from", from) + ("to", to ) + ("quantity", asset::from_string(amount) ) + ("memo", "") + ); + } + asset get_balance( const account_name& act ) { + //return get_currency_balance( config::system_account_name, symbol(CORE_SYMBOL), act ); + //temporary code. current get_currency_balancy uses table name N(accounts) from currency.h + //generic_currency table name is N(account). + const auto& db = control->db(); + const auto* tbl = db.find(boost::make_tuple(N(eosio.token), act, N(accounts))); + share_type result = 0; + + // the balance is implied to be 0 if either the table or row does not exist + if (tbl) { + const auto *obj = db.find(boost::make_tuple(tbl->id, symbol(CORE_SYMBOL).to_symbol_code())); + if (obj) { + // balance is the first field in the serialization + fc::datastream ds(obj->value.data(), obj->value.size()); + fc::raw::unpack(ds, result); + } + } + return asset( result, symbol(CORE_SYMBOL) ); + } + + transaction_trace_ptr push_action( const account_name& signer, const action_name& name, const variant_object& data, bool auth = true ) { + vector accounts; + if( auth ) + accounts.push_back( signer ); + auto trace = base_tester::push_action( N(eosio.msig), name, accounts, data ); + produce_block(); + BOOST_REQUIRE_EQUAL( true, chain_has_transaction(trace->id) ); + return trace; + } + + transaction reqauth( account_name from, const vector& auths, const fc::microseconds& max_serialization_time ); + + abi_serializer abi_ser; +}; + +transaction eosio_msig_tester::reqauth( account_name from, const vector& auths, const fc::microseconds& max_serialization_time ) { + fc::variants v; + for ( auto& level : auths ) { + v.push_back(fc::mutable_variant_object() + ("actor", level.actor) + ("permission", level.permission) + ); + } + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("max_net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "reqauth") + ("authorization", v) + ("data", fc::mutable_variant_object() ("from", from) ) + }) + ); + transaction trx; + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), max_serialization_time); + return trx; +} + +BOOST_AUTO_TEST_SUITE(eosio_msig_tests) + +BOOST_FIXTURE_TEST_CASE( propose_approve_execute, eosio_msig_tester ) try { + auto trx = reqauth("alice", {permission_level{N(alice), config::active_name}}, abi_serializer_max_time ); + + push_action( N(alice), N(propose), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("trx", trx) + ("requested", vector{{ N(alice), config::active_name }}) + ); + + //fail to execute before approval + BOOST_REQUIRE_EXCEPTION( push_action( N(alice), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") + ), + eosio_assert_message_exception, + eosio_assert_message_is("transaction authorization failed") + ); + + //approve and execute + push_action( N(alice), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(alice), config::active_name }) + ); + + transaction_trace_ptr trace; + control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } ); + push_action( N(alice), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") + ); + + BOOST_REQUIRE( bool(trace) ); + BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); +} FC_LOG_AND_RETHROW() + + +BOOST_FIXTURE_TEST_CASE( propose_approve_unapprove, eosio_msig_tester ) try { + auto trx = reqauth("alice", {permission_level{N(alice), config::active_name}}, abi_serializer_max_time ); + + push_action( N(alice), N(propose), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("trx", trx) + ("requested", vector{{ N(alice), config::active_name }}) + ); + + push_action( N(alice), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(alice), config::active_name }) + ); + + push_action( N(alice), N(unapprove), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(alice), config::active_name }) + ); + + BOOST_REQUIRE_EXCEPTION( push_action( N(alice), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") + ), + eosio_assert_message_exception, + eosio_assert_message_is("transaction authorization failed") + ); + +} FC_LOG_AND_RETHROW() + + +BOOST_FIXTURE_TEST_CASE( propose_approve_by_two, eosio_msig_tester ) try { + auto trx = reqauth("alice", vector{ { N(alice), config::active_name }, { N(bob), config::active_name } }, abi_serializer_max_time ); + push_action( N(alice), N(propose), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("trx", trx) + ("requested", vector{ { N(alice), config::active_name }, { N(bob), config::active_name } }) + ); + + //approve by alice + push_action( N(alice), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(alice), config::active_name }) + ); + + //fail because approval by bob is missing + BOOST_REQUIRE_EXCEPTION( push_action( N(alice), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") + ), + eosio_assert_message_exception, + eosio_assert_message_is("transaction authorization failed") + ); + + //approve by bob and execute + push_action( N(bob), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(bob), config::active_name }) + ); + + transaction_trace_ptr trace; + control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } ); + + push_action( N(alice), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") + ); + + BOOST_REQUIRE( bool(trace) ); + BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); +} FC_LOG_AND_RETHROW() + + +BOOST_FIXTURE_TEST_CASE( propose_with_wrong_requested_auth, eosio_msig_tester ) try { + auto trx = reqauth("alice", vector{ { N(alice), config::active_name }, { N(bob), config::active_name } }, abi_serializer_max_time ); + //try with not enough requested auth + BOOST_REQUIRE_EXCEPTION( push_action( N(alice), N(propose), mvo() + ("proposer", "alice") + ("proposal_name", "third") + ("trx", trx) + ("requested", vector{ { N(alice), config::active_name } } ) + ), + eosio_assert_message_exception, + eosio_assert_message_is("transaction authorization failed") + ); + +} FC_LOG_AND_RETHROW() + + +BOOST_FIXTURE_TEST_CASE( big_transaction, eosio_msig_tester ) try { + vector perm = { { N(alice), config::active_name }, { N(bob), config::active_name } }; + // auto wasm = wast_to_wasm( contracts::eosio_token_wasm() ); + auto wasm = contracts::eosio_token_wasm(); + + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("max_net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "setcode") + ("authorization", perm) + ("data", fc::mutable_variant_object() + ("account", "alice") + ("vmtype", 0) + ("vmversion", 0) + ("code", bytes( wasm.begin(), wasm.end() )) + ) + }) + ); + + transaction trx; + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + + push_action( N(alice), N(propose), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("trx", trx) + ("requested", perm) + ); + + //approve by alice + push_action( N(alice), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(alice), config::active_name }) + ); + //approve by bob and execute + push_action( N(bob), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(bob), config::active_name }) + ); + + transaction_trace_ptr trace; + control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } ); + + push_action( N(alice), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") + ); + + BOOST_REQUIRE( bool(trace) ); + BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); +} FC_LOG_AND_RETHROW() + + + +BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) try { + + // required to set up the link between (eosio active) and (eosio.prods active) + // + // eosio active + // | + // eosio.prods active (2/3 threshold) + // / | \ <--- implicitly updated in onblock action + // alice active bob active carol active + + set_authority(config::system_account_name, "active", authority(1, + vector{{get_private_key("eosio", "active").get_public_key(), 1}}, + vector{{{config::producers_account_name, config::active_name}, 1}}), "owner", + { { config::system_account_name, "active" } }, { get_private_key( config::system_account_name, "active" ) }); + + set_producers( {N(alice),N(bob),N(carol)} ); + produce_blocks(50); + + create_accounts( { N(eosio.token) } ); + set_code( N(eosio.token), contracts::eosio_token_wasm() ); + set_abi( N(eosio.token), contracts::eosio_token_abi().data() ); + + create_currency( N(eosio.token), config::system_account_name, core_from_string("10000000000.0000") ); + issue(config::system_account_name, core_from_string("1000000000.0000")); + BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), + get_balance("eosio") + get_balance("eosio.ramfee") + get_balance("eosio.stake") + get_balance("eosio.ram") ); + + set_code( config::system_account_name, contracts::eosio_system_wasm() ); + set_abi( config::system_account_name, contracts::eosio_system_abi().data() ); + + produce_blocks(); + + base_tester::push_action(config::system_account_name, N(init), + config::system_account_name, mutable_variant_object() + ("version", 0) + ("core", CORE_SYM_STR)); + + create_account_with_resources( N(alice1111111), config::system_account_name, core_from_string("1.0000"), false ); + create_account_with_resources( N(bob111111111), config::system_account_name, core_from_string("0.4500"), false ); + create_account_with_resources( N(carol1111111), config::system_account_name, core_from_string("1.0000"), false ); + + BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), + get_balance("eosio") + get_balance("eosio.ramfee") + get_balance("eosio.stake") + get_balance("eosio.ram") ); + + vector perm = { { N(alice), config::active_name }, { N(bob), config::active_name }, + {N(carol), config::active_name} }; + + vector action_perm = {{config::system_account_name, config::active_name}}; + + auto wasm = contracts::test_api_wasm(); + + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("max_net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "setcode") + ("authorization", action_perm) + ("data", fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("vmtype", 0) + ("vmversion", 0) + ("code", bytes( wasm.begin(), wasm.end() )) + ) + }) + ); + + transaction trx; + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + + // propose action + push_action( N(alice), N(propose), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("trx", trx) + ("requested", perm) + ); + + //approve by alice + push_action( N(alice), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(alice), config::active_name }) + ); + //approve by bob + push_action( N(bob), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(bob), config::active_name }) + ); + //approve by carol + push_action( N(carol), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(carol), config::active_name }) + ); + // execute by alice to replace the eosio system contract + transaction_trace_ptr trace; + control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } ); + + push_action( N(alice), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") + ); + + BOOST_REQUIRE( bool(trace) ); + BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + + // can't create account because system contract was replace by the test_api contract + + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(alice1111112), config::system_account_name, core_from_string("1.0000"), false ), + eosio_assert_message_exception, eosio_assert_message_is("Unknown Test") + + ); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester ) try { + + // set up the link between (eosio active) and (eosio.prods active) + set_authority(config::system_account_name, "active", authority(1, + vector{{get_private_key("eosio", "active").get_public_key(), 1}}, + vector{{{config::producers_account_name, config::active_name}, 1}}), "owner", + { { config::system_account_name, "active" } }, { get_private_key( config::system_account_name, "active" ) }); + + create_accounts( { N(apple) } ); + set_producers( {N(alice),N(bob),N(carol), N(apple)} ); + produce_blocks(50); + + create_accounts( { N(eosio.token) } ); + set_code( N(eosio.token), contracts::eosio_token_wasm() ); + set_abi( N(eosio.token), contracts::eosio_token_abi().data() ); + + create_currency( N(eosio.token), config::system_account_name, core_from_string("10000000000.0000") ); + issue(config::system_account_name, core_from_string("1000000000.0000")); + BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), get_balance( "eosio" ) ); + + set_code( config::system_account_name, contracts::eosio_system_wasm() ); + set_abi( config::system_account_name, contracts::eosio_system_abi().data() ); + + produce_blocks(); + + base_tester::push_action(config::system_account_name, N(init), + config::system_account_name, mutable_variant_object() + ("version", 0) + ("core", CORE_SYM_STR)); + + create_account_with_resources( N(alice1111111), config::system_account_name, core_from_string("1.0000"), false ); + create_account_with_resources( N(bob111111111), config::system_account_name, core_from_string("0.4500"), false ); + create_account_with_resources( N(carol1111111), config::system_account_name, core_from_string("1.0000"), false ); + + BOOST_REQUIRE_EQUAL( core_from_string("1000000000.0000"), + get_balance("eosio") + get_balance("eosio.ramfee") + get_balance("eosio.stake") + get_balance("eosio.ram") ); + + vector perm = { { N(alice), config::active_name }, { N(bob), config::active_name }, + {N(carol), config::active_name}, {N(apple), config::active_name}}; + + vector action_perm = {{config::system_account_name, config::active_name}}; + + auto wasm = contracts::test_api_wasm(); + + variant pretty_trx = fc::mutable_variant_object() + ("expiration", "2020-01-01T00:30") + ("ref_block_num", 2) + ("ref_block_prefix", 3) + ("max_net_usage_words", 0) + ("max_cpu_usage_ms", 0) + ("delay_sec", 0) + ("actions", fc::variants({ + fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("name", "setcode") + ("authorization", action_perm) + ("data", fc::mutable_variant_object() + ("account", name(config::system_account_name)) + ("vmtype", 0) + ("vmversion", 0) + ("code", bytes( wasm.begin(), wasm.end() )) + ) + }) + ); + + transaction trx; + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + + // propose action + push_action( N(alice), N(propose), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("trx", trx) + ("requested", perm) + ); + + //approve by alice + push_action( N(alice), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(alice), config::active_name }) + ); + //approve by bob + push_action( N(bob), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(bob), config::active_name }) + ); + + // not enough approvers + BOOST_REQUIRE_EXCEPTION( + push_action( N(alice), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") + ), + eosio_assert_message_exception, eosio_assert_message_is("transaction authorization failed") + ); + + //approve by apple + push_action( N(apple), N(approve), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("level", permission_level{ N(apple), config::active_name }) + ); + // execute by alice to replace the eosio system contract + transaction_trace_ptr trace; + control->applied_transaction.connect([&]( const transaction_trace_ptr& t) { if (t->scheduled) { trace = t; } } ); + + // execute by another producer different from proposer + push_action( N(apple), N(exec), mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "apple") + ); + + BOOST_REQUIRE( bool(trace) ); + BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + + // can't create account because system contract was replace by the test_api contract + + BOOST_REQUIRE_EXCEPTION( create_account_with_resources( N(alice1111112), config::system_account_name, core_from_string("1.0000"), false ), + eosio_assert_message_exception, eosio_assert_message_is("Unknown Test") + + ); +} FC_LOG_AND_RETHROW() + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/payloadless_tests.cpp b/unittests/payloadless_tests.cpp index 138ae887ecd..c9519e0ed71 100644 --- a/unittests/payloadless_tests.cpp +++ b/unittests/payloadless_tests.cpp @@ -1,19 +1,24 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" #include #pragma GCC diagnostic pop -#include + #include #include -#include -#include - #include #include #include +#include + +#include + #ifdef NON_VALIDATING_TEST #define TESTER tester #else @@ -34,8 +39,8 @@ BOOST_AUTO_TEST_SUITE(payloadless_tests) BOOST_FIXTURE_TEST_CASE( test_doit, payloadless_tester ) { create_accounts( {N(payloadless)} ); - set_code( N(payloadless), payloadless_wast ); - set_abi( N(payloadless), payloadless_abi ); + set_code( N(payloadless), contracts::payloadless_wasm() ); + set_abi( N(payloadless), contracts::payloadless_abi().data() ); auto trace = push_action(N(payloadless), N(doit), N(payloadless), mutable_variant_object()); auto msg = trace->action_traces.front().console; @@ -47,8 +52,8 @@ BOOST_FIXTURE_TEST_CASE( test_doit, payloadless_tester ) { BOOST_FIXTURE_TEST_CASE( test_abi_serializer, payloadless_tester ) { create_accounts( {N(payloadless)} ); - set_code( N(payloadless), payloadless_wast ); - set_abi( N(payloadless), payloadless_abi ); + set_code( N(payloadless), contracts::payloadless_wasm() ); + set_abi( N(payloadless), contracts::payloadless_abi().data() ); variant pretty_trx = fc::mutable_variant_object() ("actions", fc::variants({ diff --git a/unittests/producer_schedule_tests.cpp b/unittests/producer_schedule_tests.cpp index 07435f97d96..877645cbcde 100644 --- a/unittests/producer_schedule_tests.cpp +++ b/unittests/producer_schedule_tests.cpp @@ -1,7 +1,12 @@ -#include -#include +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #include +#include + #include +#include #ifdef NON_VALIDATING_TEST #define TESTER tester diff --git a/unittests/ram_tests.cpp b/unittests/ram_tests.cpp index 6fe0eec6613..e73eb979339 100644 --- a/unittests/ram_tests.cpp +++ b/unittests/ram_tests.cpp @@ -7,30 +7,27 @@ #include #pragma GCC diagnostic pop -#include #include #include +#include #include #include -#include "eosio_system_tester.hpp" +#include -#include -#include +#include "eosio_system_tester.hpp" /* * register test suite `ram_tests` */ BOOST_AUTO_TEST_SUITE(ram_tests) - - /************************************************************************************* * ram_tests test case *************************************************************************************/ BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try { - auto init_request_bytes = 80000; + auto init_request_bytes = 80000 + 7110; // `7110' is for table token row const auto increment_contract_bytes = 10000; const auto table_allocation_bytes = 12000; BOOST_REQUIRE_MESSAGE(table_allocation_bytes > increment_contract_bytes, "increment_contract_bytes must be less than table_allocation_bytes for this test setup to work"); @@ -44,7 +41,7 @@ BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try { for (auto i = 0; i < 10; ++i) { try { - set_code( N(testram11111), test_ram_limit_wast ); + set_code( N(testram11111), contracts::test_ram_limit_wasm() ); break; } catch (const ram_usage_exceeded&) { init_request_bytes += increment_contract_bytes; @@ -56,7 +53,7 @@ BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try { for (auto i = 0; i < 10; ++i) { try { - set_abi( N(testram11111), test_ram_limit_abi ); + set_abi( N(testram11111), contracts::test_ram_limit_abi().data() ); break; } catch (const ram_usage_exceeded&) { init_request_bytes += increment_contract_bytes; @@ -65,8 +62,8 @@ BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try { } } produce_blocks(10); - set_code( N(testram22222), test_ram_limit_wast ); - set_abi( N(testram22222), test_ram_limit_abi ); + set_code( N(testram22222), contracts::test_ram_limit_wasm() ); + set_abi( N(testram22222), contracts::test_ram_limit_abi().data() ); produce_blocks(10); auto total = get_total_stake( N(testram11111) ); @@ -213,7 +210,7 @@ BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try { ("to", 13) ("size", 1720)); produce_blocks(1); - + // verify that new entries for testram22222 exceed the allocation bytes limit BOOST_REQUIRE_EXCEPTION( tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo() diff --git a/unittests/resource_limits_test.cpp b/unittests/resource_limits_test.cpp index 76c0d541699..69e62915bfb 100644 --- a/unittests/resource_limits_test.cpp +++ b/unittests/resource_limits_test.cpp @@ -1,16 +1,19 @@ -#include -#include +/** + * @file api_tests.cpp + * @copyright defined in eos/LICENSE.txt + */ +#include + #include +#include #include -#include +#include using namespace eosio::chain::resource_limits; using namespace eosio::testing; using namespace eosio::chain; - - class resource_limits_fixture: private chainbase_fixture<512*1024>, public resource_limits_manager { public: diff --git a/unittests/snapshot_tests.cpp b/unittests/snapshot_tests.cpp index 1534a49b5dc..c3578e15750 100644 --- a/unittests/snapshot_tests.cpp +++ b/unittests/snapshot_tests.cpp @@ -2,17 +2,15 @@ * @file * @copyright defined in eos/LICENSE */ - -#include -#include -#include +#include #include +#include -#include -#include +#include +#include -#include +#include using namespace eosio; using namespace testing; @@ -159,8 +157,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_exhaustive_snapshot, SNAPSHOT_SUITE, snapshot chain.create_account(N(snapshot)); chain.produce_blocks(1); - chain.set_code(N(snapshot), snapshot_test_wast); - chain.set_abi(N(snapshot), snapshot_test_abi); + chain.set_code(N(snapshot), contracts::snapshot_test_wasm()); + chain.set_abi(N(snapshot), contracts::snapshot_test_abi().data()); chain.produce_blocks(1); chain.control->abort_block(); @@ -203,8 +201,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_replay_over_snapshot, SNAPSHOT_SUITE, snapsho chain.create_account(N(snapshot)); chain.produce_blocks(1); - chain.set_code(N(snapshot), snapshot_test_wast); - chain.set_abi(N(snapshot), snapshot_test_abi); + chain.set_code(N(snapshot), contracts::snapshot_test_wasm()); + chain.set_abi(N(snapshot), contracts::snapshot_test_abi().data()); chain.produce_blocks(1); chain.control->abort_block(); diff --git a/unittests/special_accounts_tests.cpp b/unittests/special_accounts_tests.cpp index e3ad16fa9bc..58e9444b58a 100644 --- a/unittests/special_accounts_tests.cpp +++ b/unittests/special_accounts_tests.cpp @@ -3,23 +3,21 @@ * @copyright defined in eos/LICENSE */ #include -#include #include -#include +#include #include #include #include #include - #include #include -#include #include #include #include +#include using namespace eosio; using namespace chain; diff --git a/unittests/test-contracts/CMakeLists.txt b/unittests/test-contracts/CMakeLists.txt new file mode 100644 index 00000000000..70a3fc83e66 --- /dev/null +++ b/unittests/test-contracts/CMakeLists.txt @@ -0,0 +1,17 @@ +set(EOSIO_WASM_OLD_BEHAVIOR "Off") +find_package( eosio.cdt ) + +add_subdirectory( asserter ) +add_subdirectory( deferred_test ) +add_subdirectory( integration_test ) +add_subdirectory( multi_index_test ) +add_subdirectory( noop ) +add_subdirectory( payloadless ) +add_subdirectory( proxy ) +add_subdirectory( snapshot_test ) +add_subdirectory( test.inline ) +add_subdirectory( test_api ) +add_subdirectory( test_api_mem ) +add_subdirectory( test_api_db ) +add_subdirectory( test_api_multi_index ) +add_subdirectory( test_ram_limit ) diff --git a/unittests/test-contracts/Readme.txt b/unittests/test-contracts/Readme.txt new file mode 100644 index 00000000000..7453ed0c6a9 --- /dev/null +++ b/unittests/test-contracts/Readme.txt @@ -0,0 +1,3 @@ +test_ram_limit contract was compiled with eosio.cdt v1.4.1 + +This contract is already ported to compile with eosio.cdt v1.5.0, but the test that uses it is very sensitive to stdlib/eosiolib changes, compilation flags and linker flags. diff --git a/unittests/test-contracts/asserter/CMakeLists.txt b/unittests/test-contracts/asserter/CMakeLists.txt new file mode 100644 index 00000000000..f8bf4b8643b --- /dev/null +++ b/unittests/test-contracts/asserter/CMakeLists.txt @@ -0,0 +1,8 @@ +if( ${eosio.cdt_FOUND} ) + add_executable( asserter asserter asserter.cpp ) + target_include_directories(asserter PUBLIC ${CMAKE_CURRENT_SOURCE}/../) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/asserter.wasm ${CMAKE_CURRENT_BINARY_DIR}/asserter.wasm COPYONLY ) +endif() + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/asserter.abi ${CMAKE_CURRENT_BINARY_DIR}/asserter.abi COPYONLY ) diff --git a/contracts/asserter/asserter.abi b/unittests/test-contracts/asserter/asserter.abi similarity index 100% rename from contracts/asserter/asserter.abi rename to unittests/test-contracts/asserter/asserter.abi diff --git a/unittests/test-contracts/asserter/asserter.cpp b/unittests/test-contracts/asserter/asserter.cpp new file mode 100644 index 00000000000..5c5e95a51e0 --- /dev/null +++ b/unittests/test-contracts/asserter/asserter.cpp @@ -0,0 +1,28 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include "asserter.hpp" /// defines assert_def struct (abi) + +using namespace eosio; +using namespace asserter; + +static int global_variable = 45; + +extern "C" { + /// The apply method implements the dispatch of events to this contract + void apply( uint64_t /* receiver */, uint64_t code, uint64_t action ) { + require_auth(code); + if( code == "asserter"_n.value ) { + if( action == "procassert"_n.value ) { + assertdef def = eosio::unpack_action_data(); + + // maybe assert? + eosio_assert( (uint32_t)def.condition, def.message.c_str() ); + } else if( action == "provereset"_n.value ) { + eosio_assert( global_variable == 45, "Global Variable Initialized poorly" ); + global_variable = 100; + } + } + } +} diff --git a/contracts/asserter/asserter.hpp b/unittests/test-contracts/asserter/asserter.hpp similarity index 86% rename from contracts/asserter/asserter.hpp rename to unittests/test-contracts/asserter/asserter.hpp index 01d4b343e3f..123e29a862f 100644 --- a/contracts/asserter/asserter.hpp +++ b/unittests/test-contracts/asserter/asserter.hpp @@ -2,14 +2,13 @@ * @file * @copyright defined in eos/LICENSE */ - #include namespace asserter { - struct assertdef { + TABLE assertdef { int8_t condition; std::string message; EOSLIB_SERIALIZE( assertdef, (condition)(message) ) }; -} +} /// asserter diff --git a/unittests/test-contracts/asserter/asserter.wasm b/unittests/test-contracts/asserter/asserter.wasm new file mode 100755 index 00000000000..c639a6db70c Binary files /dev/null and b/unittests/test-contracts/asserter/asserter.wasm differ diff --git a/unittests/test-contracts/deferred_test/CMakeLists.txt b/unittests/test-contracts/deferred_test/CMakeLists.txt new file mode 100644 index 00000000000..053cbb8683b --- /dev/null +++ b/unittests/test-contracts/deferred_test/CMakeLists.txt @@ -0,0 +1,6 @@ +if( ${eosio.cdt_FOUND} ) + add_contract( deferred_test deferred_test deferred_test.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/deferred_test.wasm ${CMAKE_CURRENT_BINARY_DIR}/deferred_test.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/deferred_test.abi ${CMAKE_CURRENT_BINARY_DIR}/deferred_test.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/deferred_test/deferred_test.abi b/unittests/test-contracts/deferred_test/deferred_test.abi new file mode 100644 index 00000000000..27c6c50cd0c --- /dev/null +++ b/unittests/test-contracts/deferred_test/deferred_test.abi @@ -0,0 +1,78 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Dec 7 11:56:43 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "defercall", + "base": "", + "fields": [ + { + "name": "payer", + "type": "name" + }, + { + "name": "sender_id", + "type": "uint64" + }, + { + "name": "contract", + "type": "name" + }, + { + "name": "payload", + "type": "uint64" + } + ] + }, + { + "name": "deferfunc", + "base": "", + "fields": [ + { + "name": "payload", + "type": "uint64" + } + ] + }, + { + "name": "inlinecall", + "base": "", + "fields": [ + { + "name": "contract", + "type": "name" + }, + { + "name": "authorizer", + "type": "name" + }, + { + "name": "payload", + "type": "uint64" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "defercall", + "type": "defercall", + "ricardian_contract": "" + }, + { + "name": "deferfunc", + "type": "deferfunc", + "ricardian_contract": "" + }, + { + "name": "inlinecall", + "type": "inlinecall", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/contracts/deferred_test/deferred_test.cpp b/unittests/test-contracts/deferred_test/deferred_test.cpp similarity index 51% rename from unittests/contracts/deferred_test/deferred_test.cpp rename to unittests/test-contracts/deferred_test/deferred_test.cpp index a30a7a2550e..3d7392e34b6 100644 --- a/unittests/contracts/deferred_test/deferred_test.cpp +++ b/unittests/test-contracts/deferred_test/deferred_test.cpp @@ -2,14 +2,13 @@ * @file * @copyright defined in eos/LICENSE */ - #include -#include #include +#include using namespace eosio; -class deferred_test : public eosio::contract { +CONTRACT deferred_test : public contract { public: using contract::contract; @@ -17,27 +16,24 @@ class deferred_test : public eosio::contract { uint64_t payload; }; - //@abi action - void defercall( account_name payer, uint64_t sender_id, account_name contract, uint64_t payload ) { + ACTION defercall( name payer, uint64_t sender_id, name contract, uint64_t payload ) { print( "defercall called on ", name{_self}, "\n" ); require_auth( payer ); print( "deferred send of deferfunc action to ", name{contract}, " by ", name{payer}, " with sender id ", sender_id ); transaction trx; deferfunc_args a = {.payload = payload}; - trx.actions.emplace_back(permission_level{_self, N(active)}, contract, N(deferfunc), a); - trx.send( (static_cast(payer) << 64) | sender_id, payer); + trx.actions.emplace_back(permission_level{_self, name{"active"}}, contract, name{"deferfunc"}, a); + trx.send( (static_cast(payer.value) << 64) | sender_id, payer); } - //@abi action - void deferfunc( uint64_t payload ) { + ACTION deferfunc( uint64_t payload ) { print("deferfunc called on ", name{_self}, " with payload = ", payload, "\n"); eosio_assert( payload != 13, "value 13 not allowed in payload" ); } - //@abi action - void inlinecall( account_name contract, account_name authorizer, uint64_t payload ) { - action a( {permission_level{authorizer, N(active)}}, contract, N(deferfunc), payload ); + ACTION inlinecall( name contract, name authorizer, uint64_t payload ) { + action a( {permission_level{authorizer, "active"_n}}, contract, "deferfunc"_n, payload ); a.send(); } @@ -51,19 +47,17 @@ void apply_onerror(uint64_t receiver, const onerror& error ) { extern "C" { /// The apply method implements the dispatch of events to this contract void apply( uint64_t receiver, uint64_t code, uint64_t action ) { - if( code == N(eosio) && action == N(onerror) ) { + if( code == name{"eosio"}.value && action == name{"onerror"}.value ) { apply_onerror( receiver, onerror::from_current_action() ); } else if( code == receiver ) { - deferred_test thiscontract(receiver); - if( action == N(defercall) ) { - execute_action( &thiscontract, &deferred_test::defercall ); - } else if( action == N(deferfunc) ) { - execute_action( &thiscontract, &deferred_test::deferfunc ); - } else if( action == N(inlinecall) ) { - execute_action( &thiscontract, &deferred_test::inlinecall ); + deferred_test thiscontract( name{receiver}, name{code}, eosio::datastream{nullptr, 0} ); + if( action == name{"defercall"}.value ) { + execute_action( name{receiver}, name{code}, &deferred_test::defercall ); + } else if( action == name{"deferfunc"}.value ) { + execute_action( name{receiver}, name{code}, &deferred_test::deferfunc ); + } else if(action == name{"inlinecall"}.value) { + execute_action( name{receiver}, name{code}, &deferred_test::inlinecall ); } } } } - -//EOSIO_ABI( deferred_test, (defercall)(deferfunc) ) diff --git a/unittests/test-contracts/deferred_test/deferred_test.wasm b/unittests/test-contracts/deferred_test/deferred_test.wasm new file mode 100755 index 00000000000..50ee1c13b4b Binary files /dev/null and b/unittests/test-contracts/deferred_test/deferred_test.wasm differ diff --git a/unittests/test-contracts/integration_test/CMakeLists.txt b/unittests/test-contracts/integration_test/CMakeLists.txt new file mode 100644 index 00000000000..f1276f9ed78 --- /dev/null +++ b/unittests/test-contracts/integration_test/CMakeLists.txt @@ -0,0 +1,6 @@ +if( ${eosio.cdt_FOUND} ) + add_contract( integration_test integration_test integration_test.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/integration_test.wasm ${CMAKE_CURRENT_BINARY_DIR}/integration_test.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/integration_test.abi ${CMAKE_CURRENT_BINARY_DIR}/integration_test.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/integration_test/integration_test.abi b/unittests/test-contracts/integration_test/integration_test.abi new file mode 100644 index 00000000000..8e9866cab20 --- /dev/null +++ b/unittests/test-contracts/integration_test/integration_test.abi @@ -0,0 +1,58 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Dec 7 11:56:43 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "payload", + "base": "", + "fields": [ + { + "name": "key", + "type": "uint64" + }, + { + "name": "data", + "type": "uint64[]" + } + ] + }, + { + "name": "store", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "to", + "type": "name" + }, + { + "name": "num", + "type": "uint64" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "store", + "type": "store", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "payloads", + "type": "payload", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/test-contracts/integration_test/integration_test.cpp b/unittests/test-contracts/integration_test/integration_test.cpp new file mode 100644 index 00000000000..c6a5c72fd9e --- /dev/null +++ b/unittests/test-contracts/integration_test/integration_test.cpp @@ -0,0 +1,44 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include + +using namespace eosio; + +CONTRACT integration_test : public contract { + using contract::contract; + + TABLE payload { + uint64_t key; + std::vector data; + + uint64_t primary_key()const { return key; } + + EOSLIB_SERIALIZE( payload, (key)(data) ) + }; + typedef eosio::multi_index<"payloads"_n, payload> payloads; + +public: + ACTION store( name from, name to, uint64_t num ) { + require_auth(from); + + eosio_assert( is_account( to ), "to account does not exist" ); + eosio_assert( num < std::numeric_limits::max(), "num to large" ); + + payloads data ( _self, from.value ); + uint64_t key = 0; + const uint64_t num_keys = 5; + + while ( data.find( key ) != data.end() ) { + key += num_keys; + } + for (size_t i = 0; i < num_keys; ++i) { + data.emplace(from, [&]( auto& g ) { + g.key = key + i; + g.data = std::vector( static_cast(num), 5); }); + } + } +}; + +EOSIO_DISPATCH( integration_test, (store) ) diff --git a/unittests/test-contracts/integration_test/integration_test.wasm b/unittests/test-contracts/integration_test/integration_test.wasm new file mode 100755 index 00000000000..39caaaec3d6 Binary files /dev/null and b/unittests/test-contracts/integration_test/integration_test.wasm differ diff --git a/unittests/test-contracts/multi_index_test/CMakeLists.txt b/unittests/test-contracts/multi_index_test/CMakeLists.txt new file mode 100644 index 00000000000..f94955764eb --- /dev/null +++ b/unittests/test-contracts/multi_index_test/CMakeLists.txt @@ -0,0 +1,6 @@ +if( ${eosio.cdt_FOUND} ) + add_contract( snapshot_test multi_index_test multi_index_test.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/multi_index_test.wasm ${CMAKE_CURRENT_BINARY_DIR}/multi_index_test.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/multi_index_test.abi ${CMAKE_CURRENT_BINARY_DIR}/multi_index_test.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/multi_index_test/multi_index_test.abi b/unittests/test-contracts/multi_index_test/multi_index_test.abi new file mode 100644 index 00000000000..57b181e2ec7 --- /dev/null +++ b/unittests/test-contracts/multi_index_test/multi_index_test.abi @@ -0,0 +1,28 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Dec 7 11:56:44 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "multitest", + "base": "", + "fields": [ + { + "name": "what", + "type": "uint32" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "multitest", + "type": "multitest", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/test-contracts/multi_index_test/multi_index_test.cpp b/unittests/test-contracts/multi_index_test/multi_index_test.cpp new file mode 100644 index 00000000000..e214d324294 --- /dev/null +++ b/unittests/test-contracts/multi_index_test/multi_index_test.cpp @@ -0,0 +1,194 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include + +using namespace eosio; + +namespace multi_index_test { + + CONTRACT snapshot_test : public contract { + public: + using contract::contract; + + struct limit_order { + uint64_t id; + uint64_t padding = 0; + uint128_t price; + uint64_t expiration; + name owner; + + auto primary_key()const { return id; } + uint64_t get_expiration()const { return expiration; } + uint128_t get_price()const { return price; } + + EOSLIB_SERIALIZE( limit_order, (id)(price)(expiration)(owner) ) + }; + + struct test_k256 { + uint64_t id; + checksum256 val; + + auto primary_key()const { return id; } + checksum256 get_val()const { return val; } + + EOSLIB_SERIALIZE( test_k256, (id)(val) ) + }; + + struct trigger { + trigger( uint32_t w = 0 ) + : what(w) + {} + + uint32_t what; + }; + + ACTION multitest( uint32_t what ) { + trigger t( what ); + + on( t, _self ); + } + + static void on( const trigger& act, name _payer ) + { + name payer = _payer; + print("Acting on trigger action.\n"); + switch(act.what) + { + case 0: + { + print("Testing uint128_t secondary index.\n"); + eosio::multi_index<"orders"_n, limit_order, + indexed_by< "byexp"_n, const_mem_fun >, + indexed_by< "byprice"_n, const_mem_fun > + > orders( name{"multitest"}, name{"multitest"}.value ); + + orders.emplace( payer, [&]( auto& o ) { + o.id = 1; + o.expiration = 300; + o.owner = "dan"_n; }); + + auto order2 = orders.emplace( payer, [&]( auto& o ) { + o.id = 2; + o.expiration = 200; + o.owner = "alice"_n; }); + + print("Items sorted by primary key:\n"); + for( const auto& item : orders ) { + print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); + } + + auto expidx = orders.get_index<"byexp"_n>(); + + print("Items sorted by expiration:\n"); + for( const auto& item : expidx ) { + print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); + } + + print("Modifying expiration of order with ID=2 to 400.\n"); + orders.modify( order2, payer, [&]( auto& o ) { + o.expiration = 400; }); + + print("Items sorted by expiration:\n"); + for( const auto& item : expidx ) { + print(" ID=", item.id, ", expiration=", item.expiration, ", owner=", name{item.owner}, "\n"); + } + + auto lower = expidx.lower_bound( 100 ); + + print("First order with an expiration of at least 100 has ID=", lower->id, " and expiration=", lower->get_expiration(), "\n"); + + } + break; + case 1: // Test key265 secondary index + { + print("Testing key256 secondary index.\n"); + eosio::multi_index<"test1"_n, test_k256, + indexed_by< "byval"_n, const_mem_fun > + > testtable( "multitest"_n, "exchange"_n.value ); // Code must be same as the receiver? Scope doesn't have to be. + + testtable.emplace( payer, [&]( auto& o ) { + o.id = 1; + o.val = checksum256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 42ULL); }); + + testtable.emplace( payer, [&]( auto& o ) { + o.id = 2; + o.val = checksum256::make_from_word_sequence(1ULL, 2ULL, 3ULL, 4ULL); }); + + testtable.emplace( payer, [&]( auto& o ) { + o.id = 3; + o.val = checksum256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 42ULL); }); + + auto itr = testtable.find( 2 ); + + print("Items sorted by primary key:\n"); + for( const auto& item : testtable ) { + print(" ID=", item.primary_key(), ", val=", item.val, "\n"); + } + + auto validx = testtable.get_index<"byval"_n>(); + + auto lower1 = validx.lower_bound( checksum256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 40ULL) ); + print("First entry with a val of at least 40 has ID=", lower1->id, ".\n"); + + auto lower2 = validx.lower_bound( checksum256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 50ULL) ); + print("First entry with a val of at least 50 has ID=", lower2->id, ".\n"); + + if( testtable.iterator_to(*lower2) == itr ) { + print("Previously found entry is the same as the one found earlier with a primary key value of 2.\n"); + } + + print("Items sorted by val (secondary key):\n"); + for( const auto& item : validx ) { + print(" ID=", item.primary_key(), ", val=", item.val, "\n"); + } + + auto upper = validx.upper_bound( checksum256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 42ULL) ); + + print("First entry with a val greater than 42 has ID=", upper->id, ".\n"); + + print("Removed entry with ID=", lower1->id, ".\n"); + validx.erase( lower1 ); + + print("Items sorted by primary key:\n"); + for( const auto& item : testtable ) { + print(" ID=", item.primary_key(), ", val=", item.val, "\n"); + } + + } + break; + default: + eosio_assert( 0, "Given what code is not supported." ); + break; + } + } + }; +} /// multi_index_test + +namespace multi_index_test { + extern "C" { + /// The apply method implements the dispatch of events to this contract + void apply( uint64_t receiver, uint64_t code, uint64_t action ) { + require_auth( code ); + if( code == receiver ) { + if( action == "multitest"_n.value ) { + size_t size = action_data_size(); + void* buffer = nullptr; + buffer = alloca( 512 ); + read_action_data( buffer, size ); + datastream ds( (char*)buffer, size ); + + uint32_t w; + ds >> w; + + snapshot_test test( name{receiver}, name{code}, ds ); + test.multitest( w ); + } + else { + eosio_assert( false, "Could not dispatch" ); + } + } + } + } +} diff --git a/unittests/test-contracts/multi_index_test/multi_index_test.wasm b/unittests/test-contracts/multi_index_test/multi_index_test.wasm new file mode 100755 index 00000000000..529a41d9caf Binary files /dev/null and b/unittests/test-contracts/multi_index_test/multi_index_test.wasm differ diff --git a/unittests/test-contracts/noop/CMakeLists.txt b/unittests/test-contracts/noop/CMakeLists.txt new file mode 100644 index 00000000000..cd7538c1d23 --- /dev/null +++ b/unittests/test-contracts/noop/CMakeLists.txt @@ -0,0 +1,6 @@ +if( ${eosio.cdt_FOUND} ) + add_contract( noop noop noop.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/noop.wasm ${CMAKE_CURRENT_BINARY_DIR}/noop.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/noop.abi ${CMAKE_CURRENT_BINARY_DIR}/noop.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/noop/noop.abi b/unittests/test-contracts/noop/noop.abi new file mode 100644 index 00000000000..258eb2a946f --- /dev/null +++ b/unittests/test-contracts/noop/noop.abi @@ -0,0 +1,36 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Dec 7 11:56:43 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "anyaction", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "type", + "type": "string" + }, + { + "name": "data", + "type": "string" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "anyaction", + "type": "anyaction", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/test-contracts/noop/noop.cpp b/unittests/test-contracts/noop/noop.cpp new file mode 100644 index 00000000000..2fd0ccb6e76 --- /dev/null +++ b/unittests/test-contracts/noop/noop.cpp @@ -0,0 +1,24 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include + +namespace eosio { + + CONTRACT noop: public contract { + public: + using contract::contract; + + // Ignore type in action + ACTION anyaction( name from, + const eosio::ignore& type, + const eosio::ignore& data ) + { + require_auth( from ); + } + }; + + EOSIO_DISPATCH( noop, ( anyaction ) ) + +} /// namespace eosio diff --git a/unittests/test-contracts/noop/noop.wasm b/unittests/test-contracts/noop/noop.wasm new file mode 100755 index 00000000000..aa2acfcf854 Binary files /dev/null and b/unittests/test-contracts/noop/noop.wasm differ diff --git a/unittests/test-contracts/payloadless/CMakeLists.txt b/unittests/test-contracts/payloadless/CMakeLists.txt new file mode 100644 index 00000000000..2704b230d98 --- /dev/null +++ b/unittests/test-contracts/payloadless/CMakeLists.txt @@ -0,0 +1,6 @@ +if( ${eosio.cdt_FOUND} ) + add_contract( payloadless payloadless payloadless.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/payloadless.wasm ${CMAKE_CURRENT_BINARY_DIR}/payloadless.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/payloadless.abi ${CMAKE_CURRENT_BINARY_DIR}/payloadless.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/payloadless/payloadless.abi b/unittests/test-contracts/payloadless/payloadless.abi new file mode 100644 index 00000000000..1b31e14ce1b --- /dev/null +++ b/unittests/test-contracts/payloadless/payloadless.abi @@ -0,0 +1,23 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Dec 7 11:56:42 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "doit", + "base": "", + "fields": [] + } + ], + "types": [], + "actions": [ + { + "name": "doit", + "type": "doit", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/test-contracts/payloadless/payloadless.cpp b/unittests/test-contracts/payloadless/payloadless.cpp new file mode 100644 index 00000000000..9304da8e6cd --- /dev/null +++ b/unittests/test-contracts/payloadless/payloadless.cpp @@ -0,0 +1,19 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include + +using namespace eosio; + +CONTRACT payloadless : public contract { +public: + using contract::contract; + + ACTION doit() { + print("Im a payloadless action"); + } +}; + +EOSIO_DISPATCH( payloadless, (doit) ) diff --git a/contracts/payloadless/payloadless.doit_rc.md b/unittests/test-contracts/payloadless/payloadless.doit_rc.md similarity index 100% rename from contracts/payloadless/payloadless.doit_rc.md rename to unittests/test-contracts/payloadless/payloadless.doit_rc.md diff --git a/unittests/test-contracts/payloadless/payloadless.wasm b/unittests/test-contracts/payloadless/payloadless.wasm new file mode 100755 index 00000000000..2b6708ebd42 Binary files /dev/null and b/unittests/test-contracts/payloadless/payloadless.wasm differ diff --git a/contracts/payloadless/payloadless_rc.md b/unittests/test-contracts/payloadless/payloadless_rc.md similarity index 100% rename from contracts/payloadless/payloadless_rc.md rename to unittests/test-contracts/payloadless/payloadless_rc.md diff --git a/unittests/test-contracts/proxy/CMakeLists.txt b/unittests/test-contracts/proxy/CMakeLists.txt new file mode 100644 index 00000000000..45d519049ed --- /dev/null +++ b/unittests/test-contracts/proxy/CMakeLists.txt @@ -0,0 +1,7 @@ +if( ${eosio.cdt_FOUND} ) + add_executable( proxy proxy proxy.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/proxy.wasm ${CMAKE_CURRENT_BINARY_DIR}/proxy.wasm COPYONLY ) +endif() + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/proxy.abi ${CMAKE_CURRENT_BINARY_DIR}/proxy.abi COPYONLY ) diff --git a/contracts/proxy/proxy.abi b/unittests/test-contracts/proxy/proxy.abi similarity index 100% rename from contracts/proxy/proxy.abi rename to unittests/test-contracts/proxy/proxy.abi diff --git a/unittests/test-contracts/proxy/proxy.cpp b/unittests/test-contracts/proxy/proxy.cpp new file mode 100644 index 00000000000..c1a1ca0e633 --- /dev/null +++ b/unittests/test-contracts/proxy/proxy.cpp @@ -0,0 +1,101 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include + +#include "proxy.hpp" + +using namespace eosio; + +namespace proxy { + namespace configs { + bool get( config &out, const name &self ) { + auto it = db_find_i64( self.value, self.value, name{"config"}.value, out.key.value ); + if (it != -1) { + auto size = db_get_i64( it, (char*)&out, sizeof(config) ); + eosio_assert( size == sizeof(config), "Wrong record size" ); + return true; + } else { + return false; + } + } + + void store(const config &in, const name &self) { + auto it = db_find_i64(self.value, self.value, name{"config"}.value, in.key.value); + if (it != -1) { + db_update_i64(it, self.value, (const char *)&in, sizeof(config)); + } else { + db_store_i64(self.value, "config"_n.value, self.value, config::key.value, (const char *)&in, sizeof(config)); + } + } + } /// configs + + template + void apply_transfer( uint64_t receiver, name /* code */, const T& transfer ) { + config code_config; + const auto self = receiver; + auto get_res = configs::get( code_config, name{self} ); + eosio_assert( get_res, "Attempting to use unconfigured proxy" ); + if ( transfer.from == name{self} ) { + eosio_assert( transfer.to == name{code_config.owner}, "proxy may only pay its owner" ); + } else { + eosio_assert( transfer.to == name{self}, "proxy is not involved in this transfer" ); + T new_transfer = T(transfer); + new_transfer.from = name{self}; + new_transfer.to = name{code_config.owner}; + + auto id = code_config.next_id++; + configs::store( code_config, name{self} ); + + transaction out; + out.actions.emplace_back( permission_level{name{self}, "active"_n}, "eosio.token"_n, "transfer"_n, new_transfer ); + out.delay_sec = code_config.delay; + out.send( id, name{self} ); + } + } + +void apply_setowner(uint64_t receiver, set_owner params) { + const auto self = receiver; + require_auth(params.owner); + config code_config; + configs::get(code_config, name{self}); + code_config.owner = params.owner.value; + code_config.delay = params.delay; + eosio::print("Setting owner to: ", name{params.owner}, " with delay: ", params.delay, "\n"); + configs::store(code_config, name{self}); +} + +template +void apply_onerror(uint64_t receiver, const onerror& error ) { + eosio::print("starting onerror\n"); + const auto self = receiver; + config code_config; + eosio_assert(configs::get(code_config, name{self}), "Attempting use of unconfigured proxy"); + + auto id = code_config.next_id++; + configs::store(code_config, name{self}); + + eosio::print("Resending Transaction: ", error.sender_id, " as ", id, "\n"); + transaction dtrx = error.unpack_sent_trx(); + dtrx.delay_sec = code_config.delay; + dtrx.send(id, name{self}); +} }; // namespace proxy + +extern "C" { + + /// The apply method implements the dispatch of events to this contract + void apply( uint64_t receiver, uint64_t code, uint64_t action ) { + if( code == "eosio"_n.value && action == "onerror"_n.value ) { + proxy::apply_onerror( receiver, onerror::from_current_action() ); + } else if( code ==( "eosio.token"_n.value ) ) { + if( action ==( "transfer"_n.value ) ) { + apply_transfer( receiver, name{code}, unpack_action_data() ); + } + } else if( code == receiver ) { + if( action == "setowner"_n.value ) { + apply_setowner( receiver, unpack_action_data() ); + } + } + } +} diff --git a/unittests/test-contracts/proxy/proxy.hpp b/unittests/test-contracts/proxy/proxy.hpp new file mode 100644 index 00000000000..084258453a3 --- /dev/null +++ b/unittests/test-contracts/proxy/proxy.hpp @@ -0,0 +1,40 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once + +#include +#include + +using namespace eosio; + +namespace proxy { + + TABLE set_owner { + name owner; + uint32_t delay; + + EOSLIB_SERIALIZE( set_owner, (owner)(delay) ) + }; + + TABLE config { + static constexpr name key = "config"_n; + + capi_name owner = 0; + uint32_t delay = 0; + uint32_t next_id = 0; + + uint64_t primary_key() const { return key.value; } + + EOSLIB_SERIALIZE( config, (key)(owner)(delay)(next_id) ) + }; + + struct transfer_args { + name from; + name to; + asset quantity; + std::string memo; + }; + +} /// namespace proxy diff --git a/unittests/test-contracts/proxy/proxy.wasm b/unittests/test-contracts/proxy/proxy.wasm new file mode 100755 index 00000000000..78c4a6dcacf Binary files /dev/null and b/unittests/test-contracts/proxy/proxy.wasm differ diff --git a/unittests/test-contracts/snapshot_test/CMakeLists.txt b/unittests/test-contracts/snapshot_test/CMakeLists.txt new file mode 100644 index 00000000000..0e85b946055 --- /dev/null +++ b/unittests/test-contracts/snapshot_test/CMakeLists.txt @@ -0,0 +1,6 @@ +if( ${eosio.cdt_FOUND} ) + add_contract( snapshot_test snapshot_test snapshot_test.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/snapshot_test.wasm ${CMAKE_CURRENT_BINARY_DIR}/snapshot_test.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/snapshot_test.abi ${CMAKE_CURRENT_BINARY_DIR}/snapshot_test.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/snapshot_test/snapshot_test.abi b/unittests/test-contracts/snapshot_test/snapshot_test.abi new file mode 100644 index 00000000000..b82233291d0 --- /dev/null +++ b/unittests/test-contracts/snapshot_test/snapshot_test.abi @@ -0,0 +1,66 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Dec 7 11:56:43 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "increment", + "base": "", + "fields": [ + { + "name": "value", + "type": "uint32" + } + ] + }, + { + "name": "main_record", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "index_f64", + "type": "float64" + }, + { + "name": "index_f128", + "type": "float128" + }, + { + "name": "index_i64", + "type": "uint64" + }, + { + "name": "index_i128", + "type": "uint128" + }, + { + "name": "index_i256", + "type": "checksum256" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "increment", + "type": "increment", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "data", + "type": "main_record", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/test-contracts/snapshot_test/snapshot_test.cpp b/unittests/test-contracts/snapshot_test/snapshot_test.cpp new file mode 100644 index 00000000000..65ef6f6d854 --- /dev/null +++ b/unittests/test-contracts/snapshot_test/snapshot_test.cpp @@ -0,0 +1,82 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include + +using namespace eosio; + +namespace snapshot_test { + + struct [[eosio::contract("snapshot_test"), eosio::table]] main_record { + uint64_t id; + double index_f64 = 0.0; + long double index_f128 = 0.0L; + uint64_t index_i64 = 0ULL; + uint128_t index_i128 = 0ULL; + checksum256 index_i256 = checksum256(); + + auto primary_key()const { return id; } + + auto get_index_f64()const { return index_f64 ; } + auto get_index_f128()const { return index_f128; } + auto get_index_i64()const { return index_i64 ; } + auto get_index_i128()const { return index_i128; } + const checksum256& get_index_i256 ()const { return index_i256; } + + EOSLIB_SERIALIZE( main_record, (id)(index_f64)(index_f128)(index_i64)(index_i128)(index_i256) ) + }; + + struct [[eosio::contract("snapshot_test"), eosio::action]] increment { + increment(): value(0) {} + increment(uint32_t v): value(v) {} + + uint32_t value; + + EOSLIB_SERIALIZE( increment, (value) ) + }; + + using multi_index_type = eosio::multi_index<"data"_n, main_record, + indexed_by< "byf"_n, const_mem_fun>, + indexed_by< "byff"_n, const_mem_fun>, + indexed_by< "byi"_n, const_mem_fun>, + indexed_by< "byii"_n, const_mem_fun>, + indexed_by< "byiiii"_n, const_mem_fun> + >; + + static void exec( uint64_t self, uint32_t value ) { + multi_index_type data( name{self}, self ); + auto current = data.begin(); + if( current == data.end() ) { + data.emplace( name{self}, [&]( auto& r ) { + r.id = value; + r.index_f64 = value; + r.index_f128 = value; + r.index_i64 = value; + r.index_i128 = value; + r.index_i256.data()[0] = value; + }); + + } else { + data.modify( current, name{self}, [&]( auto& r ) { + r.index_f64 += value; + r.index_f128 += value; + r.index_i64 += value; + r.index_i128 += value; + r.index_i256.data()[0] += value; + }); + } + } + +} /// multi_index_test + +namespace multi_index_test { + extern "C" { + /// The apply method implements the dispatch of events to this contract + void apply( uint64_t self, uint64_t code, uint64_t action ) { + require_auth(code); + eosio_assert( action == "increment"_n.value, "unsupported action" ); + snapshot_test::exec( self, unpack_action_data().value ); + } + } +} diff --git a/unittests/test-contracts/snapshot_test/snapshot_test.wasm b/unittests/test-contracts/snapshot_test/snapshot_test.wasm new file mode 100755 index 00000000000..27692dbf540 Binary files /dev/null and b/unittests/test-contracts/snapshot_test/snapshot_test.wasm differ diff --git a/unittests/test-contracts/test.inline/CMakeLists.txt b/unittests/test-contracts/test.inline/CMakeLists.txt new file mode 100644 index 00000000000..8027e9c44c7 --- /dev/null +++ b/unittests/test-contracts/test.inline/CMakeLists.txt @@ -0,0 +1,6 @@ +if( ${eosio.cdt_FOUND} ) + add_contract( test.inline test.inline test.inline.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test.inline.wasm ${CMAKE_CURRENT_BINARY_DIR}/test.inline.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test.inline.abi ${CMAKE_CURRENT_BINARY_DIR}/test.inline.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/test.inline/test.inline.abi b/unittests/test-contracts/test.inline/test.inline.abi new file mode 100644 index 00000000000..8f152dad9e2 --- /dev/null +++ b/unittests/test-contracts/test.inline/test.inline.abi @@ -0,0 +1,11 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Dec 7 11:56:42 2018", + "version": "eosio::abi/1.1", + "structs": [], + "types": [], + "actions": [], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} \ No newline at end of file diff --git a/unittests/test-contracts/test.inline/test.inline.cpp b/unittests/test-contracts/test.inline/test.inline.cpp new file mode 100644 index 00000000000..3ff379bf807 --- /dev/null +++ b/unittests/test-contracts/test.inline/test.inline.cpp @@ -0,0 +1,7 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include "test.inline.hpp" + +EOSIO_DISPATCH( eosio::testinline, (reqauth)(forward) ) diff --git a/unittests/test-contracts/test.inline/test.inline.hpp b/unittests/test-contracts/test.inline/test.inline.hpp new file mode 100644 index 00000000000..1cc8db684f4 --- /dev/null +++ b/unittests/test-contracts/test.inline/test.inline.hpp @@ -0,0 +1,23 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include + +namespace eosio { + + CONTRACT testinline : public eosio::contract { + public: + using eosio::contract::contract; + + ACTION reqauth( name from ) { + require_auth( from ); + } + + ACTION forward( name reqauth, name forward_code, name forward_auth ) { + require_auth(reqauth); + INLINE_ACTION_SENDER( testinline, reqauth)( forward_code, {forward_auth,"active"_n}, {forward_auth} ); + } + }; + +} /// namespace eosio diff --git a/unittests/test-contracts/test.inline/test.inline.wasm b/unittests/test-contracts/test.inline/test.inline.wasm new file mode 100755 index 00000000000..91b4ccb686b Binary files /dev/null and b/unittests/test-contracts/test.inline/test.inline.wasm differ diff --git a/unittests/test-contracts/test_api/CMakeLists.txt b/unittests/test-contracts/test_api/CMakeLists.txt new file mode 100644 index 00000000000..00b4bcb0ee2 --- /dev/null +++ b/unittests/test-contracts/test_api/CMakeLists.txt @@ -0,0 +1,5 @@ +if( ${eosio.cdt_FOUND} ) + add_executable( test_api test_api.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test_api.wasm ${CMAKE_CURRENT_BINARY_DIR}/test_api.wasm COPYONLY ) +endif() diff --git a/contracts/test_api/test_action.cpp b/unittests/test-contracts/test_api/test_action.cpp similarity index 61% rename from contracts/test_api/test_action.cpp rename to unittests/test-contracts/test_api/test_action.cpp index 20eacaa1bd8..266fd030c23 100644 --- a/contracts/test_api/test_action.cpp +++ b/unittests/test-contracts/test_api/test_action.cpp @@ -3,41 +3,44 @@ * @copyright defined in eos/LICENSE */ #include -#include #include -#include +#include #include -#include -#include #include +#include +#include #include -#include +#include +#include + #include "test_api.hpp" +using namespace eosio; + void test_action::read_action_normal() { char buffer[100]; uint32_t total = 0; - eosio_assert(action_data_size() == sizeof(dummy_action), "action_size() == sizeof(dummy_action)"); + eosio_assert( action_data_size() == sizeof(dummy_action), "action_size() == sizeof(dummy_action)" ); - total = read_action_data(buffer, 30); - eosio_assert(total == sizeof(dummy_action) , "read_action(30)" ); + total = read_action_data( buffer, 30 ); + eosio_assert( total == sizeof(dummy_action) , "read_action(30)" ); - total = read_action_data(buffer, 100); + total = read_action_data( buffer, 100 ); eosio_assert(total == sizeof(dummy_action) , "read_action(100)" ); total = read_action_data(buffer, 5); - eosio_assert(total == 5 , "read_action(5)" ); + eosio_assert( total == 5 , "read_action(5)" ); total = read_action_data(buffer, sizeof(dummy_action) ); - eosio_assert(total == sizeof(dummy_action), "read_action(sizeof(dummy_action))" ); + eosio_assert( total == sizeof(dummy_action), "read_action(sizeof(dummy_action))" ); dummy_action *dummy13 = reinterpret_cast(buffer); - eosio_assert(dummy13->a == DUMMY_ACTION_DEFAULT_A, "dummy13->a == DUMMY_ACTION_DEFAULT_A"); - eosio_assert(dummy13->b == DUMMY_ACTION_DEFAULT_B, "dummy13->b == DUMMY_ACTION_DEFAULT_B"); - eosio_assert(dummy13->c == DUMMY_ACTION_DEFAULT_C, "dummy13->c == DUMMY_ACTION_DEFAULT_C"); + eosio_assert( dummy13->a == DUMMY_ACTION_DEFAULT_A, "dummy13->a == DUMMY_ACTION_DEFAULT_A" ); + eosio_assert( dummy13->b == DUMMY_ACTION_DEFAULT_B, "dummy13->b == DUMMY_ACTION_DEFAULT_B" ); + eosio_assert( dummy13->c == DUMMY_ACTION_DEFAULT_C, "dummy13->c == DUMMY_ACTION_DEFAULT_C" ); } void test_action::test_dummy_action() { @@ -49,26 +52,26 @@ void test_action::test_dummy_action() { total = get_action( 1, 0, buffer, static_cast(total) ); eosio_assert( total > 0, "get_action failed" ); eosio::action act = eosio::get_action( 1, 0 ); - eosio_assert( act.authorization.back().actor == N(testapi), "incorrect permission actor" ); - eosio_assert( act.authorization.back().permission == N(active), "incorrect permission name" ); + eosio_assert( act.authorization.back().actor == "testapi"_n, "incorrect permission actor" ); + eosio_assert( act.authorization.back().permission == "active"_n, "incorrect permission name" ); eosio_assert( eosio::pack_size(act) == static_cast(total), "pack_size does not match get_action size" ); - eosio_assert( act.account == N(testapi), "expected testapi account" ); + eosio_assert( act.account == "testapi"_n, "expected testapi account" ); dummy_action dum13 = act.data_as(); if ( dum13.b == 200 ) { // attempt to access context free only api get_context_free_data( 0, nullptr, 0 ); - eosio_assert(false, "get_context_free_data() not allowed in non-context free action"); + eosio_assert( false, "get_context_free_data() not allowed in non-context free action" ); } else { - eosio_assert(dum13.a == DUMMY_ACTION_DEFAULT_A, "dum13.a == DUMMY_ACTION_DEFAULT_A"); - eosio_assert(dum13.b == DUMMY_ACTION_DEFAULT_B, "dum13.b == DUMMY_ACTION_DEFAULT_B"); - eosio_assert(dum13.c == DUMMY_ACTION_DEFAULT_C, "dum13.c == DUMMY_ACTION_DEFAULT_C"); + eosio_assert( dum13.a == DUMMY_ACTION_DEFAULT_A, "dum13.a == DUMMY_ACTION_DEFAULT_A" ); + eosio_assert( dum13.b == DUMMY_ACTION_DEFAULT_B, "dum13.b == DUMMY_ACTION_DEFAULT_B" ); + eosio_assert( dum13.c == DUMMY_ACTION_DEFAULT_C, "dum13.c == DUMMY_ACTION_DEFAULT_C" ); } } void test_action::read_action_to_0() { - read_action_data((void *)0, action_data_size()); + read_action_data( (void *)0, action_data_size() ); } void test_action::read_action_to_64k() { @@ -83,14 +86,14 @@ void test_action::test_cf_action() { // verify read of get_context_free_data, also verifies system api access int size = get_context_free_data( cfa.cfd_idx, nullptr, 0 ); eosio_assert( size > 0, "size determination failed" ); - eosio::bytes cfd( static_cast(size) ); + std::vector cfd( static_cast(size) ); size = get_context_free_data( cfa.cfd_idx, &cfd[0], static_cast(size) ); eosio_assert(static_cast(size) == cfd.size(), "get_context_free_data failed" ); uint32_t v = eosio::unpack( &cfd[0], cfd.size() ); eosio_assert( v == cfa.payload, "invalid value" ); // verify crypto api access - checksum256 hash; + capi_checksum256 hash; char test[] = "test"; sha256( test, sizeof(test), &hash ); assert_sha256( test, sizeof(test), &hash ); @@ -100,7 +103,7 @@ void test_action::test_cf_action() { eosio::print("test\n"); // verify memory api access uint32_t i = 42; - memccpy(&v, &i, sizeof(i), sizeof(i)); + memccpy( &v, &i, sizeof(i), sizeof(i) ); // verify transaction api access eosio_assert(transaction_size() > 0, "transaction_size failed"); // verify softfloat api access @@ -109,14 +112,14 @@ void test_action::test_cf_action() { eosio_assert( f3 > 2.0f, "Unable to add float."); // verify compiler builtin api access __int128 ret; - __divti3(ret, 2, 2, 2, 2); + __divti3( ret, 2, 2, 2, 2 ); // verify context_free_system_api eosio_assert( true, "verify eosio_assert can be called" ); } else if ( cfa.payload == 200 ) { // attempt to access non context free api, privileged_api - is_privileged(act.name); + is_privileged(act.name.value); eosio_assert( false, "privileged_api should not be allowed" ); } else if ( cfa.payload == 201 ) { // attempt to access non context free api, producer_api @@ -124,15 +127,15 @@ void test_action::test_cf_action() { eosio_assert( false, "producer_api should not be allowed" ); } else if ( cfa.payload == 202 ) { // attempt to access non context free api, db_api - db_store_i64( N(testapi), N(testapi), N(testapi), 0, "test", 4 ); + db_store_i64( "testapi"_n.value, "testapi"_n.value, "testapi"_n.value, 0, "test", 4 ); eosio_assert( false, "db_api should not be allowed" ); } else if ( cfa.payload == 203 ) { // attempt to access non context free api, db_api uint64_t i = 0; - db_idx64_store( N(testapi), N(testapi), N(testapi), 0, &i ); + db_idx64_store( "testapi"_n.value, "testapi"_n.value, "testapi"_n.value, 0, &i ); eosio_assert( false, "db_api should not be allowed" ); } else if ( cfa.payload == 204 ) { - db_find_i64( N(testapi), N(testapi), N(testapi), 1); + db_find_i64( "testapi"_n.value, "testapi"_n.value, "testapi"_n.value, 1 ); eosio_assert( false, "db_api should not be allowed" ); } else if ( cfa.payload == 205 ) { // attempt to access non context free api, send action @@ -140,7 +143,7 @@ void test_action::test_cf_action() { dum_act.send(); eosio_assert( false, "action send should not be allowed" ); } else if ( cfa.payload == 206 ) { - eosio::require_auth(N(test)); + eosio::require_auth("test"_n); eosio_assert( false, "authorization_api should not be allowed" ); } else if ( cfa.payload == 207 ) { now(); @@ -155,52 +158,52 @@ void test_action::test_cf_action() { send_inline( (char*)"hello", 6 ); eosio_assert( false, "transaction_api should not be allowed" ); } else if ( cfa.payload == 211 ) { - send_deferred( N(testapi), N(testapi), "hello", 6 ); + send_deferred( "testapi"_n.value, "testapi"_n.value, "hello", 6, 0 ); eosio_assert( false, "transaction_api should not be allowed" ); } } -void test_action::require_notice(uint64_t receiver, uint64_t code, uint64_t action) { +void test_action::require_notice( uint64_t receiver, uint64_t code, uint64_t action ) { (void)code;(void)action; - if( receiver == N(testapi) ) { - eosio::require_recipient( N(acc1) ); - eosio::require_recipient( N(acc2) ); - eosio::require_recipient( N(acc1), N(acc2) ); - eosio_assert(false, "Should've failed"); - } else if ( receiver == N(acc1) || receiver == N(acc2) ) { + if( receiver == "testapi"_n.value ) { + eosio::require_recipient( "acc1"_n ); + eosio::require_recipient( "acc2"_n ); + eosio::require_recipient( "acc1"_n, "acc2"_n ); + eosio_assert( false, "Should've failed" ); + } else if ( receiver == "acc1"_n.value || receiver == "acc2"_n.value ) { return; } - eosio_assert(false, "Should've failed"); + eosio_assert( false, "Should've failed" ); } -void test_action::require_notice_tests(uint64_t receiver, uint64_t code, uint64_t action) { +void test_action::require_notice_tests( uint64_t receiver, uint64_t code, uint64_t action ) { eosio::print( "require_notice_tests" ); - if( receiver == N( testapi ) ) { - eosio::print( "require_recipient( N(acc5) )" ); - eosio::require_recipient( N( acc5 ) ); - } else if( receiver == N( acc5 ) ) { - eosio::print( "require_recipient( N(testapi) )" ); - eosio::require_recipient( N( testapi ) ); + if( receiver == "testapi"_n.value ) { + eosio::print("require_recipient( \"acc5\"_n )"); + eosio::require_recipient("acc5"_n); + } else if( receiver == "acc5"_n.value ) { + eosio::print("require_recipient( \"testapi\"_n )"); + eosio::require_recipient("testapi"_n); } } void test_action::require_auth() { prints("require_auth"); - eosio::require_auth( N(acc3) ); - eosio::require_auth( N(acc4) ); + eosio::require_auth("acc3"_n); + eosio::require_auth("acc4"_n); } void test_action::assert_false() { - eosio_assert(false, "test_action::assert_false"); + eosio_assert( false, "test_action::assert_false" ); } void test_action::assert_true() { - eosio_assert(true, "test_action::assert_true"); + eosio_assert( true, "test_action::assert_true" ); } void test_action::assert_true_cf() { - eosio_assert(true, "test_action::assert_true"); + eosio_assert( true, "test_action::assert_true" ); } void test_action::test_abort() { @@ -210,54 +213,53 @@ void test_action::test_abort() { void test_action::test_publication_time() { uint64_t pub_time = 0; - uint32_t total = read_action_data(&pub_time, sizeof(uint64_t)); - eosio_assert( total == sizeof(uint64_t), "total == sizeof(uint64_t)"); + uint32_t total = read_action_data( &pub_time, sizeof(uint64_t) ); + eosio_assert( total == sizeof(uint64_t), "total == sizeof(uint64_t)" ); eosio_assert( pub_time == publication_time(), "pub_time == publication_time()" ); } -void test_action::test_current_receiver(uint64_t receiver, uint64_t code, uint64_t action) { +void test_action::test_current_receiver( uint64_t receiver, uint64_t code, uint64_t action ) { (void)code;(void)action; - account_name cur_rec; - read_action_data(&cur_rec, sizeof(account_name)); + name cur_rec; + read_action_data( &cur_rec, sizeof(name) ); - eosio_assert( receiver == cur_rec, "the current receiver does not match" ); + eosio_assert( receiver == cur_rec.value, "the current receiver does not match" ); } void test_action::test_current_time() { uint64_t tmp = 0; - uint32_t total = read_action_data(&tmp, sizeof(uint64_t)); - eosio_assert( total == sizeof(uint64_t), "total == sizeof(uint64_t)"); + uint32_t total = read_action_data( &tmp, sizeof(uint64_t) ); + eosio_assert( total == sizeof(uint64_t), "total == sizeof(uint64_t)" ); eosio_assert( tmp == current_time(), "tmp == current_time()" ); } void test_action::test_assert_code() { uint64_t code = 0; uint32_t total = read_action_data(&code, sizeof(uint64_t)); - eosio_assert( total == sizeof(uint64_t), "total == sizeof(uint64_t)"); + eosio_assert( total == sizeof(uint64_t), "total == sizeof(uint64_t)" ); eosio_assert_code( false, code ); } -void test_action::test_ram_billing_in_notify(uint64_t receiver, uint64_t code, uint64_t action) { +void test_action::test_ram_billing_in_notify( uint64_t receiver, uint64_t code, uint64_t action ) { uint128_t tmp = 0; - uint32_t total = read_action_data(&tmp, sizeof(uint128_t)); - eosio_assert( total == sizeof(uint128_t), "total == sizeof(uint128_t)"); + uint32_t total = read_action_data( &tmp, sizeof(uint128_t) ); + eosio_assert( total == sizeof(uint128_t), "total == sizeof(uint128_t)" ); uint64_t to_notify = tmp >> 64; uint64_t payer = tmp & 0xFFFFFFFFFFFFFFFFULL; if( code == receiver ) { - eosio::require_recipient( to_notify ); + eosio::require_recipient( name{to_notify} ); } else { eosio_assert( to_notify == receiver, "notified recipient other than the one specified in to_notify" ); // Remove main table row if it already exists. - int itr = db_find_i64( receiver, N(notifytest), N(notifytest), N(notifytest) ); + int itr = db_find_i64( receiver, "notifytest"_n.value, "notifytest"_n.value, "notifytest"_n.value ); if( itr >= 0 ) db_remove_i64( itr ); // Create the main table row simply for the purpose of charging code more RAM. if( payer != 0 ) - db_store_i64(N(notifytest), N(notifytest), payer, N(notifytest), &to_notify, sizeof(to_notify) ); + db_store_i64( "notifytest"_n.value, "notifytest"_n.value, payer, "notifytest"_n.value, &to_notify, sizeof(to_notify) ); } - } diff --git a/unittests/test-contracts/test_api/test_api.cpp b/unittests/test-contracts/test_api/test_api.cpp new file mode 100644 index 00000000000..67c720c1f0f --- /dev/null +++ b/unittests/test-contracts/test_api/test_api.cpp @@ -0,0 +1,189 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include +#include + +#include "test_api.hpp" + +#include "test_action.cpp" +#include "test_chain.cpp" +#include "test_checktime.cpp" +#include "test_compiler_builtins.cpp" +#include "test_crypto.cpp" +#include "test_datastream.cpp" +#include "test_fixedpoint.cpp" +#include "test_permission.cpp" +#include "test_print.cpp" +#include "test_transaction.cpp" +#include "test_types.cpp" + +name global_receiver; + +extern "C" { + void apply( uint64_t receiver, uint64_t code, uint64_t action ) { + if( code == "eosio"_n.value && action == "onerror"_n.value ) { + auto error = eosio::onerror::from_current_action(); + eosio::print("onerror called\n"); + auto error_trx = error.unpack_sent_trx(); + auto error_action = error_trx.actions.at(0).name; + + // Error handlers for deferred transactions in these tests currently only support the first action + + WASM_TEST_ERROR_HANDLER( "test_action", "assert_false", test_transaction, assert_false_error_handler ); + + + return; + } + + if ( action == name{"cfaction"}.value ) { + test_action::test_cf_action(); + return; + } + WASM_TEST_HANDLER( test_action, assert_true_cf ); + + if ( action != WASM_TEST_ACTION("test_transaction", "stateful_api") && action != WASM_TEST_ACTION("test_transaction", "context_free_api") ) + require_auth(code); + + //test_types + WASM_TEST_HANDLER( test_types, types_size ); + WASM_TEST_HANDLER( test_types, char_to_symbol ); + WASM_TEST_HANDLER( test_types, string_to_name ); + + //test_compiler_builtins + WASM_TEST_HANDLER( test_compiler_builtins, test_multi3 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_divti3 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_divti3_by_0 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_udivti3 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_udivti3_by_0 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_modti3 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_modti3_by_0 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_umodti3 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_umodti3_by_0 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_lshlti3 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_lshrti3 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_ashlti3 ); + WASM_TEST_HANDLER( test_compiler_builtins, test_ashrti3 ); + + //test_action + WASM_TEST_HANDLER ( test_action, read_action_normal ); + WASM_TEST_HANDLER ( test_action, read_action_to_0 ); + WASM_TEST_HANDLER ( test_action, read_action_to_64k ); + WASM_TEST_HANDLER_EX( test_action, require_notice ); + WASM_TEST_HANDLER_EX( test_action, require_notice_tests ); + WASM_TEST_HANDLER ( test_action, require_auth ); + WASM_TEST_HANDLER ( test_action, assert_false ); + WASM_TEST_HANDLER ( test_action, assert_true ); + WASM_TEST_HANDLER ( test_action, test_current_time ); + WASM_TEST_HANDLER ( test_action, test_abort ); + WASM_TEST_HANDLER_EX( test_action, test_current_receiver ); + WASM_TEST_HANDLER ( test_action, test_publication_time ); + WASM_TEST_HANDLER ( test_action, test_assert_code ); + WASM_TEST_HANDLER_EX( test_action, test_ram_billing_in_notify ); + + // test named actions + // We enforce action name matches action data type name, so name mangling will not work for these tests. + if ( action == name{"dummyaction"}.value ) { + test_action::test_dummy_action(); + return; + } + //test_print + WASM_TEST_HANDLER( test_print, test_prints ); + WASM_TEST_HANDLER( test_print, test_prints_l ); + WASM_TEST_HANDLER( test_print, test_printi ); + WASM_TEST_HANDLER( test_print, test_printui ); + WASM_TEST_HANDLER( test_print, test_printi128 ); + WASM_TEST_HANDLER( test_print, test_printui128 ); + WASM_TEST_HANDLER( test_print, test_printn ); + WASM_TEST_HANDLER( test_print, test_printsf ); + WASM_TEST_HANDLER( test_print, test_printdf ); + WASM_TEST_HANDLER( test_print, test_printqf ); + + //test crypto + WASM_TEST_HANDLER( test_crypto, test_recover_key ); + WASM_TEST_HANDLER( test_crypto, test_recover_key_assert_true ); + WASM_TEST_HANDLER( test_crypto, test_recover_key_assert_false ); + WASM_TEST_HANDLER( test_crypto, test_sha1 ); + WASM_TEST_HANDLER( test_crypto, test_sha256 ); + WASM_TEST_HANDLER( test_crypto, test_sha512 ); + WASM_TEST_HANDLER( test_crypto, test_ripemd160 ); + WASM_TEST_HANDLER( test_crypto, sha1_no_data ); + WASM_TEST_HANDLER( test_crypto, sha256_no_data ); + WASM_TEST_HANDLER( test_crypto, sha512_no_data ); + WASM_TEST_HANDLER( test_crypto, ripemd160_no_data ); + WASM_TEST_HANDLER( test_crypto, sha256_null ); + WASM_TEST_HANDLER( test_crypto, assert_sha256_false ); + WASM_TEST_HANDLER( test_crypto, assert_sha256_true ); + WASM_TEST_HANDLER( test_crypto, assert_sha1_false ); + WASM_TEST_HANDLER( test_crypto, assert_sha1_true ); + WASM_TEST_HANDLER( test_crypto, assert_sha512_false ); + WASM_TEST_HANDLER( test_crypto, assert_sha512_true ); + WASM_TEST_HANDLER( test_crypto, assert_ripemd160_false ); + WASM_TEST_HANDLER( test_crypto, assert_ripemd160_true ); + + //test transaction + WASM_TEST_HANDLER ( test_transaction, test_tapos_block_num ); + WASM_TEST_HANDLER ( test_transaction, test_tapos_block_prefix ); + WASM_TEST_HANDLER ( test_transaction, send_action ); + WASM_TEST_HANDLER ( test_transaction, send_action_inline_fail ); + WASM_TEST_HANDLER ( test_transaction, send_action_empty ); + WASM_TEST_HANDLER ( test_transaction, send_action_large ); + WASM_TEST_HANDLER ( test_transaction, send_action_recurse ); + WASM_TEST_HANDLER ( test_transaction, test_read_transaction ); + WASM_TEST_HANDLER ( test_transaction, test_transaction_size ); + WASM_TEST_HANDLER_EX( test_transaction, send_transaction ); + WASM_TEST_HANDLER_EX( test_transaction, send_transaction_empty ); + WASM_TEST_HANDLER_EX( test_transaction, send_transaction_trigger_error_handler ); + WASM_TEST_HANDLER_EX( test_transaction, send_transaction_large ); + WASM_TEST_HANDLER_EX( test_transaction, send_action_sender ); + WASM_TEST_HANDLER ( test_transaction, deferred_print ); + WASM_TEST_HANDLER_EX( test_transaction, send_deferred_transaction ); + WASM_TEST_HANDLER_EX( test_transaction, send_deferred_transaction_replace ); + WASM_TEST_HANDLER ( test_transaction, send_deferred_tx_with_dtt_action ); + WASM_TEST_HANDLER ( test_transaction, cancel_deferred_transaction_success ); + WASM_TEST_HANDLER ( test_transaction, cancel_deferred_transaction_not_found ); + WASM_TEST_HANDLER ( test_transaction, send_cf_action ); + WASM_TEST_HANDLER ( test_transaction, send_cf_action_fail ); + WASM_TEST_HANDLER ( test_transaction, stateful_api ); + WASM_TEST_HANDLER ( test_transaction, context_free_api ); + WASM_TEST_HANDLER ( test_transaction, new_feature ); + WASM_TEST_HANDLER ( test_transaction, active_new_feature ); + WASM_TEST_HANDLER_EX( test_transaction, repeat_deferred_transaction ); + + //test chain + WASM_TEST_HANDLER( test_chain, test_activeprods ); + + // test fixed_point + WASM_TEST_HANDLER( test_fixedpoint, create_instances ); + WASM_TEST_HANDLER( test_fixedpoint, test_addition ); + WASM_TEST_HANDLER( test_fixedpoint, test_subtraction ); + WASM_TEST_HANDLER( test_fixedpoint, test_multiplication ); + WASM_TEST_HANDLER( test_fixedpoint, test_division ); + WASM_TEST_HANDLER( test_fixedpoint, test_division_by_0 ); + + // test checktime + WASM_TEST_HANDLER( test_checktime, checktime_pass ); + WASM_TEST_HANDLER( test_checktime, checktime_failure ); + WASM_TEST_HANDLER( test_checktime, checktime_sha1_failure ); + WASM_TEST_HANDLER( test_checktime, checktime_assert_sha1_failure ); + WASM_TEST_HANDLER( test_checktime, checktime_sha256_failure ); + WASM_TEST_HANDLER( test_checktime, checktime_assert_sha256_failure ); + WASM_TEST_HANDLER( test_checktime, checktime_sha512_failure ); + WASM_TEST_HANDLER( test_checktime, checktime_assert_sha512_failure ); + WASM_TEST_HANDLER( test_checktime, checktime_ripemd160_failure ); + WASM_TEST_HANDLER( test_checktime, checktime_assert_ripemd160_failure ); + + // test datastream + WASM_TEST_HANDLER( test_datastream, test_basic ); + + // test permission + WASM_TEST_HANDLER_EX( test_permission, check_authorization ); + WASM_TEST_HANDLER_EX( test_permission, test_permission_last_used ); + WASM_TEST_HANDLER_EX( test_permission, test_account_creation_time ); + + //unhandled test call + eosio_assert( false, "Unknown Test" ); + + } +} diff --git a/contracts/test_api/test_api.hpp b/unittests/test-contracts/test_api/test_api.hpp similarity index 69% rename from contracts/test_api/test_api.hpp rename to unittests/test-contracts/test_api/test_api.hpp index 5406dff5520..c3065d5d0ef 100644 --- a/contracts/test_api/test_api.hpp +++ b/unittests/test-contracts/test_api/test_api.hpp @@ -3,16 +3,12 @@ * @copyright defined in eos/LICENSE */ #pragma once -#include "test_api_common.hpp" -#include +#include -namespace eosio { - class transaction; -} - +#include "test_api_common.hpp" -//#include +namespace eosio { class transaction; } // NOTE: including eosiolib/transaction.hpp here causes !"unresolvable": env._ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv // errors in api_tests/memory_tests @@ -30,50 +26,49 @@ namespace eosio { } #define WASM_TEST_ERROR_HANDLER(CALLED_CLASS_STR, CALLED_METHOD_STR, HANDLER_CLASS, HANDLER_METHOD) \ -if( error_action == WASM_TEST_ACTION(CALLED_CLASS_STR, CALLED_METHOD_STR) ) { \ + if( error_action == name{WASM_TEST_ACTION(CALLED_CLASS_STR, CALLED_METHOD_STR)} ) { \ HANDLER_CLASS::HANDLER_METHOD(error_trx); \ return; \ } struct test_types { - static void types_size(); - static void char_to_symbol(); - static void string_to_name(); - static void name_class(); + static void types_size(); + static void char_to_symbol(); + static void string_to_name(); }; struct test_print { - static void test_prints(); - static void test_prints_l(); - static void test_printi(); - static void test_printui(); - static void test_printi128(); - static void test_printui128(); - static void test_printn(); - static void test_printsf(); - static void test_printdf(); - static void test_printqf(); - static void test_print_simple(); + static void test_prints(); + static void test_prints_l(); + static void test_printi(); + static void test_printui(); + static void test_printi128(); + static void test_printui128(); + static void test_printn(); + static void test_printsf(); + static void test_printdf(); + static void test_printqf(); + static void test_print_simple(); }; struct test_action { - static void read_action_normal(); - static void read_action_to_0(); - static void read_action_to_64k(); - static void test_dummy_action(); - static void test_cf_action(); - static void require_notice(uint64_t receiver, uint64_t code, uint64_t action); - static void require_notice_tests(uint64_t receiver, uint64_t code, uint64_t action); - static void require_auth(); - static void assert_false(); - static void assert_true(); - static void assert_true_cf(); - static void test_current_time(); - static void test_abort() __attribute__ ((noreturn)) ; - static void test_current_receiver(uint64_t receiver, uint64_t code, uint64_t action); - static void test_publication_time(); - static void test_assert_code(); - static void test_ram_billing_in_notify(uint64_t receiver, uint64_t code, uint64_t action); + static void read_action_normal(); + static void read_action_to_0(); + static void read_action_to_64k(); + static void test_dummy_action(); + static void test_cf_action(); + static void require_notice(uint64_t receiver, uint64_t code, uint64_t action); + static void require_notice_tests(uint64_t receiver, uint64_t code, uint64_t action); + static void require_auth(); + static void assert_false(); + static void assert_true(); + static void assert_true_cf(); + static void test_current_time(); + static void test_abort() __attribute__ ((noreturn)) ; + static void test_current_receiver(uint64_t receiver, uint64_t code, uint64_t action); + static void test_publication_time(); + static void test_assert_code(); + static void test_ram_billing_in_notify(uint64_t receiver, uint64_t code, uint64_t action); }; struct test_db { @@ -153,40 +148,40 @@ struct test_crypto { }; struct test_transaction { - static void test_tapos_block_num(); - static void test_tapos_block_prefix(); - static void send_action(); - static void send_action_empty(); - static void send_action_max(); - static void send_action_large(); - static void send_action_recurse(); - static void send_action_inline_fail(); - static void test_read_transaction(); - static void test_transaction_size(); - static void send_transaction(uint64_t receiver, uint64_t code, uint64_t action); - static void send_transaction_empty(uint64_t receiver, uint64_t code, uint64_t action); - static void send_transaction_trigger_error_handler(uint64_t receiver, uint64_t code, uint64_t action); - static void assert_false_error_handler(const eosio::transaction&); - static void send_transaction_max(); - static void send_transaction_large(uint64_t receiver, uint64_t code, uint64_t action); - static void send_action_sender(uint64_t receiver, uint64_t code, uint64_t action); - static void deferred_print(); - static void send_deferred_transaction(uint64_t receiver, uint64_t code, uint64_t action); - static void send_deferred_transaction_replace(uint64_t receiver, uint64_t code, uint64_t action); - static void send_deferred_tx_with_dtt_action(); - static void cancel_deferred_transaction_success(); - static void cancel_deferred_transaction_not_found(); - static void send_cf_action(); - static void send_cf_action_fail(); - static void stateful_api(); - static void context_free_api(); - static void new_feature(); - static void active_new_feature(); - static void repeat_deferred_transaction(uint64_t receiver, uint64_t code, uint64_t action); + static void test_tapos_block_num(); + static void test_tapos_block_prefix(); + static void send_action(); + static void send_action_empty(); + static void send_action_max(); + static void send_action_large(); + static void send_action_recurse(); + static void send_action_inline_fail(); + static void test_read_transaction(); + static void test_transaction_size(); + static void send_transaction(uint64_t receiver, uint64_t code, uint64_t action); + static void send_transaction_empty(uint64_t receiver, uint64_t code, uint64_t action); + static void send_transaction_trigger_error_handler(uint64_t receiver, uint64_t code, uint64_t action); + static void assert_false_error_handler(const eosio::transaction&); + static void send_transaction_max(); + static void send_transaction_large(uint64_t receiver, uint64_t code, uint64_t action); + static void send_action_sender(uint64_t receiver, uint64_t code, uint64_t action); + static void deferred_print(); + static void send_deferred_transaction(uint64_t receiver, uint64_t code, uint64_t action); + static void send_deferred_transaction_replace(uint64_t receiver, uint64_t code, uint64_t action); + static void send_deferred_tx_with_dtt_action(); + static void cancel_deferred_transaction_success(); + static void cancel_deferred_transaction_not_found(); + static void send_cf_action(); + static void send_cf_action_fail(); + static void stateful_api(); + static void context_free_api(); + static void new_feature(); + static void active_new_feature(); + static void repeat_deferred_transaction(uint64_t receiver, uint64_t code, uint64_t action); }; struct test_chain { - static void test_activeprods(); + static void test_activeprods(); }; struct test_fixedpoint { @@ -215,10 +210,10 @@ struct test_compiler_builtins { }; struct test_extended_memory { - static void test_initial_buffer(); - static void test_page_memory(); - static void test_page_memory_exceeded(); - static void test_page_memory_negative_bytes(); + static void test_initial_buffer(); + static void test_page_memory(); + static void test_page_memory_exceeded(); + static void test_page_memory_negative_bytes(); }; struct test_memory { @@ -257,23 +252,16 @@ struct test_checktime { static void checktime_assert_sha512_failure(); static void checktime_ripemd160_failure(); static void checktime_assert_ripemd160_failure(); + + static int i; }; -/* -struct test_softfloat { - static void test_f32_add(); - static void test_f32_sub(); - static void test_f32_mul(); - static void test_f32_div(); - static void test_f32_min(); -}; -*/ struct test_permission { - static void check_authorization(uint64_t receiver, uint64_t code, uint64_t action); - static void test_permission_last_used(uint64_t receiver, uint64_t code, uint64_t action); - static void test_account_creation_time(uint64_t receiver, uint64_t code, uint64_t action); + static void check_authorization(uint64_t receiver, uint64_t code, uint64_t action); + static void test_permission_last_used(uint64_t receiver, uint64_t code, uint64_t action); + static void test_account_creation_time(uint64_t receiver, uint64_t code, uint64_t action); }; struct test_datastream { - static void test_basic(); + static void test_basic(); }; diff --git a/unittests/test-contracts/test_api/test_api.wasm b/unittests/test-contracts/test_api/test_api.wasm new file mode 100755 index 00000000000..98c15da3d2a Binary files /dev/null and b/unittests/test-contracts/test_api/test_api.wasm differ diff --git a/contracts/test_api/test_api_common.hpp b/unittests/test-contracts/test_api/test_api_common.hpp similarity index 65% rename from contracts/test_api/test_api_common.hpp rename to unittests/test-contracts/test_api/test_api_common.hpp index d78afa29bb3..bfad0146b46 100644 --- a/contracts/test_api/test_api_common.hpp +++ b/unittests/test-contracts/test_api/test_api_common.hpp @@ -4,13 +4,10 @@ */ #pragma once -#ifdef DISABLE_EOSLIB_SERIALIZE #include -#undef EOSLIB_SERIALIZE -#define EOSLIB_SERIALIZE(...) -#endif -static constexpr unsigned int DJBH(const char* cp) + +static constexpr unsigned int DJBH( const char* cp ) { unsigned int hash = 5381; while (*cp) @@ -18,18 +15,18 @@ static constexpr unsigned int DJBH(const char* cp) return hash; } -static constexpr unsigned long long WASM_TEST_ACTION(const char* cls, const char* method) +static constexpr unsigned long long WASM_TEST_ACTION( const char* cls, const char* method ) { - return static_cast(DJBH(cls)) << 32 | static_cast(DJBH(method)); + return static_cast( DJBH(cls)) << 32 | static_cast(DJBH(method) ); } #pragma pack(push, 1) struct dummy_action { static uint64_t get_name() { - return N(dummy_action); + return eosio::name{"dummy_action"}.value; } static uint64_t get_account() { - return N(testapi); + return eosio::name{"testapi"}.value; } char a; //1 @@ -47,10 +44,10 @@ struct u128_action { struct cf_action { static uint64_t get_name() { - return N(cf_action); + return eosio::name{"cf_action"}.value; } static uint64_t get_account() { - return N(testapi); + return eosio::name{"testapi"}.value; } uint32_t payload = 100; @@ -62,16 +59,16 @@ struct cf_action { // Deferred Transaction Trigger Action struct dtt_action { static uint64_t get_name() { - return WASM_TEST_ACTION("test_transaction", "send_deferred_tx_with_dtt_action"); + return WASM_TEST_ACTION( "test_transaction", "send_deferred_tx_with_dtt_action" ); } static uint64_t get_account() { - return N(testapi); + return "testapi"_n.value; } - uint64_t payer = N(testapi); - uint64_t deferred_account = N(testapi); - uint64_t deferred_action = WASM_TEST_ACTION("test_transaction", "deferred_print"); - uint64_t permission_name = N(active); + uint64_t payer = "testapi"_n.value; + uint64_t deferred_account = "testapi"_n.value; + uint64_t deferred_action = WASM_TEST_ACTION( "test_transaction", "deferred_print" ); + uint64_t permission_name = "active"_n.value; uint32_t delay_sec = 2; EOSLIB_SERIALIZE( dtt_action, (payer)(deferred_account)(deferred_action)(permission_name)(delay_sec) ) diff --git a/contracts/test_api/test_chain.cpp b/unittests/test-contracts/test_api/test_chain.cpp similarity index 54% rename from contracts/test_api/test_chain.cpp rename to unittests/test-contracts/test_api/test_chain.cpp index 22f4ca4f914..b9e35f870ee 100644 --- a/contracts/test_api/test_chain.cpp +++ b/unittests/test-contracts/test_api/test_chain.cpp @@ -5,24 +5,25 @@ #include #include #include + #include "test_api.hpp" #pragma pack(push, 1) struct producers { char len; - account_name producers[21]; + capi_name producers[21]; }; #pragma pack(pop) void test_chain::test_activeprods() { producers act_prods; - read_action_data(&act_prods, sizeof(producers)); + read_action_data( &act_prods, sizeof(producers) ); - eosio_assert(act_prods.len == 21, "producers.len != 21"); + eosio_assert( act_prods.len == 21, "producers.len != 21" ); producers api_prods; - get_active_producers(api_prods.producers, sizeof(account_name)*21); + get_active_producers( api_prods.producers, sizeof(eosio::name)*21 ); for( int i = 0; i < 21 ; ++i ) - eosio_assert(api_prods.producers[i] == act_prods.producers[i], "Active producer"); + eosio_assert( api_prods.producers[i] == act_prods.producers[i], "Active producer" ); } diff --git a/contracts/test_api/test_checktime.cpp b/unittests/test-contracts/test_api/test_checktime.cpp similarity index 74% rename from contracts/test_api/test_checktime.cpp rename to unittests/test-contracts/test_api/test_checktime.cpp index a227ee91b04..4475f9fb873 100644 --- a/contracts/test_api/test_checktime.cpp +++ b/unittests/test-contracts/test_api/test_checktime.cpp @@ -2,13 +2,13 @@ * @file * @copyright defined in eos/LICENSE */ +#include -#include #include +#include #include -#include "test_api.hpp" -#include +#include "test_api.hpp" void test_checktime::checktime_pass() { int p = 0; @@ -18,12 +18,15 @@ void test_checktime::checktime_pass() { eosio::print(p); } + void test_checktime::checktime_failure() { - int p = 0; - for ( unsigned long long i = 0; i < 10000000000000000000ULL; i++ ) - for ( unsigned long long j = 0; i < 10000000000000000000ULL; i++ ) - p += i+j; + volatile unsigned long long bound{}; // `volatile' necessary to prevent loop optimization + read_action_data( (char*)&bound, sizeof(bound) ); + int p = 0; + for ( unsigned long long i = 0; i < bound; i++ ) + for ( unsigned long long j = 0; j < bound; j++ ) + p += i+j+bound; eosio::print(p); } @@ -32,48 +35,48 @@ constexpr size_t size = 20000000; void test_checktime::checktime_sha1_failure() { char* ptr = new char[size]; - checksum160 res; + capi_checksum160 res; sha1( ptr, size, &res ); } void test_checktime::checktime_assert_sha1_failure() { char* ptr = new char[size]; - checksum160 res; + capi_checksum160 res; assert_sha1( ptr, size, &res ); } void test_checktime::checktime_sha256_failure() { char* ptr = new char[size]; - checksum256 res; + capi_checksum256 res; sha256( ptr, size, &res ); } void test_checktime::checktime_assert_sha256_failure() { char* ptr = new char[size]; - checksum256 res; + capi_checksum256 res; assert_sha256( ptr, size, &res ); } void test_checktime::checktime_sha512_failure() { char* ptr = new char[size]; - checksum512 res; + capi_checksum512 res; sha512( ptr, size, &res ); } void test_checktime::checktime_assert_sha512_failure() { char* ptr = new char[size]; - checksum512 res; + capi_checksum512 res; assert_sha512( ptr, size, &res ); } void test_checktime::checktime_ripemd160_failure() { char* ptr = new char[size]; - checksum160 res; + capi_checksum160 res; ripemd160( ptr, size, &res ); } void test_checktime::checktime_assert_ripemd160_failure() { char* ptr = new char[size]; - checksum160 res; + capi_checksum160 res; assert_ripemd160( ptr, size, &res ); } diff --git a/contracts/test_api/test_compiler_builtins.cpp b/unittests/test-contracts/test_api/test_compiler_builtins.cpp similarity index 99% rename from contracts/test_api/test_compiler_builtins.cpp rename to unittests/test-contracts/test_api/test_compiler_builtins.cpp index a7571b0a2ce..7cf07efb172 100644 --- a/contracts/test_api/test_compiler_builtins.cpp +++ b/unittests/test-contracts/test_api/test_compiler_builtins.cpp @@ -2,10 +2,9 @@ * @file test_compiler_builtins.cpp * @copyright defined in eos/LICENSE */ - +#include #include #include -#include #include "test_api.hpp" diff --git a/contracts/test_api/test_crypto.cpp b/unittests/test-contracts/test_api/test_crypto.cpp similarity index 56% rename from contracts/test_api/test_crypto.cpp rename to unittests/test-contracts/test_api/test_crypto.cpp index 3b96e6e6fad..c310b2a2778 100644 --- a/contracts/test_api/test_crypto.cpp +++ b/unittests/test-contracts/test_api/test_crypto.cpp @@ -2,11 +2,12 @@ * @file * @copyright defined in eos/LICENSE */ -#include #include +#include #include #include "test_api.hpp" + #define WASM_TEST_FAIL 1 static const char test1[] = "abc"; @@ -165,18 +166,18 @@ static const unsigned char test5_ok_ripe[] = { }; extern "C" { - uint32_t my_strlen(const char *str) { + uint32_t my_strlen( const char *str ) { uint32_t len = 0; while(str[len]) ++len; return len; } - bool my_memcmp(void *s1, void *s2, uint32_t n) + bool my_memcmp( void *s1, void *s2, uint32_t n ) { unsigned char *c1 = (unsigned char *)s1; unsigned char *c2 = (unsigned char *)s2; for (uint32_t i = 0; i < n; ++i) { - if (c1[i] != c2[i]) { + if ( c1[i] != c2[i] ) { return false; } } @@ -186,9 +187,9 @@ extern "C" { } struct sig_hash_key { - checksum256 hash; - public_key pk; - signature sig; + capi_checksum256 hash; + capi_public_key pk; + capi_signature sig; }; void test_crypto::test_recover_key_assert_true() { @@ -207,7 +208,7 @@ void test_crypto::test_recover_key_assert_false() { void test_crypto::test_recover_key() { sig_hash_key sh; read_action_data( (char*)&sh, sizeof(sh) ); - public_key pk; + capi_public_key pk; recover_key( &sh.hash, (const char*)&sh.sig, sizeof(sh.sig), pk.data, sizeof(pk) ); for ( uint32_t i=0; i < sizeof(pk); i++ ) if ( pk.data[i] != sh.pk.data[i] ) @@ -215,222 +216,207 @@ void test_crypto::test_recover_key() { } void test_crypto::test_sha1() { - checksum160 tmp; + eosio::checksum160 tmp; - sha1( (char *)test1, my_strlen(test1), &tmp ); - eosio_assert( my_memcmp((void *)test1_ok_1, &tmp, sizeof(checksum160)), "sha1 test1" ); + tmp = eosio::sha1( test1, my_strlen(test1) ); + eosio_assert( my_memcmp((void *)test1_ok_1, &tmp, sizeof(eosio::checksum160)), "sha1 test1" ); - sha1( (char *)test3, my_strlen(test3), &tmp ); - eosio_assert( my_memcmp((void *)test3_ok_1, &tmp, sizeof(checksum160)), "sha1 test3" ); + tmp = eosio::sha1( test3, my_strlen(test3) ); + eosio_assert( my_memcmp((void *)test3_ok_1, &tmp, sizeof(eosio::checksum160)), "sha1 test3" ); - sha1( (char *)test4, my_strlen(test4), &tmp ); - eosio_assert( my_memcmp((void *)test4_ok_1, &tmp, sizeof(checksum160)), "sha1 test4" ); + tmp = eosio::sha1( test4, my_strlen(test4) ); + eosio_assert( my_memcmp((void *)test4_ok_1, &tmp, sizeof(eosio::checksum160)), "sha1 test4" ); - sha1( (char *)test5, my_strlen(test5), &tmp ); - eosio_assert( my_memcmp((void *)test5_ok_1, &tmp, sizeof(checksum160)), "sha1 test5" ); + tmp = eosio::sha1( test5, my_strlen(test5) ); + eosio_assert( my_memcmp((void *)test5_ok_1, &tmp, sizeof(eosio::checksum160)), "sha1 test5" ); } void test_crypto::test_sha256() { + eosio::checksum256 tmp; - checksum256 tmp; - - sha256( (char *)test1, my_strlen(test1), &tmp ); - eosio_assert( my_memcmp((void *)test1_ok_256, &tmp, sizeof(checksum256)), "sha256 test1" ); + tmp = eosio::sha256( test1, my_strlen(test1) ); + eosio_assert( my_memcmp((void *)test1_ok_256, &tmp, sizeof(eosio::checksum256)), "sha256 test1" ); - sha256( (char *)test3, my_strlen(test3), &tmp ); - eosio_assert( my_memcmp((void *)test3_ok_256, &tmp, sizeof(checksum256)), "sha256 test3" ); + tmp = eosio::sha256( test3, my_strlen(test3) ); + eosio_assert( my_memcmp((void *)test3_ok_256, &tmp, sizeof(eosio::checksum256)), "sha256 test3" ); - sha256( (char *)test4, my_strlen(test4), &tmp ); - eosio_assert( my_memcmp((void *)test4_ok_256, &tmp, sizeof(checksum256)), "sha256 test4" ); + tmp = eosio::sha256( test4, my_strlen(test4) ); + eosio_assert( my_memcmp((void *)test4_ok_256, &tmp, sizeof(eosio::checksum256)), "sha256 test4" ); - sha256( (char *)test5, my_strlen(test5), &tmp ); - eosio_assert( my_memcmp((void *)test5_ok_256, &tmp, sizeof(checksum256)), "sha256 test5" ); + tmp = eosio::sha256( test5, my_strlen(test5) ); + eosio_assert( my_memcmp((void *)test5_ok_256, &tmp, sizeof(eosio::checksum256)), "sha256 test5" ); } void test_crypto::test_sha512() { + eosio::checksum512 tmp; - checksum512 tmp; + tmp = eosio::sha512( test1, my_strlen(test1) ); + eosio_assert( my_memcmp((void *)test1_ok_512, &tmp, sizeof(eosio::checksum512)), "sha512 test1" ); - sha512( (char *)test1, my_strlen(test1), &tmp ); - eosio_assert( my_memcmp((void *)test1_ok_512, &tmp, sizeof(checksum512)), "sha512 test1" ); + tmp = eosio::sha512( test3, my_strlen(test3) ); + eosio_assert( my_memcmp((void *)test3_ok_512, &tmp, sizeof(eosio::checksum512)), "sha512 test3" ); - sha512( (char *)test3, my_strlen(test3), &tmp ); - eosio_assert( my_memcmp((void *)test3_ok_512, &tmp, sizeof(checksum512)), "sha512 test3" ); + tmp = eosio::sha512( test4, my_strlen(test4) ); + eosio_assert( my_memcmp((void *)test4_ok_512, &tmp, sizeof(eosio::checksum512)), "sha512 test4" ); - sha512( (char *)test4, my_strlen(test4), &tmp ); - eosio_assert( my_memcmp((void *)test4_ok_512, &tmp, sizeof(checksum512)), "sha512 test4" ); - - sha512( (char *)test5, my_strlen(test5), &tmp ); - eosio_assert( my_memcmp((void *)test5_ok_512, &tmp, sizeof(checksum512)), "sha512 test5" ); + tmp = eosio::sha512( test5, my_strlen(test5) ); + eosio_assert( my_memcmp((void *)test5_ok_512, &tmp, sizeof(eosio::checksum512)), "sha512 test5" ); } void test_crypto::test_ripemd160() { + eosio::checksum160 tmp; - checksum160 tmp; - - ripemd160( (char *)test1, my_strlen(test1), &tmp ); - eosio_assert( my_memcmp((void *)test1_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test1" ); + tmp = eosio::ripemd160( test1, my_strlen(test1) ); + eosio_assert( my_memcmp((void *)test1_ok_ripe, &tmp, sizeof(eosio::checksum160)), "ripemd160 test1" ); - ripemd160( (char *)test3, my_strlen(test3), &tmp ); - eosio_assert( my_memcmp((void *)test3_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test3" ); + tmp = eosio::ripemd160( test3, my_strlen(test3) ); + eosio_assert( my_memcmp((void *)test3_ok_ripe, &tmp, sizeof(eosio::checksum160)), "ripemd160 test3" ); - ripemd160( (char *)test4, my_strlen(test4), &tmp ); - eosio_assert( my_memcmp((void *)test4_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test4" ); + tmp = eosio::ripemd160( test4, my_strlen(test4) ); + eosio_assert( my_memcmp((void *)test4_ok_ripe, &tmp, sizeof(eosio::checksum160)), "ripemd160 test4" ); - ripemd160( (char *)test5, my_strlen(test5), &tmp ); - eosio_assert( my_memcmp((void *)test5_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test5" ); + tmp = eosio::ripemd160( test5, my_strlen(test5) ); + eosio_assert( my_memcmp((void *)test5_ok_ripe, &tmp, sizeof(eosio::checksum160)), "ripemd160 test5" ); } void test_crypto::sha256_null() { - checksum256 tmp; - sha256(nullptr, 100, &tmp); - //eosio_assert(false, "should've thrown an error"); + eosio::checksum256 tmp; + tmp = eosio::sha256( nullptr, 100); + eosio_assert( false, "should've thrown an error" ); } void test_crypto::sha1_no_data() { + eosio::checksum160 tmp; - checksum160 tmp; - - sha1( (char *)test2, my_strlen(test2), &tmp ); - eosio_assert( my_memcmp((void *)test2_ok_1, &tmp, sizeof(checksum160)), "sha1 test2" ); + tmp = eosio::sha1( test2, my_strlen(test2) ); + eosio_assert( my_memcmp((void *)test2_ok_1, &tmp, sizeof(eosio::checksum160)), "sha1 test2" ); } void test_crypto::sha256_no_data() { + eosio::checksum256 tmp; - checksum256 tmp; - - sha256( (char *)test2, my_strlen(test2), &tmp ); - eosio_assert( my_memcmp((void *)test2_ok_256, &tmp, sizeof(checksum256)), "sha256 test2" ); + tmp = eosio::sha256( test2, my_strlen(test2) ); + eosio_assert( my_memcmp((void *)test2_ok_256, &tmp, sizeof(eosio::checksum256)), "sha256 test2" ); } void test_crypto::sha512_no_data() { + eosio::checksum512 tmp; - checksum512 tmp; - - sha512( (char *)test2, my_strlen(test2), &tmp ); - eosio_assert( my_memcmp((void *)test2_ok_512, &tmp, sizeof(checksum512)), "sha512 test2" ); + tmp = eosio::sha512( test2, my_strlen(test2) ); + eosio_assert( my_memcmp((void *)test2_ok_512, &tmp, sizeof(eosio::checksum512)), "sha512 test2" ); } void test_crypto::ripemd160_no_data() { + eosio::checksum160 tmp; - checksum160 tmp; - - ripemd160( (char *)test2, my_strlen(test2), &tmp ); - eosio_assert( my_memcmp((void *)test2_ok_ripe, &tmp, sizeof(checksum160)), "ripemd160 test2" ); + tmp = eosio::ripemd160( test2, my_strlen(test2) ); + eosio_assert( my_memcmp((void *)test2_ok_ripe, &tmp, sizeof(eosio::checksum160)), "ripemd160 test2" ); } void test_crypto::assert_sha256_false() { - - checksum256 tmp; + eosio::checksum256 tmp; - sha256( (char *)test1, my_strlen(test1), &tmp ); - tmp.hash[0] ^= (uint64_t)(-1); - assert_sha256( (char *)test1, my_strlen(test1), &tmp); + tmp = eosio::sha256( test1, my_strlen(test1) ); + tmp.data()[0] ^= (uint64_t)(-1); + assert_sha256( test1, my_strlen(test1), tmp ); - eosio_assert(false, "should have failed"); + eosio_assert( false, "should have failed" ); } void test_crypto::assert_sha256_true() { - - checksum256 tmp; + eosio::checksum256 tmp; - sha256( (char *)test1, my_strlen(test1), &tmp ); - assert_sha256( (char *)test1, my_strlen(test1), &tmp); + tmp = eosio::sha256( test1, my_strlen(test1) ); + assert_sha256( test1, my_strlen(test1), tmp ); - sha256( (char *)test3, my_strlen(test3), &tmp ); - assert_sha256( (char *)test3, my_strlen(test3), &tmp); + tmp = eosio::sha256( test3, my_strlen(test3) ); + assert_sha256( test3, my_strlen(test3), tmp ); - sha256( (char *)test4, my_strlen(test4), &tmp ); - assert_sha256( (char *)test4, my_strlen(test4), &tmp); + tmp = eosio::sha256( test4, my_strlen(test4) ); + assert_sha256( test4, my_strlen(test4), tmp ); - sha256( (char *)test5, my_strlen(test5), &tmp ); - assert_sha256( (char *)test5, my_strlen(test5), &tmp); + tmp = eosio::sha256( test5, my_strlen(test5) ); + assert_sha256( test5, my_strlen(test5), tmp ); } void test_crypto::assert_sha1_false() { - - checksum160 tmp; + eosio::checksum160 tmp; - sha1( (char *)test1, my_strlen(test1), &tmp ); - tmp.hash[0] ^= (uint64_t)(-1); - assert_sha1( (char *)test1, my_strlen(test1), &tmp); + tmp = eosio::sha1( test1, my_strlen(test1) ); + tmp.data()[0] ^= (uint64_t)(-1); + assert_sha1( test1, my_strlen(test1), tmp ); - eosio_assert(false, "should have failed"); + eosio_assert( false, "should have failed" ); } void test_crypto::assert_sha1_true() { - - checksum160 tmp; + eosio::checksum160 tmp; - sha1( (char *)test1, my_strlen(test1), &tmp ); - assert_sha1( (char *)test1, my_strlen(test1), &tmp); + tmp = eosio::sha1( test1, my_strlen(test1) ); + assert_sha1( test1, my_strlen(test1), tmp ); - sha1( (char *)test3, my_strlen(test3), &tmp ); - assert_sha1( (char *)test3, my_strlen(test3), &tmp); + tmp = eosio::sha1( test3, my_strlen(test3) ); + assert_sha1( test3, my_strlen(test3), tmp ); - sha1( (char *)test4, my_strlen(test4), &tmp ); - assert_sha1( (char *)test4, my_strlen(test4), &tmp); + tmp = eosio::sha1( test4, my_strlen(test4) ); + assert_sha1( test4, my_strlen(test4), tmp ); - sha1( (char *)test5, my_strlen(test5), &tmp ); - assert_sha1( (char *)test5, my_strlen(test5), &tmp); + tmp = eosio::sha1( test5, my_strlen(test5) ); + assert_sha1( test5, my_strlen(test5), tmp ); } -void test_crypto::assert_sha512_false() { - - checksum512 tmp; +void test_crypto::assert_sha512_false() { + eosio::checksum512 tmp; - sha512( (char *)test1, my_strlen(test1), &tmp ); - tmp.hash[0] ^= (uint64_t)(-1); - assert_sha512( (char *)test1, my_strlen(test1), &tmp); + tmp = eosio::sha512( test1, my_strlen(test1) ); + tmp.data()[0] ^= (uint64_t)(-1); + assert_sha512( test1, my_strlen(test1), tmp ); eosio_assert(false, "should have failed"); } void test_crypto::assert_sha512_true() { - - checksum512 tmp; + eosio::checksum512 tmp; - sha512( (char *)test1, my_strlen(test1), &tmp ); - assert_sha512( (char *)test1, my_strlen(test1), &tmp); + tmp = eosio::sha512( test1, my_strlen(test1) ); + assert_sha512( test1, my_strlen(test1), tmp ); - sha512( (char *)test3, my_strlen(test3), &tmp ); - assert_sha512( (char *)test3, my_strlen(test3), &tmp); + tmp = eosio::sha512( test3, my_strlen(test3) ); + assert_sha512( test3, my_strlen(test3), tmp ); - sha512( (char *)test4, my_strlen(test4), &tmp ); - assert_sha512( (char *)test4, my_strlen(test4), &tmp); + tmp = eosio::sha512( test4, my_strlen(test4) ); + assert_sha512( test4, my_strlen(test4), tmp ); - sha512( (char *)test5, my_strlen(test5), &tmp ); - assert_sha512( (char *)test5, my_strlen(test5), &tmp); + tmp = eosio::sha512( test5, my_strlen(test5) ); + assert_sha512( test5, my_strlen(test5), tmp ); } void test_crypto::assert_ripemd160_false() { - - checksum160 tmp; + eosio::checksum160 tmp; - ripemd160( (char *)test1, my_strlen(test1), &tmp ); - tmp.hash[0] ^= (uint64_t)(-1); - assert_ripemd160( (char *)test1, my_strlen(test1), &tmp); + tmp = eosio::ripemd160( test1, my_strlen(test1) ); + tmp.data()[0] ^= (uint64_t)(-1); + assert_ripemd160( test1, my_strlen(test1), tmp ); - eosio_assert(false, "should have failed"); + eosio_assert( false, "should have failed" ); } void test_crypto::assert_ripemd160_true() { - - checksum160 tmp; + eosio::checksum160 tmp; - ripemd160( (char *)test1, my_strlen(test1), &tmp ); - assert_ripemd160( (char *)test1, my_strlen(test1), &tmp); + tmp = eosio::ripemd160( test1, my_strlen(test1) ); + assert_ripemd160( test1, my_strlen(test1), tmp ); - ripemd160( (char *)test3, my_strlen(test3), &tmp ); - assert_ripemd160( (char *)test3, my_strlen(test3), &tmp); + tmp = eosio::ripemd160( test3, my_strlen(test3) ); + assert_ripemd160( test3, my_strlen(test3), tmp ); - ripemd160( (char *)test4, my_strlen(test4), &tmp ); - assert_ripemd160( (char *)test4, my_strlen(test4), &tmp); + tmp = eosio::ripemd160( test4, my_strlen(test4) ); + assert_ripemd160( test4, my_strlen(test4), tmp ); - ripemd160( (char *)test5, my_strlen(test5), &tmp ); - assert_ripemd160( (char *)test5, my_strlen(test5), &tmp); + tmp = eosio::ripemd160( test5, my_strlen(test5) ); + assert_ripemd160( test5, my_strlen(test5), tmp ); } diff --git a/unittests/test-contracts/test_api/test_datastream.cpp b/unittests/test-contracts/test_api/test_datastream.cpp new file mode 100644 index 00000000000..ca0e00982f6 --- /dev/null +++ b/unittests/test-contracts/test_api/test_datastream.cpp @@ -0,0 +1,91 @@ +/** + * @file action_test.cpp + * @copyright defined in eos/LICENSE.txt + */ +#include + +#include +#include + +#include "test_api.hpp" + +template +struct testtype { + static void run( const T &v, const char *errmsg = "" ) { + char buf[128]; + eosio::datastream ds( buf, sizeof(buf) ); + ds << v; + T v2; + ds.seekp(0); + ds >> v2; + eosio_assert ( v == v2, errmsg ); + } +}; + +template <> +struct testtype { + static void run( const double &v, const char *errmsg = "" ) { + char buf[128]; + eosio::datastream ds( buf, sizeof(buf) ); + ds << v; + double v2; + ds.seekp(0); + ds >> v2; + eosio_assert( std::abs(v - v2) < 1e-20, errmsg ); + } +}; + +template <> +struct testtype { + static void run( const float &v, const char *errmsg = "" ) { + char buf[128]; + eosio::datastream ds( buf, sizeof(buf) ); + ds << v; + float v2; + ds.seekp(0); + ds >> v2; + eosio_assert( std::abs(v - v2) < float(1e-10), errmsg ); + } +}; + +void test_datastream::test_basic() +{ + + testtype::run( true, "bool" ); + testtype::run( false, "bool" ); + testtype::run( -123, "int8" ); + testtype::run( 127, "uint8" ); + testtype::run( -12345, "int16" ); + testtype::run( 12345, "uint16" ); + testtype::run( -1234567890, "int32" ); + testtype::run( 3234567890u, "uint32" ); + testtype::run( (long long)0x8000000000000000ll, "int64" ); + testtype::run( 0x7fffffffffffffffull, "uint64" ); + testtype::run( 1.234f, "float" ); + testtype::run( 0.333333333333333333, "double" ); + + // this should generate compile error + //testtype::run((char *)0x12345678, "pointer"); + + struct Pair { + int a; + double d; + bool operator==( const Pair &p ) const { return a == p.a && std::abs(d - p.d) < 1e-20; } + }; + testtype::run({ 1, 1.23456}, "struct" ); + + struct StaticArray { + int a[2]; + bool operator==( const StaticArray &o ) const { return a[0] == o.a[0] && a[1] == o.a[1]; } + }; + testtype::run( {{10,20}}, "StaticArray" ); + + testtype::run( "hello", "string" ); + + testtype >::run( {10,20,30}, "vector" ); + testtype >::run( {}, "empty vector" ); + testtype >::run( {{10,20,30}}, "std::array" ); + testtype >::run( {{1,"apple"}, {2,"cat"}, {3,"panda"}}, "map" ); + testtype >::run( {1, "abc", 3.3333}, "tuple" ); +} + diff --git a/contracts/test_api/test_fixedpoint.cpp b/unittests/test-contracts/test_api/test_fixedpoint.cpp similarity index 62% rename from contracts/test_api/test_fixedpoint.cpp rename to unittests/test-contracts/test_api/test_fixedpoint.cpp index 3f7c0260786..cca3a9d42f2 100644 --- a/contracts/test_api/test_fixedpoint.cpp +++ b/unittests/test-contracts/test_api/test_fixedpoint.cpp @@ -1,5 +1,9 @@ -#include +/** + * @file action_test.cpp + * @copyright defined in eos/LICENSE.txt + */ #include +#include #include "test_api.hpp" @@ -10,8 +14,8 @@ void test_fixedpoint::create_instances() eosio::fixed_point128<18> a(12345667); eosio::fixed_point128<18> b(12345667); eosio::fixed_point128<16> c(12345667); - eosio_assert(b == a, "fixed_point128 instances comparison with same number of decimals"); - eosio_assert(c == a, "fixed_point128 instances with different number of decimals"); + eosio_assert( b == a, "fixed_point128 instances comparison with same number of decimals" ); + eosio_assert( c == a, "fixed_point128 instances with different number of decimals" ); } { @@ -19,8 +23,8 @@ void test_fixedpoint::create_instances() eosio::fixed_point64<5> a(12345667); eosio::fixed_point64<5> b(12345667); eosio::fixed_point64<5> c(12345667); - eosio_assert(b == a, "fixed_point64 instances comparison with same number of decimals"); - eosio_assert(c == a, "fixed_point64 instances with different number of decimals"); + eosio_assert( b == a, "fixed_point64 instances comparison with same number of decimals" ); + eosio_assert( c == a, "fixed_point64 instances with different number of decimals" ); } { @@ -28,8 +32,8 @@ void test_fixedpoint::create_instances() eosio::fixed_point32<18> a(12345667); eosio::fixed_point32<18> b(12345667); eosio::fixed_point32<16> c(12345667); - eosio_assert(b == a, "fixed_point32 instances comparison with same number of decimals"); - eosio_assert(c == a, "fixed_point32 instances with different number of decimals"); + eosio_assert( b == a, "fixed_point32 instances comparison with same number of decimals" ); + eosio_assert( c == a, "fixed_point32 instances with different number of decimals" ); } } @@ -41,7 +45,7 @@ void test_fixedpoint::test_addition() eosio::fixed_point32<0> b(100); eosio::fixed_point32<0> c = a + b; eosio::fixed_point32<0> d = 200; - eosio_assert(c == d, "fixed_point32 instances addition with zero decmimals"); + eosio_assert( c == d, "fixed_point32 instances addition with zero decmimals" ); } { // Various ways to create fixed_point64 @@ -49,7 +53,7 @@ void test_fixedpoint::test_addition() eosio::fixed_point64<0> b(100); eosio::fixed_point64<0> c = a + b; eosio::fixed_point64<0> d = 200; - eosio_assert(c == d, "fixed_point64 instances addition with zero decmimals"); + eosio_assert( c == d, "fixed_point64 instances addition with zero decmimals" ); } }; @@ -61,12 +65,12 @@ void test_fixedpoint::test_subtraction() eosio::fixed_point64<0> b(100); eosio::fixed_point64<0> c = a - b; eosio::fixed_point64<0> d = 0; - eosio_assert(c == d, "fixed_point64 instances subtraction with zero decmimals"); + eosio_assert( c == d, "fixed_point64 instances subtraction with zero decmimals" ); eosio::fixed_point64<0> a1(0); eosio::fixed_point64<0> c1 = a1 - b; eosio::fixed_point64<0> d1 = -100; - eosio_assert(c1 == d1, "fixed_point64 instances subtraction with zero decmimals"); + eosio_assert( c1 == d1, "fixed_point64 instances subtraction with zero decmimals" ); } { // Various ways to create fixed_point32 @@ -74,13 +78,13 @@ void test_fixedpoint::test_subtraction() eosio::fixed_point32<0> b(100); eosio::fixed_point32<0> c = a - b; eosio::fixed_point32<0> d = 0; - eosio_assert(c == d, "fixed_point32 instances subtraction with zero decmimals"); + eosio_assert( c == d, "fixed_point32 instances subtraction with zero decmimals" ); // Various ways to create fixed_point32 eosio::fixed_point32<0> a1(0); eosio::fixed_point32<0> c1 = a1 - b; eosio::fixed_point32<0> d1 = -100; - eosio_assert(c1 == d1, "fixed_point32 instances subtraction with zero decmimals"); + eosio_assert( c1 == d1, "fixed_point32 instances subtraction with zero decmimals" ); } }; @@ -93,7 +97,7 @@ void test_fixedpoint::test_multiplication() eosio::fixed_point64<0> b(200); eosio::fixed_point128<0> c = a * b; eosio::fixed_point128<0> d(200*100); - eosio_assert(c == d, "fixed_point64 instances multiplication result in fixed_point128"); + eosio_assert( c == d, "fixed_point64 instances multiplication result in fixed_point128" ); } { @@ -102,7 +106,7 @@ void test_fixedpoint::test_multiplication() eosio::fixed_point32<0> b(200); eosio::fixed_point64<0> c = a * b; eosio::fixed_point64<0> d(200*100); - eosio_assert(c == d, "fixed_point32 instances multiplication result in fixed_point64"); + eosio_assert( c == d, "fixed_point32 instances multiplication result in fixed_point64" ); } } @@ -116,9 +120,9 @@ void test_fixedpoint::test_division() eosio::fixed_point64<0> b((int64_t)rhs); eosio::fixed_point128<5> c = a / b; - eosio::fixed_point128<5> e = eosio::fixed_divide<5>(lhs, rhs); + eosio::fixed_point128<5> e = eosio::fixed_divide<5>( lhs, rhs ); print(e); - eosio_assert(c == e, "fixed_point64 instances division result from operator and function and compare in fixed_point128"); + eosio_assert( c == e, "fixed_point64 instances division result from operator and function and compare in fixed_point128" ); } @@ -130,8 +134,8 @@ void test_fixedpoint::test_division() eosio::fixed_point32<0> b((int32_t)rhs); eosio::fixed_point64<5> c = a / b; - eosio::fixed_point64<5> e = eosio::fixed_divide<5>(lhs, rhs); - eosio_assert(c == e, "fixed_point64 instances division result from operator and function and compare in fixed_point128"); + eosio::fixed_point64<5> e = eosio::fixed_divide<5>( lhs, rhs ); + eosio_assert( c == e, "fixed_point64 instances division result from operator and function and compare in fixed_point128" ); } } @@ -145,11 +149,10 @@ void test_fixedpoint::test_division_by_0() eosio::fixed_point64<0> a((int64_t)lhs); eosio::fixed_point64<0> b((int64_t)rhs); - eosio::fixed_point128<5> e = eosio::fixed_divide<5>(lhs, rhs); + eosio::fixed_point128<5> e = eosio::fixed_divide<5>( lhs, rhs ); // in order to get rid of unused parameter warning e = 0; - eosio_assert(false, "should've thrown an error"); + eosio_assert( false, "should've thrown an error" ); } - } diff --git a/contracts/test_api/test_permission.cpp b/unittests/test-contracts/test_api/test_permission.cpp similarity index 55% rename from contracts/test_api/test_permission.cpp rename to unittests/test-contracts/test_api/test_permission.cpp index f26c120a0a1..df638812fed 100644 --- a/contracts/test_api/test_permission.cpp +++ b/unittests/test-contracts/test_api/test_permission.cpp @@ -2,28 +2,29 @@ * @file action_test.cpp * @copyright defined in eos/LICENSE */ -#include -#include +#include +#include +#include +#include #include +#include #include -#include #include -#include #include "test_api.hpp" -#include + struct check_auth_msg { - account_name account; - permission_name permission; - std::vector pubkeys; + eosio::name account; + eosio::name permission; + std::vector pubkeys; EOSLIB_SERIALIZE( check_auth_msg, (account)(permission)(pubkeys) ) }; -void test_permission::check_authorization(uint64_t receiver, uint64_t code, uint64_t action) { +void test_permission::check_authorization( uint64_t receiver, uint64_t code, uint64_t action ) { (void)code; (void)action; using namespace eosio; @@ -31,49 +32,45 @@ void test_permission::check_authorization(uint64_t receiver, uint64_t code, uint auto self = receiver; auto params = unpack_action_data(); auto packed_pubkeys = pack(params.pubkeys); - int64_t res64 = ::check_permission_authorization( params.account, - params.permission, + int64_t res64 = ::check_permission_authorization( params.account.value, + params.permission.value, packed_pubkeys.data(), packed_pubkeys.size(), (const char*)0, 0, - static_cast(std::numeric_limits::max()) + static_cast( std::numeric_limits::max() ) ); - /* - uint64_t res64 = (uint64_t)::check_authorization( params.account, params.permission, - (char*)params.pubkeys.data(), params.pubkeys.size()*sizeof(public_key) ); - */ - auto itr = db_lowerbound_i64(self, self, self, 1); + auto itr = db_lowerbound_i64( self, self, self, 1 ); if(itr == -1) { - db_store_i64(self, self, self, 1, &res64, sizeof(int64_t)); + db_store_i64( self, self, self, 1, &res64, sizeof(int64_t) ); } else { - db_update_i64(itr, self, &res64, sizeof(int64_t)); + db_update_i64( itr, self, &res64, sizeof(int64_t) ); } } struct test_permission_last_used_msg { - account_name account; - permission_name permission; - int64_t last_used_time; + eosio::name account; + eosio::name permission; + int64_t last_used_time; EOSLIB_SERIALIZE( test_permission_last_used_msg, (account)(permission)(last_used_time) ) }; -void test_permission::test_permission_last_used(uint64_t /* receiver */, uint64_t code, uint64_t action) { +void test_permission::test_permission_last_used( uint64_t /* receiver */, uint64_t code, uint64_t action ) { (void)code; (void)action; using namespace eosio; auto params = unpack_action_data(); - eosio_assert( get_permission_last_used(params.account, params.permission) == params.last_used_time, "unexpected last used permission time" ); + eosio_assert( get_permission_last_used(params.account.value, params.permission.value) == params.last_used_time, "unexpected last used permission time" ); } -void test_permission::test_account_creation_time(uint64_t /* receiver */, uint64_t code, uint64_t action) { +void test_permission::test_account_creation_time( uint64_t /* receiver */, uint64_t code, uint64_t action ) { (void)code; (void)action; using namespace eosio; auto params = unpack_action_data(); - eosio_assert( get_account_creation_time(params.account) == params.last_used_time, "unexpected account creation time" ); + eosio_assert( get_account_creation_time(params.account.value) == params.last_used_time, "unexpected account creation time" ); } diff --git a/contracts/test_api/test_print.cpp b/unittests/test-contracts/test_api/test_print.cpp similarity index 73% rename from contracts/test_api/test_print.cpp rename to unittests/test-contracts/test_api/test_print.cpp index a042ff6f57a..203a3b65997 100644 --- a/contracts/test_api/test_print.cpp +++ b/unittests/test-contracts/test_api/test_print.cpp @@ -6,8 +6,6 @@ #include "test_api.hpp" -//using namespace eosio; - void test_print::test_prints_l() { char ab[] = { 'a', 'b' }; const char test[] = "test"; @@ -66,18 +64,28 @@ void test_print::test_printui128() { } void test_print::test_printn() { - printn(N(abcde)); - printn(N(abBde)); - printn(N(1q1q1qAA)); - printn(N()); - printn(N(AAAAAA)); - printn(N(abcdefghijk)); - printn(N(abcdefghijkl)); - printn(N(abcdefghijkl1)); - printn(N(abcdefghijkl12)); - printn(N(abcdefghijkl123)); + printn(eosio::name{"1"}.value); + printn(eosio::name{"5"}.value); + printn(eosio::name{"a"}.value); + printn(eosio::name{"z"}.value); + + printn(eosio::name{"abc"}.value); + printn(eosio::name{"123"}.value); + + printn(eosio::name{"abc.123"}.value); + printn(eosio::name{"123.abc"}.value); + + printn(eosio::name{"12345abcdefgj"}.value); + printn(eosio::name{"ijklmnopqrstj"}.value); + printn(eosio::name{"vwxyz.12345aj"}.value); + + printn(eosio::name{"111111111111j"}.value); + printn(eosio::name{"555555555555j"}.value); + printn(eosio::name{"aaaaaaaaaaaaj"}.value); + printn(eosio::name{"zzzzzzzzzzzzj"}.value); } + void test_print::test_printsf() { float x = 1.0f / 2.0f; float y = 5.0f * -0.75f; @@ -115,8 +123,8 @@ void test_print::test_printqf() { } void test_print::test_print_simple() { - std::string const cvalue = "cvalue"; + const std::string cvalue = "cvalue"; eosio::print(cvalue); std::string value = "value"; - eosio::print(value); + eosio::print(std::move(value)); } diff --git a/unittests/test-contracts/test_api/test_transaction.cpp b/unittests/test-contracts/test_api/test_transaction.cpp new file mode 100644 index 00000000000..857daa36b63 --- /dev/null +++ b/unittests/test-contracts/test_api/test_transaction.cpp @@ -0,0 +1,356 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include +#include +#include + +#include "test_api.hpp" + +#pragma pack(push, 1) +template +struct test_action_action { + static eosio::name get_account() { + return eosio::name{ACCOUNT}; + } + + static eosio::name get_name() { + return eosio::name{NAME}; + } + + std::vector data; + + template + friend DataStream& operator<< ( DataStream& ds, const test_action_action& a ) { + for ( auto c : a.data ) + ds << c; + return ds; + } +}; + + +template +struct test_dummy_action { + static eosio::name get_account() { + return eosio::name{ACCOUNT}; + } + + static eosio::name get_name() { + return eosio::name{NAME}; + } + char a; + unsigned long long b; + int32_t c; + + template + friend DataStream& operator<< ( DataStream& ds, const test_dummy_action& da ) { + ds << da.a; + ds << da.b; + ds << da.c; + return ds; + } + + template + friend DataStream& operator>> ( DataStream& ds, test_dummy_action& da ) { + ds >> da.a; + ds >> da.b; + ds >> da.c; + return ds; + } +}; +#pragma pack(pop) + +void copy_data( char* data, size_t data_len, std::vector& data_out ) { + for (unsigned int i=0; i < data_len; i++) + data_out.push_back(data[i]); +} + +void test_transaction::send_action() { + using namespace eosio; + test_dummy_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action_normal" )> test_action = + { DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C }; + + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION( "test_action", "read_action_normal" )}, test_action ); + + act.send(); +} + +void test_transaction::send_action_empty() { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "assert_true" )> test_action; + + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION( "test_action", "assert_true" )}, test_action ); + + act.send(); +} + +/** + * cause failure due to a large action payload + */ +void test_transaction::send_action_large() { + using namespace eosio; + static char large_message[8 * 1024]; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action_normal" )> test_action; + copy_data( large_message, 8*1024, test_action.data ); + + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action_normal")}, test_action ); + + act.send(); + eosio_assert( false, "send_message_large() should've thrown an error" ); +} + +/** + * cause failure due recursive loop + */ +void test_transaction::send_action_recurse() { + using namespace eosio; + char buffer[1024]; + read_action_data( buffer, 1024 ); + + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_transaction", "send_action_recurse" )> test_action; + copy_data( buffer, 1024, test_action.data ); + + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION( "test_transaction", "send_action_recurse" )}, test_action ); + + act.send(); +} + +/** + * cause failure due to inline TX failure + */ +void test_transaction::send_action_inline_fail() { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "assert_false" )> test_action; + + std::vector permissions = { {"testapi"_n, "active"_n} }; + action act( permissions, name{"testapi"}, name{WASM_TEST_ACTION( "test_action", "assert_false" )}, test_action ); + + act.send(); +} + +void test_transaction::test_tapos_block_prefix() { + using namespace eosio; + int tbp; + read_action_data( (char*)&tbp, sizeof(int) ); + eosio_assert( tbp == tapos_block_prefix(), "tapos_block_prefix does not match" ); +} + +void test_transaction::test_tapos_block_num() { + using namespace eosio; + int tbn; + read_action_data( (char*)&tbn, sizeof(int) ); + eosio_assert( tbn == tapos_block_num(), "tapos_block_num does not match" ); +} + +void test_transaction::test_read_transaction() { + using namespace eosio; + checksum256 h; + auto size = transaction_size(); + char buf[size]; + uint32_t read = read_transaction( buf, size ); + eosio_assert( size == read, "read_transaction failed"); + h = eosio::sha256(buf, read); + print(h); +} + +void test_transaction::test_transaction_size() { + using namespace eosio; + uint32_t trans_size = 0; + read_action_data( (char*)&trans_size, sizeof(uint32_t) ); + print( "size: ", transaction_size() ); + eosio_assert( trans_size == transaction_size(), "transaction size does not match" ); +} + +void test_transaction::send_transaction(uint64_t receiver, uint64_t, uint64_t) { + using namespace eosio; + dummy_action payload = { DUMMY_ACTION_DEFAULT_A, DUMMY_ACTION_DEFAULT_B, DUMMY_ACTION_DEFAULT_C }; + + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action_normal" )> test_action; + copy_data( (char*)&payload, sizeof(dummy_action), test_action.data ); + + auto trx = transaction(); + std::vector permissions = { {"testapi"_n, "active"_n} }; + + trx.actions.emplace_back(permissions, name{"testapi"}, name{WASM_TEST_ACTION( "test_action", "read_action_normal" )}, test_action); + trx.send( 0, name{receiver} ); +} + +void test_transaction::send_action_sender( uint64_t receiver, uint64_t, uint64_t ) { + using namespace eosio; + uint64_t cur_send; + read_action_data( &cur_send, sizeof(name) ); + + auto trx = transaction(); + std::vector permissions = { {"testapi"_n, "active"_n} }; + + trx.actions.emplace_back(permissions, name{"testapi"}, name{WASM_TEST_ACTION( "test_action", "test_current_sender" )}, &cur_send); + trx.send( 0, name{receiver} ); +} + +void test_transaction::send_transaction_empty( uint64_t receiver, uint64_t, uint64_t ) { + using namespace eosio; + auto trx = transaction(); + trx.send( 0, name{receiver} ); + + eosio_assert( false, "send_transaction_empty() should've thrown an error" ); +} + +void test_transaction::send_transaction_trigger_error_handler( uint64_t receiver, uint64_t, uint64_t ) { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "assert_false" )> test_action; + + auto trx = transaction(); + std::vector permissions = { {"testapi"_n, "active"_n} }; + + trx.actions.emplace_back( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "assert_false")}, test_action ); + trx.send(0, name{receiver}); +} + +void test_transaction::assert_false_error_handler( const eosio::transaction& dtrx ) { + eosio_assert( dtrx.actions.size() == 1, "transaction should only have one action" ); + eosio_assert( dtrx.actions[0].account == "testapi"_n, "transaction has wrong code" ); + eosio_assert( dtrx.actions[0].name.value == WASM_TEST_ACTION("test_action", "assert_false"), "transaction has wrong name" ); + eosio_assert( dtrx.actions[0].authorization.size() == 1, "action should only have one authorization" ); + eosio_assert( dtrx.actions[0].authorization[0].actor == "testapi"_n, "action's authorization has wrong actor" ); + eosio_assert( dtrx.actions[0].authorization[0].permission == "active"_n, "action's authorization has wrong permission" ); +} + +/** + * cause failure due to a large transaction size + */ +void test_transaction::send_transaction_large( uint64_t receiver, uint64_t, uint64_t ) { + using namespace eosio; + auto trx = transaction(); + std::vector permissions = { {"testapi"_n, "active"_n} }; + for (int i = 0; i < 32; i ++) { + char large_message[1024]; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_action", "read_action_normal" )> test_action; + copy_data( large_message, 1024, test_action.data ); + trx.actions.emplace_back( permissions, name{"testapi"}, name{WASM_TEST_ACTION("test_action", "read_action_normal")}, test_action ); + } + + trx.send( 0, name{receiver} ); + + eosio_assert( false, "send_transaction_large() should've thrown an error" ); +} + +/** + * deferred transaction + */ +void test_transaction::deferred_print() { + eosio::print("deferred executed\n"); +} + +void test_transaction::send_deferred_transaction( uint64_t receiver, uint64_t, uint64_t ) { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_transaction", "deferred_print" )> test_action; + + auto trx = transaction(); + std::vector permissions = { {"testapi"_n, "active"_n} }; + + trx.actions.emplace_back( permissions, name{"testapi"}, name{ WASM_TEST_ACTION("test_transaction", "deferred_print" )}, test_action ); + trx.delay_sec = 2; + trx.send( 0xffffffffffffffff, name{receiver} ); +} + +void test_transaction::send_deferred_transaction_replace( uint64_t receiver, uint64_t, uint64_t ) { + using namespace eosio; + test_action_action<"testapi"_n.value, WASM_TEST_ACTION( "test_transaction", "deferred_print" )> test_action; + + auto trx = transaction(); + std::vector permissions = { {"testapi"_n, "active"_n} }; + + trx.actions.emplace_back( permissions, name{"testapi"}, name{WASM_TEST_ACTION( "test_transaction", "deferred_print" )}, test_action ); + trx.delay_sec = 2; + trx.send( 0xffffffffffffffff, name{receiver}, true ); +} + +void test_transaction::send_deferred_tx_with_dtt_action() { + using namespace eosio; + dtt_action dtt_act; + read_action_data( &dtt_act, action_data_size() ); + + action deferred_act; + deferred_act.account = name{dtt_act.deferred_account}; + deferred_act.name = name{dtt_act.deferred_action}; + deferred_act.authorization = std::vector{ {"testapi"_n, name{dtt_act.permission_name}} }; + + auto trx = transaction(); + trx.actions.emplace_back(deferred_act); + trx.delay_sec = dtt_act.delay_sec; + cancel_deferred( 0xffffffffffffffff ); // TODO: Remove this line after fixing deferred trx replacement RAM bug + trx.send( 0xffffffffffffffff, name{dtt_act.payer}, true ); +} + + +void test_transaction::cancel_deferred_transaction_success() { + using namespace eosio; + auto r = cancel_deferred( 0xffffffffffffffff ); //use the same id (0) as in send_deferred_transaction + eosio_assert( (bool)r, "transaction was not found" ); +} + +void test_transaction::cancel_deferred_transaction_not_found() { + using namespace eosio; + auto r = cancel_deferred( 0xffffffffffffffff ); //use the same id (0) as in send_deferred_transaction + eosio_assert( !r, "transaction was canceled, whild should not be found" ); +} + +void test_transaction::send_cf_action() { + using namespace eosio; + action act( std::vector{}, "dummy"_n, "event1"_n, std::vector{} ); + act.send_context_free(); +} + +void test_transaction::send_cf_action_fail() { + using namespace eosio; + action act( std::vector{{"dummy"_n, "active"_n}}, "dummy"_n, "event1"_n, std::vector{} ); + act.send_context_free(); + eosio_assert( false, "send_cfa_action_fail() should've thrown an error" ); +} + +void test_transaction::stateful_api() { + char buf[4] = {1}; + db_store_i64( eosio::name{"testtrans"}.value, eosio::name{"table"}.value, eosio::name{"testtrans"}.value, 0, buf, 4 ); +} + +void test_transaction::context_free_api() { + char buf[128] = {0}; + get_context_free_data( 0, buf, sizeof(buf) ); +} + +extern "C" { int is_feature_active(int64_t); } +void test_transaction::new_feature() { + eosio_assert( false == is_feature_active("newfeature"_n.value), "we should not have new features unless hardfork" ); +} + +extern "C" { void activate_feature(int64_t);} +void test_transaction::active_new_feature() { + activate_feature("newfeature"_n.value); +} + +void test_transaction::repeat_deferred_transaction( uint64_t receiver, uint64_t code, uint64_t action ) { + using namespace eosio; + + uint128_t sender_id = 0; + + uint32_t payload = unpack_action_data(); + print("repeat_deferred_transaction called: payload = ", payload); + + bool res = cancel_deferred( sender_id ); + + print("\nrepeat_deferred_transaction cancelled trx with sender_id = ", sender_id, ", result is ", res); + + if( payload == 0 ) return; + + --payload; + transaction trx; + std::vector permissions = { {name{receiver}, "active"_n} }; + + trx.actions.emplace_back( permissions, name{code}, name{action}, payload ); + trx.send( sender_id, eosio::name{receiver} ); +} diff --git a/unittests/test-contracts/test_api/test_types.cpp b/unittests/test-contracts/test_api/test_types.cpp new file mode 100644 index 00000000000..a74026c33fc --- /dev/null +++ b/unittests/test-contracts/test_api/test_types.cpp @@ -0,0 +1,77 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include + +#include "test_api.hpp" + +void test_types::types_size() { + + eosio_assert( sizeof(int64_t) == 8, "int64_t size != 8" ); + eosio_assert( sizeof(uint64_t) == 8, "uint64_t size != 8" ); + eosio_assert( sizeof(uint32_t) == 4, "uint32_t size != 4" ); + eosio_assert( sizeof(int32_t) == 4, "int32_t size != 4" ); + eosio_assert( sizeof(uint128_t) == 16, "uint128_t size != 16"); + eosio_assert( sizeof(int128_t) == 16, "int128_t size != 16" ); + eosio_assert( sizeof(uint8_t) == 1, "uint8_t size != 1" ); + + eosio_assert( sizeof(eosio::name) == 8, "name size != 8"); +} + +void test_types::char_to_symbol() { + + eosio_assert( eosio::name::char_to_value('1') == 1, "eosio::char_to_symbol('1') != 1" ); + eosio_assert( eosio::name::char_to_value('2') == 2, "eosio::char_to_symbol('2') != 2" ); + eosio_assert( eosio::name::char_to_value('3') == 3, "eosio::char_to_symbol('3') != 3" ); + eosio_assert( eosio::name::char_to_value('4') == 4, "eosio::char_to_symbol('4') != 4" ); + eosio_assert( eosio::name::char_to_value('5') == 5, "eosio::char_to_symbol('5') != 5" ); + eosio_assert( eosio::name::char_to_value('a') == 6, "eosio::char_to_symbol('a') != 6" ); + eosio_assert( eosio::name::char_to_value('b') == 7, "eosio::char_to_symbol('b') != 7" ); + eosio_assert( eosio::name::char_to_value('c') == 8, "eosio::char_to_symbol('c') != 8" ); + eosio_assert( eosio::name::char_to_value('d') == 9, "eosio::char_to_symbol('d') != 9" ); + eosio_assert( eosio::name::char_to_value('e') == 10, "eosio::char_to_symbol('e') != 10" ); + eosio_assert( eosio::name::char_to_value('f') == 11, "eosio::char_to_symbol('f') != 11" ); + eosio_assert( eosio::name::char_to_value('g') == 12, "eosio::char_to_symbol('g') != 12" ); + eosio_assert( eosio::name::char_to_value('h') == 13, "eosio::char_to_symbol('h') != 13" ); + eosio_assert( eosio::name::char_to_value('i') == 14, "eosio::char_to_symbol('i') != 14" ); + eosio_assert( eosio::name::char_to_value('j') == 15, "eosio::char_to_symbol('j') != 15" ); + eosio_assert( eosio::name::char_to_value('k') == 16, "eosio::char_to_symbol('k') != 16" ); + eosio_assert( eosio::name::char_to_value('l') == 17, "eosio::char_to_symbol('l') != 17" ); + eosio_assert( eosio::name::char_to_value('m') == 18, "eosio::char_to_symbol('m') != 18" ); + eosio_assert( eosio::name::char_to_value('n') == 19, "eosio::char_to_symbol('n') != 19" ); + eosio_assert( eosio::name::char_to_value('o') == 20, "eosio::char_to_symbol('o') != 20" ); + eosio_assert( eosio::name::char_to_value('p') == 21, "eosio::char_to_symbol('p') != 21" ); + eosio_assert( eosio::name::char_to_value('q') == 22, "eosio::char_to_symbol('q') != 22" ); + eosio_assert( eosio::name::char_to_value('r') == 23, "eosio::char_to_symbol('r') != 23" ); + eosio_assert( eosio::name::char_to_value('s') == 24, "eosio::char_to_symbol('s') != 24" ); + eosio_assert( eosio::name::char_to_value('t') == 25, "eosio::char_to_symbol('t') != 25" ); + eosio_assert( eosio::name::char_to_value('u') == 26, "eosio::char_to_symbol('u') != 26" ); + eosio_assert( eosio::name::char_to_value('v') == 27, "eosio::char_to_symbol('v') != 27" ); + eosio_assert( eosio::name::char_to_value('w') == 28, "eosio::char_to_symbol('w') != 28" ); + eosio_assert( eosio::name::char_to_value('x') == 29, "eosio::char_to_symbol('x') != 29" ); + eosio_assert( eosio::name::char_to_value('y') == 30, "eosio::char_to_symbol('y') != 30" ); + eosio_assert( eosio::name::char_to_value('z') == 31, "eosio::char_to_symbol('z') != 31" ); + + for(unsigned char i = 0; i<255; i++) { + if( (i >= 'a' && i <= 'z') || (i >= '1' || i <= '5') ) continue; + eosio_assert( eosio::name::char_to_value((char)i) == 0, "eosio::char_to_symbol() != 0" ); + } +} + +void test_types::string_to_name() { + return; + eosio_assert( eosio::name("a") == "a"_n, "eosio::string_to_name(a)" ); + eosio_assert( eosio::name("ba") == "ba"_n, "eosio::string_to_name(ba)" ); + eosio_assert( eosio::name("cba") == "cba"_n, "eosio::string_to_name(cba)" ); + eosio_assert( eosio::name("dcba") == "dcba"_n, "eosio::string_to_name(dcba)" ); + eosio_assert( eosio::name("edcba") == "edcba"_n, "eosio::string_to_name(edcba)" ); + eosio_assert( eosio::name("fedcba") == "fedcba"_n, "eosio::string_to_name(fedcba)" ); + eosio_assert( eosio::name("gfedcba") == "gfedcba"_n, "eosio::string_to_name(gfedcba)" ); + eosio_assert( eosio::name("hgfedcba") == "hgfedcba"_n, "eosio::string_to_name(hgfedcba)" ); + eosio_assert( eosio::name("ihgfedcba") == "ihgfedcba"_n, "eosio::string_to_name(ihgfedcba)" ); + eosio_assert( eosio::name("jihgfedcba") == "jihgfedcba"_n, "eosio::string_to_name(jihgfedcba)" ); + eosio_assert( eosio::name("kjihgfedcba") == "kjihgfedcba"_n, "eosio::string_to_name(kjihgfedcba)" ); + eosio_assert( eosio::name("lkjihgfedcba") == "lkjihgfedcba"_n, "eosio::string_to_name(lkjihgfedcba)" ); + eosio_assert( eosio::name("mlkjihgfedcba") == "mlkjihgfedcba"_n, "eosio::string_to_name(mlkjihgfedcba)" ); +} diff --git a/unittests/test-contracts/test_api_db/CMakeLists.txt b/unittests/test-contracts/test_api_db/CMakeLists.txt new file mode 100644 index 00000000000..1cc38e3c1b7 --- /dev/null +++ b/unittests/test-contracts/test_api_db/CMakeLists.txt @@ -0,0 +1,5 @@ +if( ${eosio.cdt_FOUND} ) + add_executable( test_api_db test_api_db.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test_api_db.wasm ${CMAKE_CURRENT_BINARY_DIR}/test_api_db.wasm COPYONLY ) +endif() diff --git a/unittests/test-contracts/test_api_db/test_api_db.cpp b/unittests/test-contracts/test_api_db/test_api_db.cpp new file mode 100644 index 00000000000..b50a05e71cb --- /dev/null +++ b/unittests/test-contracts/test_api_db/test_api_db.cpp @@ -0,0 +1,28 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include + +#include "../test_api/test_api.hpp" +#include "test_db.cpp" + +extern "C" { + void apply( uint64_t receiver, uint64_t code, uint64_t action ) { + require_auth(code); + WASM_TEST_HANDLER_EX( test_db, primary_i64_general ); + WASM_TEST_HANDLER_EX( test_db, primary_i64_lowerbound ); + WASM_TEST_HANDLER_EX( test_db, primary_i64_upperbound ); + WASM_TEST_HANDLER_EX( test_db, idx64_general ); + WASM_TEST_HANDLER_EX( test_db, idx64_lowerbound ); + WASM_TEST_HANDLER_EX( test_db, idx64_upperbound ); + WASM_TEST_HANDLER_EX( test_db, test_invalid_access ); + WASM_TEST_HANDLER_EX( test_db, idx_double_nan_create_fail ); + WASM_TEST_HANDLER_EX( test_db, idx_double_nan_modify_fail ); + WASM_TEST_HANDLER_EX( test_db, idx_double_nan_lookup_fail ); + WASM_TEST_HANDLER_EX( test_db, misaligned_secondary_key256_tests ); + + //unhandled test call + eosio_assert( false, "Unknown Test" ); + } +} diff --git a/unittests/test-contracts/test_api_db/test_api_db.wasm b/unittests/test-contracts/test_api_db/test_api_db.wasm new file mode 100755 index 00000000000..83d6591c150 Binary files /dev/null and b/unittests/test-contracts/test_api_db/test_api_db.wasm differ diff --git a/unittests/test-contracts/test_api_db/test_db.cpp b/unittests/test-contracts/test_api_db/test_db.cpp new file mode 100644 index 00000000000..618bc40793d --- /dev/null +++ b/unittests/test-contracts/test_api_db/test_db.cpp @@ -0,0 +1,556 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include +#include +#include +#include +#include +#include +#include + +#include "../test_api/test_api.hpp" + +int primary[11] = { 0,1,2,3,4,5,6,7,8,9,10 }; +int secondary[11] = { 7,0,1,3,6,9,10,2,4,5,8 }; +int tertiary[11] = { 0,10,1,2,4,3,5,6,7,8,9 }; + +int primary_lb[11] = { 0,0,0,3,3,3,6,7,7,9,9 }; +int secondary_lb[11] = { 0,0,10,0,10,10,0,7,8,0,10 }; +int tertiary_lb[11] = { 0,1,2,3,2,5,6,7,8,9,0 }; + +int primary_ub[11] = { 3,3,3,6,6,6,7,9,9,-1,-1 }; +int secondary_ub[11] = { 10,10,8,10,8,8,10,0,-1,10,8 }; +int tertiary_ub[11] = { 1,2,3,5,3,6,7,8,9,-1,1 }; + +#pragma pack(push, 1) +struct test_model { + eosio::name name; + unsigned char age; + uint64_t phone; +}; + +struct test_model_v2 : test_model { + test_model_v2() : new_field(0) {} + uint64_t new_field; +}; + +struct test_model_v3 : test_model_v2 { + uint64_t another_field; +}; + +struct TestModel128x2 { + uint128_t number; + uint128_t price; + uint64_t extra; + uint64_t table_name; +}; + +struct TestModel128x2_V2 : TestModel128x2 { + uint64_t new_field; +}; + +struct TestModel3xi64 { + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t table; +}; + +struct TestModel3xi64_V2 : TestModel3xi64 { + uint64_t new_field; +}; + +#pragma pack(pop) + +#define STRLEN(s) my_strlen(s) + +extern "C" { + void my_memset( void *vptr, unsigned char val, unsigned int size ) { + char *ptr = (char *)vptr; + while(size--) { *(ptr++)=(char)val; } + } + uint32_t my_strlen( const char *str ) { + uint32_t len = 0; + while(str[len]) ++len; + return len; + } + bool my_memcmp( void *s1, void *s2, uint32_t n ) { + unsigned char *c1 = (unsigned char*)s1; + unsigned char *c2 = (unsigned char*)s2; + for ( uint32_t i = 0; i < n; i++ ) { + if (c1[i] != c2[i]) { + return false; + } + } + return true; + } +} + +void test_db::primary_i64_general( uint64_t receiver, uint64_t code, uint64_t action ) +{ + (void)code; (void)action; + auto table1 = "table1"_n.value; + + int alice_itr = db_store_i64( receiver, table1, receiver, "alice"_n.value, "alice's info", strlen("alice's info") ); + db_store_i64( receiver, table1, receiver, "bob"_n.value, "bob's info", strlen("bob's info") ); + db_store_i64( receiver, table1, receiver, "charlie"_n.value, "charlie's info", strlen("charlies's info") ); + db_store_i64( receiver, table1, receiver, "allyson"_n.value, "allyson's info", strlen("allyson's info") ); + + + // find + { + uint64_t prim = 0; + int itr_next = db_next_i64( alice_itr, &prim ); + int itr_next_expected = db_find_i64( receiver, receiver, table1, "allyson"_n.value ); + eosio_assert( itr_next == itr_next_expected && prim == "allyson"_n.value, "primary_i64_general - db_find_i64" ); + itr_next = db_next_i64( itr_next, &prim ); + itr_next_expected = db_find_i64( receiver, receiver, table1, "bob"_n.value ); + eosio_assert( itr_next == itr_next_expected && prim == "bob"_n.value, "primary_i64_general - db_next_i64" ); + } + + // next + { + int charlie_itr = db_find_i64( receiver, receiver, table1, "charlie"_n.value ); + // nothing after charlie + uint64_t prim = 0; + int end_itr = db_next_i64( charlie_itr, &prim ); + eosio_assert( end_itr < 0, "primary_i64_general - db_next_i64" ); + // prim didn't change + eosio_assert( prim == 0, "primary_i64_general - db_next_i64" ); + } + + // previous + { + int charlie_itr = db_find_i64( receiver, receiver, table1, "charlie"_n.value ); + uint64_t prim = 0; + int itr_prev = db_previous_i64( charlie_itr, &prim ); + int itr_prev_expected = db_find_i64( receiver, receiver, table1, "bob"_n.value ); + eosio_assert( itr_prev == itr_prev_expected && prim == "bob"_n.value, "primary_i64_general - db_previous_i64" ); + + itr_prev = db_previous_i64( itr_prev, &prim ); + itr_prev_expected = db_find_i64( receiver, receiver, table1, "allyson"_n.value ); + eosio_assert( itr_prev == itr_prev_expected && prim == "allyson"_n.value, "primary_i64_general - db_previous_i64" ); + + itr_prev = db_previous_i64( itr_prev, &prim ); + itr_prev_expected = db_find_i64( receiver, receiver, table1, "alice"_n.value ); + eosio_assert( itr_prev == itr_prev_expected && prim == "alice"_n.value, "primary_i64_general - db_previous_i64" ); + + itr_prev = db_previous_i64( itr_prev, &prim ); + eosio_assert( itr_prev < 0 && prim == "alice"_n.value, "primary_i64_general - db_previous_i64" ); + } + + // remove + { + int itr = db_find_i64( receiver, receiver, table1, "alice"_n.value ); + eosio_assert( itr >= 0, "primary_i64_general - db_find_i64" ); + db_remove_i64( itr ); + itr = db_find_i64( receiver, receiver, table1, "alice"_n.value ); + eosio_assert( itr < 0, "primary_i64_general - db_find_i64" ); + } + + // get + { + int itr = db_find_i64( receiver, receiver, table1, "bob"_n.value ); + eosio_assert( itr >= 0, "" ); + uint32_t buffer_len = 5; + char value[50]; + auto len = db_get_i64( itr, value, buffer_len ); + value[buffer_len] = '\0'; + std::string s(value); + eosio_assert( uint32_t(len) == buffer_len, "primary_i64_general - db_get_i64" ); + eosio_assert( s == "bob's", "primary_i64_general - db_get_i64 - 5" ); + + buffer_len = 20; + len = db_get_i64( itr, value, 0 ); + len = db_get_i64( itr, value, (uint32_t)len ); + value[len] = '\0'; + std::string sfull(value); + eosio_assert( sfull == "bob's info", "primary_i64_general - db_get_i64 - full" ); + } + + // update + { + int itr = db_find_i64( receiver, receiver, table1, "bob"_n.value ); + eosio_assert( itr >= 0, "" ); + const char* new_value = "bob's new info"; + uint32_t new_value_len = strlen(new_value); + db_update_i64( itr, receiver, new_value, new_value_len ); + char ret_value[50]; + db_get_i64( itr, ret_value, new_value_len ); + ret_value[new_value_len] = '\0'; + std::string sret(ret_value); + eosio_assert( sret == "bob's new info", "primary_i64_general - db_update_i64" ); + } +} + +void test_db::primary_i64_lowerbound( uint64_t receiver, uint64_t code, uint64_t action ) +{ + (void)code;(void)action; + auto table = "mytable"_n.value; + db_store_i64( receiver, table, receiver, "alice"_n.value, "alice's info", strlen("alice's info") ); + db_store_i64( receiver, table, receiver, "bob"_n.value, "bob's info", strlen("bob's info") ); + db_store_i64( receiver, table, receiver, "charlie"_n.value, "charlie's info", strlen("charlies's info") ); + db_store_i64( receiver, table, receiver, "emily"_n.value, "emily's info", strlen("emily's info") ); + db_store_i64( receiver, table, receiver, "allyson"_n.value, "allyson's info", strlen("allyson's info") ); + db_store_i64( receiver, table, receiver, "joe"_n.value, "nothing here", strlen("nothing here") ); + + const std::string err = "primary_i64_lowerbound"; + + { + int lb = db_lowerbound_i64( receiver, receiver, table, "alice"_n.value ); + eosio_assert( lb == db_find_i64(receiver, receiver, table, "alice"_n.value), err.c_str() ); + } + { + int lb = db_lowerbound_i64( receiver, receiver, table, "billy"_n.value ); + eosio_assert( lb == db_find_i64(receiver, receiver, table, "bob"_n.value), err.c_str() ); + } + { + int lb = db_lowerbound_i64( receiver, receiver, table, "frank"_n.value ); + eosio_assert( lb == db_find_i64(receiver, receiver, table, "joe"_n.value), err.c_str() ); + } + { + int lb = db_lowerbound_i64( receiver, receiver, table, "joe"_n.value ); + eosio_assert( lb == db_find_i64(receiver, receiver, table, "joe"_n.value), err.c_str() ); + } + { + int lb = db_lowerbound_i64( receiver, receiver, table, "kevin"_n.value ); + eosio_assert( lb < 0, err.c_str() ); + } +} + +void test_db::primary_i64_upperbound( uint64_t receiver, uint64_t code, uint64_t action ) +{ + (void)code;(void)action; + auto table = "mytable"_n.value; + const std::string err = "primary_i64_upperbound"; + { + int ub = db_upperbound_i64( receiver, receiver, table, "alice"_n.value ); + eosio_assert( ub == db_find_i64(receiver, receiver, table, "allyson"_n.value), err.c_str() ); + } + { + int ub = db_upperbound_i64( receiver, receiver, table, "billy"_n.value ); + eosio_assert( ub == db_find_i64(receiver, receiver, table, "bob"_n.value), err.c_str() ); + } + { + int ub = db_upperbound_i64( receiver, receiver, table, "frank"_n.value ); + eosio_assert( ub == db_find_i64(receiver, receiver, table, "joe"_n.value), err.c_str() ); + } + { + int ub = db_upperbound_i64( receiver, receiver, table, "joe"_n.value ); + eosio_assert( ub < 0, err.c_str() ); + } + { + int ub = db_upperbound_i64( receiver, receiver, table, "kevin"_n.value ); + eosio_assert( ub < 0, err.c_str() ); + } +} + +void test_db::idx64_general( uint64_t receiver, uint64_t code, uint64_t action ) +{ + (void)code;(void)action; + const auto table = "myindextable"_n.value; + + typedef uint64_t secondary_type; + + struct record { + uint64_t ssn; + secondary_type name; + }; + + record records[] = { {265, "alice"_n.value}, + {781, "bob"_n.value}, + {234, "charlie"_n.value}, + {650, "allyson"_n.value}, + {540, "bob"_n.value}, + {976, "emily"_n.value}, + {110, "joe"_n.value} }; + + for ( uint32_t i = 0; i < sizeof(records)/sizeof(records[0]); ++i ) { + db_idx64_store( receiver, table, receiver, records[i].ssn, &records[i].name ); + } + + // find_primary + { + secondary_type sec = 0; + int itr = db_idx64_find_primary( receiver, receiver, table, &sec, 999 ); + eosio_assert( itr < 0 && sec == 0, "idx64_general - db_idx64_find_primary" ); + itr = db_idx64_find_primary( receiver, receiver, table, &sec, 110 ); + eosio_assert( itr >= 0 && sec == "joe"_n.value, "idx64_general - db_idx64_find_primary" ); + uint64_t prim_next = 0; + int itr_next = db_idx64_next( itr, &prim_next ); + eosio_assert( itr_next < 0 && prim_next == 0, "idx64_general - db_idx64_find_primary" ); + } + + // iterate forward starting with charlie + { + secondary_type sec = 0; + int itr = db_idx64_find_primary( receiver, receiver, table, &sec, 234 ); + eosio_assert( itr >= 0 && sec == "charlie"_n.value, "idx64_general - db_idx64_find_primary" ); + + uint64_t prim_next = 0; + int itr_next = db_idx64_next( itr, &prim_next ); + eosio_assert( itr_next >= 0 && prim_next == 976, "idx64_general - db_idx64_next" ); + secondary_type sec_next = 0; + int itr_next_expected = db_idx64_find_primary( receiver, receiver, table, &sec_next, prim_next ); + eosio_assert( itr_next == itr_next_expected && sec_next == "emily"_n.value, "idx64_general - db_idx64_next" ); + + itr_next = db_idx64_next( itr_next, &prim_next ); + eosio_assert( itr_next >= 0 && prim_next == 110, "idx64_general - db_idx64_next" ); + itr_next_expected = db_idx64_find_primary( receiver, receiver, table, &sec_next, prim_next ); + eosio_assert( itr_next == itr_next_expected && sec_next == "joe"_n.value, "idx64_general - db_idx64_next" ); + + itr_next = db_idx64_next( itr_next, &prim_next ); + eosio_assert( itr_next < 0 && prim_next == 110, "idx64_general - db_idx64_next" ); + } + + // iterate backward staring with second bob + { + secondary_type sec = 0; + int itr = db_idx64_find_primary( receiver, receiver, table, &sec, 781 ); + eosio_assert( itr >= 0 && sec == "bob"_n.value, "idx64_general - db_idx64_find_primary" ); + + uint64_t prim_prev = 0; + int itr_prev = db_idx64_previous( itr, &prim_prev ); + eosio_assert( itr_prev >= 0 && prim_prev == 540, "idx64_general - db_idx64_previous" ); + + secondary_type sec_prev = 0; + int itr_prev_expected = db_idx64_find_primary( receiver, receiver, table, &sec_prev, prim_prev ); + eosio_assert( itr_prev == itr_prev_expected && sec_prev == "bob"_n.value, "idx64_general - db_idx64_previous" ); + + itr_prev = db_idx64_previous( itr_prev, &prim_prev ); + eosio_assert( itr_prev >= 0 && prim_prev == 650, "idx64_general - db_idx64_previous" ); + itr_prev_expected = db_idx64_find_primary( receiver, receiver, table, &sec_prev, prim_prev ); + eosio_assert( itr_prev == itr_prev_expected && sec_prev == "allyson"_n.value, "idx64_general - db_idx64_previous" ); + + itr_prev = db_idx64_previous( itr_prev, &prim_prev ); + eosio_assert( itr_prev >= 0 && prim_prev == 265, "idx64_general - db_idx64_previous" ); + itr_prev_expected = db_idx64_find_primary( receiver, receiver, table, &sec_prev, prim_prev ); + eosio_assert( itr_prev == itr_prev_expected && sec_prev == "alice"_n.value, "idx64_general - db_idx64_previous" ); + + itr_prev = db_idx64_previous( itr_prev, &prim_prev ); + eosio_assert( itr_prev < 0 && prim_prev == 265, "idx64_general - db_idx64_previous" ); + } + + // find_secondary + { + uint64_t prim = 0; + auto sec = "bob"_n.value; + int itr = db_idx64_find_secondary( receiver, receiver, table, &sec, &prim ); + eosio_assert( itr >= 0 && prim == 540, "idx64_general - db_idx64_find_secondary" ); + + sec = "emily"_n.value; + itr = db_idx64_find_secondary( receiver, receiver, table, &sec, &prim ); + eosio_assert( itr >= 0 && prim == 976, "idx64_general - db_idx64_find_secondary" ); + + sec = "frank"_n.value; + itr = db_idx64_find_secondary( receiver, receiver, table, &sec, &prim ); + eosio_assert( itr < 0 && prim == 976, "idx64_general - db_idx64_find_secondary" ); + } + + // update and remove + { + uint64_t one_more_bob = "bob"_n.value; + const uint64_t ssn = 421; + int itr = db_idx64_store( receiver, table, receiver, ssn, &one_more_bob ); + uint64_t new_name = "billy"_n.value; + db_idx64_update( itr, receiver, &new_name ); + secondary_type sec = 0; + int sec_itr = db_idx64_find_primary( receiver, receiver, table, &sec, ssn ); + eosio_assert( sec_itr == itr && sec == new_name, "idx64_general - db_idx64_update" ); + db_idx64_remove(itr); + int itrf = db_idx64_find_primary( receiver, receiver, table, &sec, ssn ); + eosio_assert( itrf < 0, "idx64_general - db_idx64_remove" ); + } +} + +void test_db::idx64_lowerbound( uint64_t receiver, uint64_t code, uint64_t action ) +{ + (void)code;(void)action; + const auto table = "myindextable"_n.value; + typedef uint64_t secondary_type; + const std::string err = "idx64_lowerbound"; + { + secondary_type lb_sec = "alice"_n.value; + uint64_t lb_prim = 0; + const uint64_t ssn = 265; + int lb = db_idx64_lowerbound( receiver, receiver, table, &lb_sec, &lb_prim ); + eosio_assert( lb_prim == ssn && lb_sec == "alice"_n.value, err.c_str() ); + eosio_assert( lb == db_idx64_find_primary(receiver, receiver, table, &lb_sec, ssn), err.c_str() ); + } + { + secondary_type lb_sec = "billy"_n.value; + uint64_t lb_prim = 0; + const uint64_t ssn = 540; + int lb = db_idx64_lowerbound( receiver, receiver, table, &lb_sec, &lb_prim ); + eosio_assert( lb_prim == ssn && lb_sec == "bob"_n.value, err.c_str() ); + eosio_assert( lb == db_idx64_find_primary(receiver, receiver, table, &lb_sec, ssn), err.c_str() ); + } + { + secondary_type lb_sec = "joe"_n.value; + uint64_t lb_prim = 0; + const uint64_t ssn = 110; + int lb = db_idx64_lowerbound( receiver, receiver, table, &lb_sec, &lb_prim ); + eosio_assert( lb_prim == ssn && lb_sec == "joe"_n.value, err.c_str() ); + eosio_assert( lb == db_idx64_find_primary(receiver, receiver, table, &lb_sec, ssn), err.c_str() ); + } + { + secondary_type lb_sec = "kevin"_n.value; + uint64_t lb_prim = 0; + int lb = db_idx64_lowerbound( receiver, receiver, table, &lb_sec, &lb_prim ); + eosio_assert( lb_prim == 0 && lb_sec == "kevin"_n.value, err.c_str() ); + eosio_assert( lb < 0, "" ); + } +} + +void test_db::idx64_upperbound( uint64_t receiver, uint64_t code, uint64_t action ) +{ + (void)code;(void)action; + const auto table = "myindextable"_n.value; + typedef uint64_t secondary_type; + const std::string err = "idx64_upperbound"; + { + secondary_type ub_sec = "alice"_n.value; + uint64_t ub_prim = 0; + const uint64_t allyson_ssn = 650; + int ub = db_idx64_upperbound( receiver, receiver, table, &ub_sec, &ub_prim ); + eosio_assert( ub_prim == allyson_ssn && ub_sec == "allyson"_n.value, "" ); + eosio_assert( ub == db_idx64_find_primary(receiver, receiver, table, &ub_sec, allyson_ssn), err.c_str() ); + } + { + secondary_type ub_sec = "billy"_n.value; + uint64_t ub_prim = 0; + const uint64_t bob_ssn = 540; + int ub = db_idx64_upperbound( receiver, receiver, table, &ub_sec, &ub_prim ); + eosio_assert( ub_prim == bob_ssn && ub_sec == "bob"_n.value, "" ); + eosio_assert( ub == db_idx64_find_primary(receiver, receiver, table, &ub_sec, bob_ssn), err.c_str() ); + } + { + secondary_type ub_sec = "joe"_n.value; + uint64_t ub_prim = 0; + int ub = db_idx64_upperbound( receiver, receiver, table, &ub_sec, &ub_prim ); + eosio_assert( ub_prim == 0 && ub_sec == "joe"_n.value, err.c_str() ); + eosio_assert( ub < 0, err.c_str() ); + } + { + secondary_type ub_sec = "kevin"_n.value; + uint64_t ub_prim = 0; + int ub = db_idx64_upperbound( receiver, receiver, table, &ub_sec, &ub_prim ); + eosio_assert( ub_prim == 0 && ub_sec == "kevin"_n.value, err.c_str() ); + eosio_assert( ub < 0, err.c_str() ); + } +} + +void test_db::test_invalid_access( uint64_t receiver, uint64_t code, uint64_t action ) +{ + (void)code;(void)action; + auto act = eosio::get_action(1, 0); + auto ia = eosio::unpack(act.data); + uint64_t scope = "access"_n.value; + uint64_t table = scope; + uint64_t pk = scope; + + int32_t itr = -1; + uint64_t value = 0; + switch( ia.index ) { + case 1: + itr = db_idx64_find_primary( ia.code, scope, table, &value, pk ); + break; + case 0: + default: + itr = db_find_i64( ia.code, scope, table, pk ); + break; + } + if(ia.store) { + uint64_t value_to_store = ia.val; + if( itr < 0 ) { + switch(ia.index) { + case 1: + db_idx64_store( scope, table, receiver, pk, &value_to_store ); + break; + case 0: + default: + db_store_i64( scope, table, receiver, pk, &value_to_store, sizeof(value_to_store) ); + break; + } + } else { + switch(ia.index) { + case 1: + db_idx64_update( itr, receiver, &value_to_store); + break; + case 0: + default: + db_update_i64( itr, receiver, &value_to_store, sizeof(value_to_store) ); + break; + } + } + //eosio::print("test_invalid_access: stored ", value_to_store, "\n"); + } else { + eosio_assert( itr >= 0, "test_invalid_access: could not find row" ); + switch(ia.index) { + case 1: + break; + case 0: + default: + eosio_assert( db_get_i64( itr, &value, sizeof(value) ) == sizeof(value), + "test_invalid_access: value in primary table was incorrect size" ); + break; + } + //eosio::print("test_invalid_access: expected ", ia.val, " and retrieved ", value, "\n"); + eosio_assert( value == ia.val, "test_invalid_access: value did not match" ); + } +} + +void test_db::idx_double_nan_create_fail( uint64_t receiver, uint64_t, uint64_t ) { + double x = 0.0; + x = x / x; // create a NaN + db_idx_double_store( "nan"_n.value, "nan"_n.value, receiver, 0, &x ); // should fail +} + +void test_db::idx_double_nan_modify_fail( uint64_t receiver, uint64_t, uint64_t ) { + double x = 0.0; + db_idx_double_store( "nan"_n.value, "nan"_n.value, receiver, 0, &x ); + auto itr = db_idx_double_find_primary( receiver, "nan"_n.value, "nan"_n.value, &x, 0 ); + x = 0.0; + x = x / x; // create a NaN + db_idx_double_update( itr, 0, &x ); // should fail +} + +void test_db::idx_double_nan_lookup_fail( uint64_t receiver, uint64_t, uint64_t ) { + auto act = eosio::get_action( 1,0 ); + auto lookup_type = eosio::unpack(act.data); + + uint64_t pk; + double x = 0.0; + db_idx_double_store( "nan"_n.value, "nan"_n.value, receiver, 0, &x ); + x = x / x; // create a NaN + switch(lookup_type) { + case 0: // find + db_idx_double_find_secondary( receiver, "nan"_n.value, "nan"_n.value, &x, &pk ); + break; + case 1: // lower bound + db_idx_double_lowerbound( receiver, "nan"_n.value, "nan"_n.value, &x, &pk ); + break; + case 2: // upper bound + db_idx_double_upperbound( receiver, "nan"_n.value, "nan"_n.value, &x, &pk ); + break; + default: + eosio_assert( false, "idx_double_nan_lookup_fail: unexpected lookup_type" ); + } +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-align" + +void test_db::misaligned_secondary_key256_tests( uint64_t /* receiver */, uint64_t, uint64_t ) { + auto key = eosio::checksum256::make_from_word_sequence( 0ULL, 0ULL, 0ULL, 42ULL ); + char* ptr = (char*)(&key); + ptr += 1; + // test that store doesn't crash on unaligned data + db_idx256_store( "testapi"_n.value, "testtable"_n.value, "testapi"_n.value, 1, (uint128_t*)(ptr), 2 ); + // test that find_primary doesn't crash on unaligned data + db_idx256_find_primary( "testapi"_n.value, "testtable"_n.value, "testapi"_n.value, (uint128_t*)(ptr), 2,0 ); +} + +#pragma clang diagnostic pop diff --git a/unittests/test-contracts/test_api_mem/CMakeLists.txt b/unittests/test-contracts/test_api_mem/CMakeLists.txt new file mode 100644 index 00000000000..b0de4a71135 --- /dev/null +++ b/unittests/test-contracts/test_api_mem/CMakeLists.txt @@ -0,0 +1,5 @@ +if( ${eosio.cdt_FOUND} ) + add_executable( test_api_mem test_api_mem.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test_api_mem.wasm ${CMAKE_CURRENT_BINARY_DIR}/test_api_mem.wasm COPYONLY ) +endif() diff --git a/unittests/test-contracts/test_api_mem/test_api_mem.cpp b/unittests/test-contracts/test_api_mem/test_api_mem.cpp new file mode 100644 index 00000000000..df635e35a0d --- /dev/null +++ b/unittests/test-contracts/test_api_mem/test_api_mem.cpp @@ -0,0 +1,49 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include + +#include "../test_api/test_api.hpp" +#include "test_extended_memory.cpp" +#include "test_memory.cpp" + +extern "C" { + void apply( uint64_t /*receiver*/, uint64_t code, uint64_t action ) { + require_auth(code); + + //test_extended_memory + WASM_TEST_HANDLER( test_extended_memory, test_initial_buffer ); + WASM_TEST_HANDLER( test_extended_memory, test_page_memory ); + WASM_TEST_HANDLER( test_extended_memory, test_page_memory_exceeded ); + WASM_TEST_HANDLER( test_extended_memory, test_page_memory_negative_bytes ); + + //test_memory + WASM_TEST_HANDLER( test_memory, test_memory_allocs ); + WASM_TEST_HANDLER( test_memory, test_memory_hunk ); + WASM_TEST_HANDLER( test_memory, test_memory_hunks ); + WASM_TEST_HANDLER( test_memory, test_memory_hunks_disjoint ); + WASM_TEST_HANDLER( test_memory, test_memset_memcpy ); + WASM_TEST_HANDLER( test_memory, test_memcpy_overlap_start ); + WASM_TEST_HANDLER( test_memory, test_memcpy_overlap_end ); + WASM_TEST_HANDLER( test_memory, test_memcmp ); + WASM_TEST_HANDLER( test_memory, test_outofbound_0 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_1 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_2 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_3 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_4 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_5 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_6 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_7 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_8 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_9 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_10 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_11 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_12 ); + WASM_TEST_HANDLER( test_memory, test_outofbound_13 ); + + //unhandled test call + eosio_assert( false, "Unknown Test" ); + } + +} diff --git a/unittests/test-contracts/test_api_mem/test_api_mem.wasm b/unittests/test-contracts/test_api_mem/test_api_mem.wasm new file mode 100755 index 00000000000..89582ffaeca Binary files /dev/null and b/unittests/test-contracts/test_api_mem/test_api_mem.wasm differ diff --git a/contracts/test_api_mem/test_extended_memory.cpp b/unittests/test-contracts/test_api_mem/test_extended_memory.cpp similarity index 53% rename from contracts/test_api_mem/test_extended_memory.cpp rename to unittests/test-contracts/test_api_mem/test_extended_memory.cpp index 48740a1421f..8a66d528150 100644 --- a/contracts/test_api_mem/test_extended_memory.cpp +++ b/unittests/test-contracts/test_api_mem/test_extended_memory.cpp @@ -1,13 +1,16 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ #include #include -#include "../test_api/test_api.hpp" -//using namespace eosio; +#include "../test_api/test_api.hpp" void verify( const void* const ptr, const uint32_t val, const uint32_t size) { const char* char_ptr = (const char*)ptr; - for (uint32_t i = 0; i < size; ++i) - eosio_assert(static_cast(static_cast(char_ptr[i])) == val, "buffer slot doesn't match"); + for ( uint32_t i = 0; i < size; ++i ) + eosio_assert( static_cast(static_cast(char_ptr[i])) == val, "buffer slot doesn't match" ); } #define PRINT_PTR(x) prints("PTR : "); print((uint32_t)x, 4); prints("\n"); @@ -20,7 +23,7 @@ void test_extended_memory::test_page_memory() { * when I call sbrk(0), then I should get the end of the first page, which should be 64K. */ auto prev = sbrk(0); - eosio_assert(reinterpret_cast(prev) == _64K, "Should initially have 1 64K page allocated"); + eosio_assert( reinterpret_cast(prev) == _64K, "Should initially have 1 64K page allocated" ); /* * Test test_extended_memory::test_page_memory `ensure sbrk returns previous end of program break` @@ -28,7 +31,7 @@ void test_extended_memory::test_page_memory() { * when I call sbrk(1), then I should get the end of the first page, which should be 64K. */ prev = sbrk(1); - eosio_assert(reinterpret_cast(prev) == _64K, "Should still be pointing to the end of the 1st 64K page"); + eosio_assert( reinterpret_cast(prev) == _64K, "Should still be pointing to the end of the 1st 64K page" ); /* * Test test_extended_memory::test_page_memory `ensure sbrk aligns allocations` @@ -36,7 +39,7 @@ void test_extended_memory::test_page_memory() { * when I call sbrk(2), then I should get 8 bytes past the previous end because of maintaining 8 byte alignment. */ prev = sbrk(2); - eosio_assert(reinterpret_cast(prev) == _64K+8, "Should point to 8 past the end of 1st 64K page"); + eosio_assert( reinterpret_cast(prev) == _64K+8, "Should point to 8 past the end of 1st 64K page" ); /* * Test test_extended_memory::test_page_memory `ensure sbrk aligns allocations 2` @@ -44,31 +47,31 @@ void test_extended_memory::test_page_memory() { * when I call sbrk(_64K-17), then I should get 8 bytes past the previous end because of maintaining 8 byte alignment. */ prev = sbrk(_64K - 17); - eosio_assert(reinterpret_cast(prev) == _64K+16, "Should point to 16 past the end of the 1st 64K page"); + eosio_assert( reinterpret_cast(prev) == _64K+16, "Should point to 16 past the end of the 1st 64K page" ); prev = sbrk(1); - eosio_assert(reinterpret_cast(prev) == 2*_64K, "Should point to the end of the 2nd 64K page"); + eosio_assert( reinterpret_cast(prev) == 2*_64K, "Should point to the end of the 2nd 64K page" ); prev = sbrk(_64K); - eosio_assert(reinterpret_cast(prev) == 2*_64K+8, "Should point to 8 past the end of the 2nd 64K page"); + eosio_assert( reinterpret_cast(prev) == 2*_64K+8, "Should point to 8 past the end of the 2nd 64K page" ); prev = sbrk(_64K - 15); - eosio_assert(reinterpret_cast(prev) == 3*_64K+8, "Should point to 8 past the end of the 3rd 64K page"); + eosio_assert( reinterpret_cast(prev) == 3*_64K+8, "Should point to 8 past the end of the 3rd 64K page" ); prev = sbrk(2*_64K-1); - eosio_assert(reinterpret_cast(prev) == 4*_64K, "Should point to the end of the 4th 64K page"); + eosio_assert( reinterpret_cast(prev) == 4*_64K, "Should point to the end of the 4th 64K page" ); prev = sbrk(2*_64K); - eosio_assert(reinterpret_cast(prev) == 6*_64K, "Should point to the end of the 6th 64K page"); + eosio_assert( reinterpret_cast(prev) == 6*_64K, "Should point to the end of the 6th 64K page" ); prev = sbrk(2*_64K+1); - eosio_assert(reinterpret_cast(prev) == 8*_64K, "Should point to the end of the 8th 64K page"); + eosio_assert( reinterpret_cast(prev) == 8*_64K, "Should point to the end of the 8th 64K page" ); prev = sbrk(6*_64K-15); - eosio_assert(reinterpret_cast(prev) == 10*_64K+8, "Should point to 8 past the end of the 10th 64K page"); + eosio_assert( reinterpret_cast(prev) == 10*_64K+8, "Should point to 8 past the end of the 10th 64K page" ); prev = sbrk(0); - eosio_assert(reinterpret_cast(prev) == 16*_64K, "Should point to 8 past the end of the 16th 64K page"); + eosio_assert( reinterpret_cast(prev) == 16*_64K, "Should point to 8 past the end of the 16th 64K page" ); } void test_extended_memory::test_page_memory_exceeded() { @@ -78,33 +81,32 @@ void test_extended_memory::test_page_memory_exceeded() { * when I increase allocated memory with sbrk(15*64K), then I should get the end of the first page. */ auto prev = sbrk(15*64*1024); - eosio_assert(reinterpret_cast(prev) == 64*1024, "Should have allocated 1M of memory"); + eosio_assert( reinterpret_cast(prev) == 64*1024, "Should have allocated 1M of memory" ); /* * Test test_extended_memory::test_page_memory_exceeded `ensure sbrk won't allocation more than 1M of memory 2` */ prev = sbrk(0); - eosio_assert(reinterpret_cast(prev) == (1024*1024), "Should have allocated 1M of memory"); - - eosio_assert(reinterpret_cast(sbrk(1)) == -1, "sbrk should have failed for trying to allocate too much memory"); + eosio_assert( reinterpret_cast(prev) == (1024*1024), "Should have allocated 1M of memory" ); + eosio_assert( reinterpret_cast(sbrk(32*1024*1024+1)) == -1, "sbrk should have failed for trying to allocate too much memory" ); } void test_extended_memory::test_page_memory_negative_bytes() { - eosio_assert(reinterpret_cast(sbrk((uint32_t)-1)) == -1, "Should have errored for trying to remove memory"); + eosio_assert( reinterpret_cast(sbrk((uint32_t)-1)) == -1, "Should have errored for trying to remove memory" ); } void test_extended_memory::test_initial_buffer() { // initial buffer should be exhausted at 8192 bytes // 8176 left ( 12 + ptr header ) char* ptr1 = (char*)malloc(12); - eosio_assert(ptr1 != nullptr, "should have allocated 12 char buffer"); + eosio_assert( ptr1 != nullptr, "should have allocated 12 char buffer" ); char* ptr2 = (char*)malloc(8159); - eosio_assert(ptr2 != nullptr, "should have allocate 8159 char buffer"); + eosio_assert( ptr2 != nullptr, "should have allocate 8159 char buffer" ); // should overrun initial heap, allocated in 2nd heap char* ptr3 = (char*)malloc(20); - eosio_assert(ptr3 != nullptr, "should have allocated a 20 char buffer"); - verify(ptr3, 0, 20); + eosio_assert( ptr3 != nullptr, "should have allocated a 20 char buffer" ); + verify( ptr3, 0, 20 ); } diff --git a/unittests/test-contracts/test_api_mem/test_memory.cpp b/unittests/test-contracts/test_api_mem/test_memory.cpp new file mode 100644 index 00000000000..7fbe3a26e7a --- /dev/null +++ b/unittests/test-contracts/test_api_mem/test_memory.cpp @@ -0,0 +1,386 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include + +#include "../test_api/test_api.hpp" + +void verify_mem( const void* const ptr, const uint32_t val, const uint32_t size ) +{ + const char* char_ptr = (const char*)ptr; + for ( uint32_t i = 0; i < size; ++i ) + { + eosio_assert( static_cast(static_cast(char_ptr[i])) == val, "buf slot doesn't match" ); + } +} + +/* +* malloc and realloc always allocate on 8 byte boundaries based off of total allocation, so +* if the requested size + the 2 byte header is not divisible by 8, then the allocated space +* will be larger than the requested size +*/ +void test_memory::test_memory_allocs() +{ + char* ptr1 = (char*)malloc(0); + eosio_assert( ptr1 == nullptr, "should not have allocated a 0 char buf" ); + + // 20 chars - 20 + 4(header) which is divisible by 8 + ptr1 = (char*)malloc(20); + eosio_assert( ptr1 != nullptr, "should have allocated a 20 char buf" ); + verify_mem( ptr1, 0, 20 ); + // existing memory layout -> |24| + + // 36 chars allocated - 30 + 4 plus an extra 6 to be divisible by 8 + char* ptr1_realloc = (char*)realloc( ptr1, 30 ); + eosio_assert( ptr1_realloc != nullptr, "should have returned a 30 char buf" ); + eosio_assert( ptr1_realloc == ptr1, "should have enlarged the 20 char buf" ); + // existing memory layout -> |40| + + // 20 chars allocated + char* ptr2 = (char*)malloc(20); + eosio_assert( ptr2 != nullptr, "should have allocated another 20 char buf" ); + eosio_assert( ptr1 + 36 < ptr2, "20 char buf should have been created after ptr1" ); // test specific to implementation (can remove for refactor) + verify_mem( ptr1, 0, 36 ); + eosio_assert( ptr1[36] != 0, "should not have empty bytes following since block allocated" ); // test specific to implementation (can remove for refactor) + // existing memory layout -> |40|24| + + //shrink the buffer + ptr1[14] = 0x7e; + // 20 chars allocated (still) + ptr1_realloc = (char*)realloc( ptr1, 15 ); + eosio_assert( ptr1_realloc != nullptr, "should have returned a 15 char buf" ); + eosio_assert( ptr1_realloc == ptr1, "should have shrunk the reallocated 30 char buf" ); + verify_mem( ptr1, 0, 14); // test specific to implementation (can remove for refactor) + eosio_assert( ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched" ); + // existing memory layout -> |24(shrunk)|16(freed)|24| + + //same size the buffer (verify corner case) + // 20 chars allocated (still) + ptr1_realloc = (char*)realloc( ptr1, 15 ); + eosio_assert( ptr1_realloc != nullptr, "should have returned a reallocated 15 char buf" ); + eosio_assert( ptr1_realloc == ptr1, "should have reallocated 15 char buf as the same buf" ); + eosio_assert( ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched for unchanged buf" ); + + //same size as max allocated buffer -- test specific to implementation (can remove for refactor) + ptr1_realloc = (char*)realloc( ptr1, 30 ); + eosio_assert( ptr1_realloc != nullptr, "should have returned a 30 char buf" ); + eosio_assert( ptr1_realloc == ptr1, "should have increased the buf back to orig max"); //test specific to implementation (can remove for refacto r) + eosio_assert( ptr1[14] == 0x7e, "remaining 15 chars of buf should be untouched for expanded buf" ); + + //increase buffer beyond (indicated) allocated space + // 36 chars allocated (still) + ptr1_realloc = (char*)realloc( ptr1, 36 ); + eosio_assert( ptr1_realloc != nullptr, "should have returned a 36 char buf" ); + eosio_assert( ptr1_realloc == ptr1, "should have increased char buf to actual size" ); // test specific to implementation (can remove for refacto r) + + //increase buffer beyond allocated space + ptr1[35] = 0x7f; + // 44 chars allocated - 37 + 4 plus an extra 7 to be divisible by 8 + ptr1_realloc = (char*)realloc( ptr1, 37 ); + eosio_assert( ptr1_realloc != nullptr, "should have returned a 37 char buf" ); + eosio_assert( ptr1_realloc != ptr1, "should have had to create new 37 char buf from 36 char buf" ); + eosio_assert( ptr2 < ptr1_realloc, "should have been created after ptr2" ); // test specific to implementation (can remove for refacto r) + eosio_assert( ptr1_realloc[14] == 0x7e, "orig 36 char buf's content should be copied" ); + eosio_assert( ptr1_realloc[35] == 0x7f, "orig 36 char buf's content should be copied" ); + + //realloc with nullptr + char* nullptr_realloc = (char*)realloc( nullptr, 50 ); + eosio_assert( nullptr_realloc != nullptr, "should have returned a 50 char buf and ignored nullptr" ); + eosio_assert( ptr1_realloc < nullptr_realloc, "should have created after ptr1_realloc" ); // test specific to implementation (can remove for refactor) + + //realloc with invalid ptr + char* invalid_ptr_realloc = (char*)realloc( nullptr_realloc + 4, 10 ); + eosio_assert( invalid_ptr_realloc != nullptr, "should have returned a 10 char buf and ignored invalid ptr" ); + eosio_assert( nullptr_realloc < invalid_ptr_realloc, "should have created invalid_ptr_realloc after nullptr_realloc" ); // test specific to implementation (can remove for refactor) +} + +// this test verifies that malloc can allocate 15 64K pages and treat them as one big heap space (if sbrk is not called in the mean time) +void test_memory::test_memory_hunk() +{ + // try to allocate the largest buffer we can, which is 15 contiguous 64K pages (with the 4 char space for the ptr header) + char* ptr1 = (char*)malloc( 15 * 64 * 1024 - 4 ); + eosio_assert( ptr1 != nullptr, "should have allocated a ~983K char buf" ); +} + +void test_memory::test_memory_hunks() +{ + // This test will be moved to `eosio.cdt' + // Note: for this reason, the asserts are commented out. + + // leave 784 bytes of initial buffer to allocate later (rounds up to nearest 8 byte boundary, + // 16 bytes bigger than remainder left below in 15 64K page heap)) + char* ptr1 = (char*)malloc(7404); + eosio_assert( ptr1 != nullptr, "should have allocated a 7404 char buf" ); + + char* last_ptr = nullptr; + // 96 * (10 * 1024 - 15) => 15 ~64K pages with 768 byte buffer left to allocate + for (int i = 0; i < 96; ++i) + { + char* ptr2 = (char*)malloc( 10 * 1024 - 15 ); + eosio_assert( ptr2 != nullptr, "should have allocated a ~10K char buf" ); + if ( last_ptr != nullptr ) + { + // - 15 rounds to -8 + eosio_assert( last_ptr + 10 * 1024 - 8 == ptr2, "should allocate the very next ptr" ); // test specific to implementation (can remove for refactor) + } + + last_ptr = ptr2; + } + + // try to allocate a buffer slightly larger than the remaining buffer| 765 + 4 rounds to 776 + char* ptr3 = (char*)malloc(765); + + eosio_assert( ptr3 != nullptr, "should have allocated a 772 char buf" ); + //eosio_assert(ptr1 + 7408 == ptr3, "should allocate the very next ptr after ptr1 in initial heap"); // test specific to implementation (can remove for refactor) + + // use all but 8 chars + char* ptr4 = (char*)malloc(764); + eosio_assert( ptr4 != nullptr, "should have allocated a 764 char buf" ); + //eosio_assert(last_ptr + 10 * 1024 - 8 == ptr4, "should allocate the very next ptr after last_ptr at end of contiguous heap"); // test specific to implementation (can remove for refactor) + + // use up remaining 8 chars + char* ptr5 = (char*)malloc(4); + eosio_assert( ptr5 != nullptr, "should have allocated a 4 char buf" ); + //eosio_assert(ptr3 + 776 == ptr5, "should allocate the very next ptr after ptr3 in initial heap"); // test specific to implementation (can remove for refactor) + + // nothing left to allocate + char* ptr6 = (char*)malloc(4); + //eosio_assert(ptr6 == nullptr, "should not have allocated a char buf"); +} + +void test_memory::test_memory_hunks_disjoint() +{ + // leave 8 bytes of initial buffer to allocate later + char* ptr1 = (char*)malloc( 8 * 1024 - 12 ); + eosio_assert( ptr1 != nullptr, "should have allocated a 8184 char buf" ); + + // can only make 14 extra (64K) heaps for malloc, since calls to sbrk will eat up part + char* loop_ptr1[14]; + // 14 * (64 * 1024 - 28) => 14 ~64K pages with each page having 24 bytes left to allocate + for ( int i = 0; i < 14; ++ i) + { + // allocates a new heap for each request, since sbrk call doesn't allow contiguous heaps to grow + loop_ptr1[i] = (char*)malloc( 64 * 1024 - 28 ); + eosio_assert( loop_ptr1[i] != nullptr, "should have allocated a 64K char buf" ); + + eosio_assert( reinterpret_cast(sbrk(4)) != -1, "should be able to allocate 8 bytes" ); + } + + // the 15th extra heap is reduced in size because of the 14 * 8 bytes allocated by sbrk calls + // will leave 8 bytes to allocate later (verifying that we circle back in the list + char* ptr2 = (char*)malloc(65412); + eosio_assert( ptr2 != nullptr, "should have allocated a 65412 char buf" ); + + char* loop_ptr2[14]; + for ( int i = 0; i < 14; ++ i) + { + // 12 char buffer to leave 8 bytes for another pass + loop_ptr2[i] = (char*)malloc(12); + eosio_assert( loop_ptr2[i] != nullptr, "should have allocated a 12 char buf" ); + eosio_assert( loop_ptr1[i] + 64 * 1024 - 24 == loop_ptr2[i], "loop_ptr2[i] should be very next pointer after loop_ptr1[i]" ); + } + + // this shows that searching for free ptrs starts at the last loop to find free memory, not at the begining + char* ptr3 = (char*)malloc(4); + eosio_assert( ptr3 != nullptr, "should have allocated a 4 char buf" ); + eosio_assert( loop_ptr2[13] + 16 == ptr3, "should allocate the very next ptr after loop_ptr2[13]" ); // test specific to implementation (can remove for refacto r) + + char* ptr4 = (char*)malloc(4); + eosio_assert( ptr4 != nullptr, "should have allocated a 4 char buf" ); + eosio_assert( ptr2 + 65416 == ptr4, "should allocate the very next ptr after ptr2 in last heap" ); // test specific to implementation (can remove for refacto r) + + char* ptr5 = (char*)malloc(4); + eosio_assert( ptr5 != nullptr, "should have allocated a 4 char buf" ); + eosio_assert( ptr1 + 8184 == ptr5, "should allocate the very next ptr after ptr1 in last heap" ); // test specific to implementation (can remove for refactor) + + // will eat up remaining memory (14th heap already used up) + char* loop_ptr3[13]; + for ( int i = 0; i < 13; ++i ) + { + // 4 char buffer to use up buffer + loop_ptr3[i] = (char*)malloc(4); + eosio_assert( loop_ptr3[i] != nullptr, "should have allocated a 4 char buf" ); + eosio_assert( loop_ptr2[i] + 16 == loop_ptr3[i], "loop_ptr3[i] should be very next pointer after loop_ptr2[i]" ); + } + + char* ptr6 = (char*)malloc(4); + eosio_assert( ptr6 == nullptr, "should not have allocated a char buf" ); + + free(loop_ptr1[3]); + free(loop_ptr2[3]); + free(loop_ptr3[3]); + + char* slot3_ptr[64]; + for ( int i = 0; i < 64; ++ i) + { + slot3_ptr[i] = (char*)malloc(1020); + eosio_assert( slot3_ptr[i] != nullptr, "should have allocated a 1020 char buf" ); + if (i == 0) + eosio_assert( loop_ptr1[3] == slot3_ptr[0], "loop_ptr1[3] should be very next pointer after slot3_ptr[0]" ); + else + eosio_assert( slot3_ptr[i - 1] + 1024 == slot3_ptr[i], "slot3_ptr[i] should be very next pointer after slot3_ptr[i-1]" ); + } + + char* ptr7 = (char*)malloc(4); + eosio_assert( ptr7 == nullptr, "should not have allocated a char buf" ); +} + +void test_memory::test_memset_memcpy() +{ + char buf1[40] = {}; + char buf2[40] = {}; + + verify_mem( buf1, 0, 40 ); + verify_mem( buf2, 0, 40 ); + + memset( buf1, 0x22, 20 ); + verify_mem( buf1, 0x22, 20 ); + verify_mem( &buf1[20], 0, 20 ); + + memset( &buf2[20], 0xff, 20 ); + verify_mem( buf2, 0, 20 ); + verify_mem( &buf2[20], 0xff, 20 ); + + memcpy( &buf1[10], &buf2[10], 20 ); + verify_mem( buf1, 0x22, 10 ); + verify_mem( &buf1[10], 0, 10 ); + verify_mem( &buf1[20], 0xff, 10 ); + verify_mem( &buf1[30], 0, 10 ); + + memset( &buf1[1], 1, 1 ); + verify_mem( buf1, 0x22, 1 ); + verify_mem( &buf1[1], 1, 1 ); + verify_mem( &buf1[2], 0x22, 8 ); + + // verify adjacent non-overlapping buffers + char buf3[50] = {}; + memset( &buf3[25], 0xee, 25 ); + verify_mem( buf3, 0, 25 ); + memcpy( buf3, &buf3[25], 25 ); + verify_mem( buf3, 0xee, 50 ); + + memset( buf3, 0, 25 ); + verify_mem( &buf3[25], 0xee, 25 ); + memcpy( &buf3[25], buf3, 25 ); + verify_mem( buf3, 0, 50 ); +} + +void test_memory::test_memcpy_overlap_start() +{ + char buf3[99] = {}; + memset( buf3, 0xee, 50 ); + memset( &buf3[50], 0xff, 49 ); + memcpy( &buf3[49], buf3, 50 ); +} + + +void test_memory::test_memcpy_overlap_end() +{ + char buf3[99] = {}; + memset( buf3, 0xee, 50 ); + memset( &buf3[50], 0xff, 49 ); + memcpy( buf3, &buf3[49], 50 ); +} + +void test_memory::test_memcmp() +{ + char buf1[] = "abcde"; + char buf2[] = "abcde"; + int32_t res1 = memcmp( buf1, buf2, 6 ); + eosio_assert( res1 == 0, "first data should be equal to second data" ); + + char buf3[] = "abcde"; + char buf4[] = "fghij"; + int32_t res2 = memcmp( buf3, buf4, 6 ); + eosio_assert( res2 < 0, "first data should be smaller than second data" ); + + char buf5[] = "fghij"; + char buf6[] = "abcde"; + int32_t res3 = memcmp( buf5, buf6, 6 ); + eosio_assert( res3 > 0, "first data should be larger than second data" ); +} + +void test_memory::test_outofbound_0() +{ + memset( (char *)0, 0xff, 1024 * 1024 * 1024 ); // big memo ry +} + +void test_memory::test_outofbound_1() +{ + memset( (char *)16, 0xff, 0xffffffff ); // memory wrap around +} + +void test_memory::test_outofbound_2() +{ + char buf[1024] = {0}; + char *ptr = (char *)malloc(1048576); + memcpy( buf, ptr, 1048576 ); // stack memory out of bound +} + +void test_memory::test_outofbound_3() +{ + char *ptr = (char *)malloc(128); + memset( ptr, 0xcc, 1048576 ); // heap memory out of bound +} + +template +void test_memory_store() { + T *ptr = (T *)( 8192 * 1024 - 1 ); + ptr[0] = (T)1; +} + +template +void test_memory_load() { + T *ptr = (T *)( 8192 * 1024 - 1 ); + volatile T tmp = ptr[0]; + (void)tmp; +} + +void test_memory::test_outofbound_4() +{ + test_memory_store(); +} +void test_memory::test_outofbound_5() +{ + test_memory_store(); +} +void test_memory::test_outofbound_6() +{ + test_memory_store(); +} +void test_memory::test_outofbound_7() +{ + test_memory_store(); +} +void test_memory::test_outofbound_8() +{ + test_memory_load(); +} +void test_memory::test_outofbound_9() +{ + test_memory_load(); +} +void test_memory::test_outofbound_10() +{ + test_memory_load(); +} +void test_memory::test_outofbound_11() +{ + test_memory_load(); +} + +void test_memory::test_outofbound_12() +{ + volatile unsigned int a = 0xffffffff; + double *ptr = (double *)a; // store with memory wrap + ptr[0] = 1; +} + +void test_memory::test_outofbound_13() +{ + volatile unsigned int a = 0xffffffff; + double *ptr = (double *)a; // load with memory wrap + volatile double tmp = ptr[0]; + (void)tmp; +} diff --git a/unittests/test-contracts/test_api_multi_index/CMakeLists.txt b/unittests/test-contracts/test_api_multi_index/CMakeLists.txt new file mode 100644 index 00000000000..4331707d23b --- /dev/null +++ b/unittests/test-contracts/test_api_multi_index/CMakeLists.txt @@ -0,0 +1,6 @@ +if( ${eosio.cdt_FOUND} ) + include_directories( ${Boost_INCLUDE_DIRS} ) + add_executable( test_api_multi_index test_api_multi_index.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test_api_multi_index.wasm ${CMAKE_CURRENT_BINARY_DIR}/test_api_multi_index.wasm COPYONLY ) +endif() diff --git a/unittests/test-contracts/test_api_multi_index/test_api_multi_index.cpp b/unittests/test-contracts/test_api_multi_index/test_api_multi_index.cpp new file mode 100644 index 00000000000..54c4dc4214d --- /dev/null +++ b/unittests/test-contracts/test_api_multi_index/test_api_multi_index.cpp @@ -0,0 +1,50 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include + +#include "../test_api/test_api.hpp" +#include "test_multi_index.cpp" + +extern "C" { + + void apply( uint64_t receiver, uint64_t code, uint64_t action ) { + require_auth(code); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_general ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_store_only ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_check_without_storing ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_require_find_fail ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_require_find_fail_with_msg ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_require_find_sk_fail ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_require_find_sk_fail_with_msg ); + WASM_TEST_HANDLER_EX( test_multi_index, idx128_general ); + WASM_TEST_HANDLER_EX( test_multi_index, idx128_store_only ); + WASM_TEST_HANDLER_EX( test_multi_index, idx128_check_without_storing ); + WASM_TEST_HANDLER_EX( test_multi_index, idx128_autoincrement_test ); + WASM_TEST_HANDLER_EX( test_multi_index, idx128_autoincrement_test_part1 ); + WASM_TEST_HANDLER_EX( test_multi_index, idx128_autoincrement_test_part2 ); + WASM_TEST_HANDLER_EX( test_multi_index, idx256_general ); + WASM_TEST_HANDLER_EX( test_multi_index, idx_double_general ); + WASM_TEST_HANDLER_EX( test_multi_index, idx_long_double_general ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pk_iterator_exceed_end ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_sk_iterator_exceed_end ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pk_iterator_exceed_begin ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_sk_iterator_exceed_begin ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pass_pk_ref_to_other_table ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pass_sk_ref_to_other_table ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pass_pk_end_itr_to_iterator_to ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pass_pk_end_itr_to_modify ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pass_pk_end_itr_to_erase ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pass_sk_end_itr_to_iterator_to ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pass_sk_end_itr_to_modify ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pass_sk_end_itr_to_erase ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_modify_primary_key ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_run_out_of_avl_pk ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_sk_cache_pk_lookup ); + WASM_TEST_HANDLER_EX( test_multi_index, idx64_pk_cache_sk_lookup ); + + //unhandled test call + eosio_assert( false, "Unknown Test" ); + } +} diff --git a/unittests/test-contracts/test_api_multi_index/test_api_multi_index.wasm b/unittests/test-contracts/test_api_multi_index/test_api_multi_index.wasm new file mode 100755 index 00000000000..322c00f6795 Binary files /dev/null and b/unittests/test-contracts/test_api_multi_index/test_api_multi_index.wasm differ diff --git a/unittests/test-contracts/test_api_multi_index/test_multi_index.cpp b/unittests/test-contracts/test_api_multi_index/test_multi_index.cpp new file mode 100644 index 00000000000..f0a3bd76384 --- /dev/null +++ b/unittests/test-contracts/test_api_multi_index/test_multi_index.cpp @@ -0,0 +1,957 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include +#include + +#include + +#include "../test_api/test_api.hpp" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + +namespace _test_multi_index { + + using eosio::checksum256; + + struct record_idx64 { + uint64_t id; + uint64_t sec; + + auto primary_key()const { return id; } + uint64_t get_secondary()const { return sec; } + + EOSLIB_SERIALIZE( record_idx64, (id)(sec) ) + }; + + struct record_idx128 { + uint64_t id; + uint128_t sec; + + auto primary_key()const { return id; } + uint128_t get_secondary()const { return sec; } + + EOSLIB_SERIALIZE( record_idx128, (id)(sec) ) + }; + + struct record_idx256 { + uint64_t id; + checksum256 sec; + + auto primary_key()const { return id; } + const checksum256& get_secondary()const { return sec; } + + EOSLIB_SERIALIZE( record_idx256, (id)(sec) ) + }; + + struct record_idx_double { + uint64_t id; + double sec; + + auto primary_key()const { return id; } + double get_secondary()const { return sec; } + + EOSLIB_SERIALIZE( record_idx_double, (id)(sec) ) + }; + + struct record_idx_long_double { + uint64_t id; + long double sec; + + auto primary_key()const { return id; } + long double get_secondary()const { return sec; } + + EOSLIB_SERIALIZE( record_idx_long_double, (id)(sec) ) + }; + + template + void idx64_store_only( uint64_t receiver ) + { + using namespace eosio; + + typedef record_idx64 record; + + record records[] = {{265, "alice"_n.value}, + {781, "bob"_n.value}, + {234, "charlie"_n.value}, + {650, "allyson"_n.value}, + {540, "bob"_n.value}, + {976, "emily"_n.value}, + {110, "joe"_n.value} + }; + size_t num_records = sizeof(records)/sizeof(records[0]); + + // Construct and fill table using multi_index + multi_index> + > table( name{receiver}, receiver ); + + auto payer = receiver; + + for ( size_t i = 0; i < num_records; ++i ) { + table.emplace( name{payer}, [&](auto& r) { + r.id = records[i].id; + r.sec = records[i].sec; + }); + } + } + + template + void idx64_check_without_storing( uint64_t receiver ) + { + using namespace eosio; + + typedef record_idx64 record; + + // Load table using multi_index + multi_index> + > table( name{receiver}, receiver ); + + auto payer = receiver; + + auto secondary_index = table.template get_index<"bysecondary"_n>(); + + // find by primary key + { + auto itr = table.find(999); + eosio_assert( itr == table.end(), "idx64_general - table.find() of non-existing primary key" ); + + itr = table.find(976); + eosio_assert( itr != table.end() && itr->sec == "emily"_n.value, "idx64_general - table.find() of existing primary key" ); + + ++itr; + eosio_assert( itr == table.end(), "idx64_general - increment primary iterator to end" ); + + itr = table.require_find(976); + eosio_assert( itr != table.end() && itr->sec == "emily"_n.value, "idx64_general - table.require_find() of existing primary key" ); + + ++itr; + eosio_assert( itr == table.end(), "idx64_general - increment primary iterator to end" ); + } + + // iterate forward starting with charlie + { + auto itr = secondary_index.lower_bound("charlie"_n.value); + eosio_assert( itr != secondary_index.end() && itr->sec == "charlie"_n.value, "idx64_general - secondary_index.lower_bound()" ); + + ++itr; + eosio_assert( itr != secondary_index.end() && itr->id == 976 && itr->sec == "emily"_n.value, "idx64_general - increment secondary iterator" ); + + ++itr; + eosio_assert( itr != secondary_index.end() && itr->id == 110 && itr->sec == "joe"_n.value, "idx64_general - increment secondary iterator again" ); + + ++itr; + eosio_assert( itr == secondary_index.end(), "idx64_general - increment secondary iterator to end" ); + } + + // iterate backward starting with second bob + { + auto pk_itr = table.find(781); + eosio_assert( pk_itr != table.end() && pk_itr->sec == "bob"_n.value, "idx64_general - table.find() of existing primary key" ); + + auto itr = secondary_index.iterator_to(*pk_itr); + eosio_assert( itr->id == 781 && itr->sec == "bob"_n.value, "idx64_general - iterator to existing object in secondary index" ); + + --itr; + eosio_assert( itr != secondary_index.end() && itr->id == 540 && itr->sec == "bob"_n.value, "idx64_general - decrement secondary iterator" ); + + --itr; + eosio_assert( itr != secondary_index.end() && itr->id == 650 && itr->sec == "allyson"_n.value, "idx64_general - decrement secondary iterator again" ); + + --itr; + eosio_assert( itr == secondary_index.begin() && itr->id == 265 && itr->sec == "alice"_n.value, "idx64_general - decrement secondary iterator to beginning" ); + } + + // iterate backward starting with emily using const_reverse_iterator + { + std::array pks{{976, 234, 781, 540, 650, 265}}; + + auto pk_itr = pks.begin(); + + auto itr = --std::make_reverse_iterator( secondary_index.find("emily"_n.value) ); + for( ; itr != secondary_index.rend(); ++itr ) { + eosio_assert( pk_itr != pks.end(), "idx64_general - unexpected continuation of secondary index in reverse iteration" ); + eosio_assert( *pk_itr == itr->id, "idx64_general - primary key mismatch in reverse iteration" ); + ++pk_itr; + } + eosio_assert( pk_itr == pks.end(), "idx64_general - did not iterate backwards through secondary index properly" ); + } + + // require_find secondary key + { + auto itr = secondary_index.require_find("bob"_n.value); + eosio_assert( itr != secondary_index.end(), "idx64_general - require_find must never return end iterator" ); + eosio_assert( itr->id == 540, "idx64_general - require_find test" ); + + ++itr; + eosio_assert( itr->id == 781, "idx64_general - require_find secondary key test" ); + } + + // modify and erase + { + const uint64_t ssn = 421; + auto new_person = table.emplace( name{payer}, [&](auto& r) { + r.id = ssn; + r.sec = "bob"_n.value; + }); + + table.modify( new_person, name{payer}, [&](auto& r) { + r.sec = "billy"_n.value; + }); + + auto itr1 = table.find(ssn); + eosio_assert( itr1 != table.end() && itr1->sec == "billy"_n.value, "idx64_general - table.modify()" ); + + table.erase(itr1); + auto itr2 = table.find(ssn); + eosio_assert( itr2 == table.end(), "idx64_general - table.erase()" ); + } + } + + template + void idx64_require_find_fail(uint64_t receiver) + { + using namespace eosio; + typedef record_idx64 record; + + // Load table using multi_index + multi_index table( name{receiver}, receiver ); + + // make sure we're looking at the right table + auto itr = table.require_find( 781, "table not loaded" ); + eosio_assert( itr != table.end(), "table not loaded" ); + + // require_find by primary key + // should fail + itr = table.require_find(999); + } + + template + void idx64_require_find_fail_with_msg(uint64_t receiver) + { + using namespace eosio; + typedef record_idx64 record; + + // Load table using multi_index + multi_index table( name{receiver}, receiver ); + + // make sure we're looking at the right table + auto itr = table.require_find( 234, "table not loaded" ); + eosio_assert( itr != table.end(), "table not loaded" ); + + // require_find by primary key + // should fail + itr = table.require_find( 335, "unable to find primary key in require_find" ); + } + + template + void idx64_require_find_sk_fail(uint64_t receiver) + { + using namespace eosio; + typedef record_idx64 record; + + // Load table using multi_index + multi_index>> table( eosio::name{receiver}, receiver ); + auto sec_index = table.template get_index<"bysecondary"_n>(); + + // make sure we're looking at the right table + auto itr = sec_index.require_find( "charlie"_n.value, "table not loaded" ); + eosio_assert( itr != sec_index.end(), "table not loaded" ); + + // require_find by secondary key + // should fail + itr = sec_index.require_find("bill"_n.value); + } + + template + void idx64_require_find_sk_fail_with_msg(uint64_t receiver) + { + using namespace eosio; + typedef record_idx64 record; + + // Load table using multi_index + multi_index>> table( eosio::name{receiver}, receiver ); + auto sec_index = table.template get_index<"bysecondary"_n>(); + + // make sure we're looking at the right table + auto itr = sec_index.require_find( "emily"_n.value, "table not loaded" ); + eosio_assert( itr != sec_index.end(), "table not loaded" ); + + // require_find by secondary key + // should fail + itr = sec_index.require_find( "frank"_n.value, "unable to find sec key" ); + } + + template + void idx128_store_only(uint64_t receiver) + { + using namespace eosio; + + typedef record_idx128 record; + + + // Construct and fill table using multi_index + multi_index> + > table( name{receiver}, receiver ); + + auto payer = receiver; + + for (uint64_t i = 0; i < 5; ++i) { + table.emplace( name{payer}, [&](auto& r) { + r.id = i; + r.sec = static_cast(1ULL << 63) * i; + }); + } + } + + template + void idx128_check_without_storing( uint64_t receiver ) + { + using namespace eosio; + + typedef record_idx128 record; + + // Load table using multi_index + multi_index> + > table( name{receiver}, receiver ); + + auto payer = receiver; + + auto secondary_index = table.template get_index<"bysecondary"_n>(); + + table.modify( table.get(3), name{payer}, [&](auto& r) { + r.sec *= 2; + }); + + { + uint128_t multiplier = 1ULL << 63; + + auto itr = secondary_index.begin(); + eosio_assert( itr->primary_key() == 0 && itr->get_secondary() == multiplier*0, "idx128_general - secondary key sort" ); + ++itr; + eosio_assert( itr->primary_key() == 1 && itr->get_secondary() == multiplier*1, "idx128_general - secondary key sort" ); + ++itr; + eosio_assert( itr->primary_key() == 2 && itr->get_secondary() == multiplier*2, "idx128_general - secondary key sort" ); + ++itr; + eosio_assert( itr->primary_key() == 4 && itr->get_secondary() == multiplier*4, "idx128_general - secondary key sort" ); + ++itr; + eosio_assert( itr->primary_key() == 3 && itr->get_secondary() == multiplier*6, "idx128_general - secondary key sort" ); + ++itr; + eosio_assert( itr == secondary_index.end(), "idx128_general - secondary key sort" ); + } + + } + + template + auto idx64_table( uint64_t receiver ) + { + using namespace eosio; + typedef record_idx64 record; + // Load table using multi_index + multi_index> + > table( name{receiver}, receiver ); + return table; + } + +} /// _test_multi_index + +void test_multi_index::idx64_store_only( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx64_store_only<"indextable1"_n.value>(receiver); +} + +void test_multi_index::idx64_check_without_storing( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx64_check_without_storing<"indextable1"_n.value>(receiver); +} + +void test_multi_index::idx64_general( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx64_store_only<"indextable2"_n.value>(receiver); + _test_multi_index::idx64_check_without_storing<"indextable2"_n.value>(receiver); +} + +void test_multi_index::idx128_store_only( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx128_store_only<"indextable3"_n.value>(receiver); +} + +void test_multi_index::idx128_check_without_storing( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx128_check_without_storing<"indextable3"_n.value>(receiver); +} + +void test_multi_index::idx128_general( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx128_store_only<"indextable4"_n.value>(receiver); + _test_multi_index::idx128_check_without_storing<"indextable4"_n.value>(receiver); +} + +void test_multi_index::idx64_require_find_fail( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx64_store_only<"indextable5"_n.value>(receiver); + _test_multi_index::idx64_require_find_fail<"indextable5"_n.value>(receiver); +} + +void test_multi_index::idx64_require_find_fail_with_msg( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx64_store_only<"indextablea"_n.value>(receiver); // Making the name smaller fixes this? + _test_multi_index::idx64_require_find_fail_with_msg<"indextablea"_n.value>(receiver); // Making the name smaller fixes this? +} + +void test_multi_index::idx64_require_find_sk_fail( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx64_store_only<"indextableb"_n.value>(receiver); + _test_multi_index::idx64_require_find_sk_fail<"indextableb"_n.value>(receiver); +} + +void test_multi_index::idx64_require_find_sk_fail_with_msg( uint64_t receiver, uint64_t code, uint64_t action ) +{ + _test_multi_index::idx64_store_only<"indextablec"_n.value>(receiver); + _test_multi_index::idx64_require_find_sk_fail_with_msg<"indextablec"_n.value>(receiver); +} + +void test_multi_index::idx128_autoincrement_test( uint64_t receiver, uint64_t code, uint64_t action ) +{ + using namespace eosio; + using namespace _test_multi_index; + + typedef record_idx128 record; + + const uint64_t table_name = "autoinctbl1"_n.value; + auto payer = receiver; + + multi_index> + > table( name{receiver}, receiver ); + + for( int i = 0; i < 5; ++i ) { + table.emplace( name{payer}, [&](auto& r) { + r.id = table.available_primary_key(); + r.sec = 1000 - static_cast(r.id); + }); + } + + uint64_t expected_key = 4; + for( const auto& r : table.get_index<"bysecondary"_n>() ) + { + eosio_assert( r.primary_key() == expected_key, "idx128_autoincrement_test - unexpected primary key" ); + --expected_key; + } + eosio_assert( expected_key == static_cast(-1), "idx128_autoincrement_test - did not iterate through secondary index properly" ); + + auto itr = table.find(3); + eosio_assert( itr != table.end(), "idx128_autoincrement_test - could not find object with primary key of 3" ); + + // The modification below would trigger an error: + /* + table.modify(itr, payer, [&](auto& r) { + r.id = 100; + }); + */ + + table.emplace( name{payer}, [&](auto& r) { + r.id = 100; + r.sec = itr->sec; + }); + table.erase(itr); + + eosio_assert( table.available_primary_key() == 101, "idx128_autoincrement_test - next_primary_key was not correct after record modify" ); +} + +void test_multi_index::idx128_autoincrement_test_part1( uint64_t receiver, uint64_t code, uint64_t action ) +{ + using namespace eosio; + using namespace _test_multi_index; + + typedef record_idx128 record; + + const uint64_t table_name = "autoinctbl2"_n.value; + auto payer = receiver; + + multi_index> + > table( name{receiver}, receiver ); + + for( int i = 0; i < 3; ++i ) { + table.emplace( name{payer}, [&](auto& r) { + r.id = table.available_primary_key(); + r.sec = 1000 - static_cast(r.id); + }); + } + + table.erase(table.get(0)); + + uint64_t expected_key = 2; + for( const auto& r : table.get_index<"bysecondary"_n>() ) + { + eosio_assert( r.primary_key() == expected_key, "idx128_autoincrement_test_part1 - unexpected primary key" ); + --expected_key; + } + eosio_assert( expected_key == 0, "idx128_autoincrement_test_part1 - did not iterate through secondary index properly" ); + +} + +void test_multi_index::idx128_autoincrement_test_part2( uint64_t receiver, uint64_t code, uint64_t action ) +{ + using namespace eosio; + using namespace _test_multi_index; + + typedef record_idx128 record; + + const uint64_t table_name = "autoinctbl2"_n.value; + auto payer = receiver; + + { + multi_index> + > table( name{receiver}, receiver ); + + eosio_assert( table.available_primary_key() == 3, "idx128_autoincrement_test_part2 - did not recover expected next primary key" ); + } + + multi_index> + > table( name{receiver}, receiver ); + + table.emplace( name{payer}, [&](auto& r) { + r.id = 0; + r.sec = 1000; + }); + // Done this way to make sure that table._next_primary_key is not incorrectly set to 1. + + for( int i = 3; i < 5; ++i ) { + table.emplace( name{payer}, [&](auto& r) { + auto itr = table.available_primary_key(); + r.id = itr; + r.sec = 1000 - static_cast(r.id); + }); + } + + uint64_t expected_key = 4; + for( const auto& r : table.get_index<"bysecondary"_n>() ) + { + eosio_assert( r.primary_key() == expected_key, "idx128_autoincrement_test_part2 - unexpected primary key" ); + --expected_key; + } + eosio_assert( expected_key == static_cast(-1), "idx128_autoincrement_test_part2 - did not iterate through secondary index properly" ); + + auto itr = table.find(3); + eosio_assert( itr != table.end(), "idx128_autoincrement_test_part2 - could not find object with primary key of 3" ); + + table.emplace( name{payer}, [&](auto& r) { + r.id = 100; + r.sec = itr->sec; + }); + table.erase(itr); + + eosio_assert( table.available_primary_key() == 101, "idx128_autoincrement_test_part2 - next_primary_key was not correct after record update" ); +} + +void test_multi_index::idx256_general( uint64_t receiver, uint64_t code, uint64_t action ) +{ + using namespace eosio; + using namespace _test_multi_index; + + typedef record_idx256 record; + + const uint64_t table_name = "indextable5"_n.value; + auto payer = receiver; + + print("Testing checksum256 secondary index.\n"); + multi_index> + > table( name{receiver}, receiver ); + + auto fourtytwo = checksum256::make_from_word_sequence( 0ULL, 0ULL, 0ULL, 42ULL ); + //auto onetwothreefour = checksum256::make_from_word_sequence(1ULL, 2ULL, 3ULL, 4ULL); + auto onetwothreefour = checksum256{std::array{ {0,1, 0,2, 0,3, 0,4} }}; + + table.emplace( name{payer}, [&](auto& o) { + o.id = 1; + o.sec = fourtytwo; + }); + + table.emplace( name{payer}, [&](auto& o) { + o.id = 2; + o.sec = onetwothreefour; + }); + + table.emplace( name{payer}, [&](auto& o) { + o.id = 3; + o.sec = fourtytwo; + }); + + auto e = table.find(2); + + print("Items sorted by primary key:\n"); + for( const auto& item : table ) { + print(" ID=", item.primary_key(), ", secondary=", item.sec, "\n"); + } + + { + auto itr = table.begin(); + eosio_assert( itr->primary_key() == 1 && itr->get_secondary() == fourtytwo, "idx256_general - primary key sort" ); + ++itr; + eosio_assert( itr->primary_key() == 2 && itr->get_secondary() == onetwothreefour, "idx256_general - primary key sort" ); + ++itr; + eosio_assert( itr->primary_key() == 3 && itr->get_secondary() == fourtytwo, "idx256_general - primary key sort" ); + ++itr; + eosio_assert( itr == table.end(), "idx256_general - primary key sort" ); + } + + auto secidx = table.get_index<"bysecondary"_n>(); + + auto lower1 = secidx.lower_bound( checksum256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 40ULL) ); + print("First entry with a secondary key of at least 40 has ID=", lower1->id, ".\n"); + eosio_assert( lower1->id == 1, "idx256_general - lower_bound" ); + + auto lower2 = secidx.lower_bound( checksum256::make_from_word_sequence(0ULL, 0ULL, 0ULL, 50ULL) ); + print("First entry with a secondary key of at least 50 has ID=", lower2->id, ".\n"); + eosio_assert( lower2->id == 2, "idx256_general - lower_bound" ); + + if( table.iterator_to(*lower2) == e ) { + print("Previously found entry is the same as the one found earlier with a primary key value of 2.\n"); + } + + print("Items sorted by secondary key (checksum256):\n"); + for( const auto& item : secidx ) { + print(" ID=", item.primary_key(), ", secondary=", item.sec, "\n"); + } + + { + auto itr = secidx.begin(); + eosio_assert( itr->primary_key() == 1, "idx256_general - secondary key sort" ); + ++itr; + eosio_assert( itr->primary_key() == 3, "idx256_general - secondary key sort" ); + ++itr; + eosio_assert( itr->primary_key() == 2, "idx256_general - secondary key sort" ); + ++itr; + eosio_assert( itr == secidx.end(), "idx256_general - secondary key sort" ); + } + + auto upper = secidx.upper_bound( checksum256{std::array{{0, 0, 0, 42}}} ); + + print("First entry with a secondary key greater than 42 has ID=", upper->id, ".\n"); + eosio_assert( upper->id == 2, "idx256_general - upper_bound" ); + eosio_assert( upper->id == secidx.get(onetwothreefour).id, "idx256_general - secondary index get" ); + + print("Removed entry with ID=", lower1->id, ".\n"); + secidx.erase( lower1 ); + + print("Items reverse sorted by primary key:\n"); + for( const auto& item : boost::make_iterator_range(table.rbegin(), table.rend()) ) { + print(" ID=", item.primary_key(), ", secondary=", item.sec, "\n"); + } + + { + auto itr = table.rbegin(); + eosio_assert( itr->primary_key() == 3 && itr->get_secondary() == fourtytwo, "idx256_general - primary key sort after remove" ); + ++itr; + eosio_assert( itr->primary_key() == 2 && itr->get_secondary() == onetwothreefour, "idx256_general - primary key sort after remove" ); + ++itr; + eosio_assert( itr == table.rend(), "idx256_general - primary key sort after remove" ); + } +} + +void test_multi_index::idx_double_general( uint64_t receiver, uint64_t code, uint64_t action ) +{ + using namespace eosio; + using namespace _test_multi_index; + + typedef record_idx_double record; + + const uint64_t table_name = "floattable1"_n.value; + auto payer = receiver; + + print("Testing double secondary index.\n"); + multi_index> + > table( name{receiver}, receiver ); + + auto secidx = table.get_index<"bysecondary"_n>(); + + double tolerance = std::numeric_limits::epsilon(); + print("tolerance = ", tolerance, "\n"); + + for( uint64_t i = 1; i <= 10; ++i ) { + table.emplace( name{payer}, [&]( auto& o ) { + o.id = i; + o.sec = 1.0 / (i * 1000000.0); + }); + } + + double expected_product = 1.0 / 1000000.0; + print( "expected_product = ", expected_product, "\n" ); + + uint64_t expected_key = 10; + for( const auto& obj : secidx ) { + eosio_assert( obj.primary_key() == expected_key, "idx_double_general - unexpected primary key" ); + + double prod = obj.sec * obj.id; + + print(" id = ", obj.id, ", sec = ", obj.sec, ", sec * id = ", prod, "\n"); + + eosio_assert( std::abs(prod - expected_product) <= tolerance, + "idx_double_general - product of secondary and id not equal to expected_product within tolerance" ); + + --expected_key; + } + eosio_assert( expected_key == 0, "idx_double_general - did not iterate through secondary index properly" ); + + { + auto itr = secidx.lower_bound( expected_product / 5.5 ); + eosio_assert( std::abs(1.0 / itr->sec - 5000000.0) <= tolerance, "idx_double_general - lower_bound" ); + + itr = secidx.upper_bound( expected_product / 5.0 ); + eosio_assert( std::abs(1.0 / itr->sec - 4000000.0) <= tolerance, "idx_double_general - upper_bound" ); + + } +} + +void test_multi_index::idx_long_double_general( uint64_t receiver, uint64_t code, uint64_t action ) +{ + using namespace eosio; + using namespace _test_multi_index; + + typedef record_idx_long_double record; + + const uint64_t table_name = "floattable2"_n.value; + auto payer = receiver; + + print("Testing long double secondary index.\n"); + multi_index> + > table( name{receiver}, receiver ); + + auto secidx = table.get_index<"bysecondary"_n>(); + + long double tolerance = std::min( static_cast(std::numeric_limits::epsilon()), + std::numeric_limits::epsilon() * 1e7l ); + print("tolerance = ", tolerance, "\n"); + + long double f = 1.0l; + for( uint64_t i = 1; i <= 10; ++i, f += 1.0l ) { + table.emplace( name{payer}, [&](auto& o) { + o.id = i; + o.sec = 1.0l / (i * 1000000.0l); + }); + } + + long double expected_product = 1.0l / 1000000.0l; + print( "expected_product = ", expected_product, "\n" ); + + uint64_t expected_key = 10; + for( const auto& obj : secidx ) { + eosio_assert( obj.primary_key() == expected_key, "idx_long_double_general - unexpected primary key" ); + + long double prod = obj.sec * obj.id; + + print(" id = ", obj.id, ", sec = ", obj.sec, ", sec * id = ", prod, "\n"); + + eosio_assert( std::abs(prod - expected_product) <= tolerance, + "idx_long_double_general - product of secondary and id not equal to expected_product within tolerance" ); + + --expected_key; + } + eosio_assert( expected_key == 0, "idx_long_double_general - did not iterate through secondary index properly" ); + + { + auto itr = secidx.lower_bound( expected_product / 5.5l ); + eosio_assert( std::abs(1.0l / itr->sec - 5000000.0l) <= tolerance, "idx_long_double_general - lower_bound" ); + + itr = secidx.upper_bound( expected_product / 5.0l ); + eosio_assert( std::abs(1.0l / itr->sec - 4000000.0l) <= tolerance, "idx_long_double_general - upper_bound" ); + + } +} + +void test_multi_index::idx64_pk_iterator_exceed_end( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto end_itr = table.end(); + // Should fail + ++end_itr; +} + +void test_multi_index::idx64_sk_iterator_exceed_end( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto end_itr = table.get_index<"bysecondary"_n>().end(); + // Should fail + ++end_itr; +} + +void test_multi_index::idx64_pk_iterator_exceed_begin( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto begin_itr = table.begin(); + // Should fail + --begin_itr; +} + +void test_multi_index::idx64_sk_iterator_exceed_begin( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto begin_itr = table.get_index<"bysecondary"_n>().begin(); + // Should fail + --begin_itr; +} + +void test_multi_index::idx64_pass_pk_ref_to_other_table( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table1 = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto table2 = _test_multi_index::idx64_table<"indextable2"_n.value, "bysecondary"_n.value>(receiver); + + auto table1_pk_itr = table1.find(781); + eosio_assert( table1_pk_itr != table1.end() && table1_pk_itr->sec == "bob"_n.value, "idx64_pass_pk_ref_to_other_table - table.find() of existing primary key" ); + + // Should fail + table2.iterator_to(*table1_pk_itr); +} + +void test_multi_index::idx64_pass_sk_ref_to_other_table( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table1 = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto table2 = _test_multi_index::idx64_table<"indextable2"_n.value, "bysecondary"_n.value>(receiver); + + auto table1_pk_itr = table1.find(781); + eosio_assert( table1_pk_itr != table1.end() && table1_pk_itr->sec == "bob"_n.value, "idx64_pass_sk_ref_to_other_table - table.find() of existing primary key" ); + + auto table2_sec_index = table2.get_index<"bysecondary"_n>(); + // Should fail + table2_sec_index.iterator_to(*table1_pk_itr); +} + +void test_multi_index::idx64_pass_pk_end_itr_to_iterator_to( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto end_itr = table.end(); + // Should fail + table.iterator_to(*end_itr); +} + +void test_multi_index::idx64_pass_pk_end_itr_to_modify( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto end_itr = table.end(); + + auto payer = receiver; + // Should fail + table.modify( end_itr, eosio::name{payer}, [](auto&){} ); +} + +void test_multi_index::idx64_pass_pk_end_itr_to_erase( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto end_itr = table.end(); + + // Should fail + table.erase(end_itr); +} + +void test_multi_index::idx64_pass_sk_end_itr_to_iterator_to( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto sec_index = table.get_index<"bysecondary"_n>(); + auto end_itr = sec_index.end(); + + // Should fail + sec_index.iterator_to(*end_itr); +} + +void test_multi_index::idx64_pass_sk_end_itr_to_modify( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto sec_index = table.get_index<"bysecondary"_n>(); + auto end_itr = sec_index.end(); + + auto payer = receiver; + // Should fail + sec_index.modify( end_itr, eosio::name{payer}, [](auto&){} ); +} + + +void test_multi_index::idx64_pass_sk_end_itr_to_erase( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + auto sec_index = table.get_index<"bysecondary"_n>(); + auto end_itr = sec_index.end(); + + // Should fail + sec_index.erase(end_itr); +} + +void test_multi_index::idx64_modify_primary_key( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + + auto pk_itr = table.find(781); + eosio_assert( pk_itr != table.end() && pk_itr->sec == "bob"_n.value, "idx64_modify_primary_key - table.find() of existing primary key" ); + + auto payer = receiver; + + // Should fail + table.modify( pk_itr, eosio::name{payer}, [](auto& r){ + r.id = 1100; + }); +} + +void test_multi_index::idx64_run_out_of_avl_pk( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + + auto pk_itr = table.find(781); + eosio_assert( pk_itr != table.end() && pk_itr->sec == "bob"_n.value, "idx64_modify_primary_key - table.find() of existing primary key" ); + + auto payer = receiver; + + table.emplace( eosio::name{payer}, [&](auto& r) { + r.id = static_cast(-4); + r.sec = "alice"_n.value; + }); + eosio_assert( table.available_primary_key() == static_cast(-3), "idx64_run_out_of_avl_pk - incorrect available primary key" ); + + table.emplace( eosio::name{payer}, [&](auto& r) { + r.id = table.available_primary_key(); + r.sec = "bob"_n.value; + }); + + // Should fail + table.available_primary_key(); +} + +void test_multi_index::idx64_sk_cache_pk_lookup( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + + auto sec_index = table.get_index<"bysecondary"_n>(); + auto sk_itr = sec_index.find("bob"_n.value); + eosio_assert( sk_itr != sec_index.end() && sk_itr->id == 540, "idx64_sk_cache_pk_lookup - sec_index.find() of existing secondary key" ); + + auto pk_itr = table.iterator_to(*sk_itr); + auto prev_itr = --pk_itr; + eosio_assert( prev_itr->id == 265 && prev_itr->sec == "alice"_n.value, "idx64_sk_cache_pk_lookup - previous record" ); +} + +void test_multi_index::idx64_pk_cache_sk_lookup( uint64_t receiver, uint64_t code, uint64_t action ) +{ + auto table = _test_multi_index::idx64_table<"indextable1"_n.value, "bysecondary"_n.value>(receiver); + + + auto pk_itr = table.find(540); + eosio_assert( pk_itr != table.end() && pk_itr->sec == "bob"_n.value, "idx64_pk_cache_sk_lookup - table.find() of existing primary key" ); + + auto sec_index = table.get_index<"bysecondary"_n>(); + auto sk_itr = sec_index.iterator_to(*pk_itr); + auto next_itr = ++sk_itr; + eosio_assert( next_itr->id == 781 && next_itr->sec == "bob"_n.value, "idx64_pk_cache_sk_lookup - next record" ); +} + +#pragma GCC diagnostic pop diff --git a/unittests/test-contracts/test_ram_limit/CMakeLists.txt b/unittests/test-contracts/test_ram_limit/CMakeLists.txt new file mode 100644 index 00000000000..2520fb59bcc --- /dev/null +++ b/unittests/test-contracts/test_ram_limit/CMakeLists.txt @@ -0,0 +1,8 @@ +if( ${eosio.cdt_FOUND} ) + message(STATUS "Not building test_ram_limit, read README.txt in eos/unittests/test-contracts/test_ram_limit") + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test_ram_limit.wasm ${CMAKE_CURRENT_BINARY_DIR}/test_ram_limit.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test_ram_limit.abi ${CMAKE_CURRENT_BINARY_DIR}/test_ram_limit.abi COPYONLY ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test_ram_limit.wasm ${CMAKE_CURRENT_BINARY_DIR}/test_ram_limit.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test_ram_limit.abi ${CMAKE_CURRENT_BINARY_DIR}/test_ram_limit.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/test_ram_limit/test_ram_limit.abi b/unittests/test-contracts/test_ram_limit/test_ram_limit.abi new file mode 100644 index 00000000000..0874a7cb964 --- /dev/null +++ b/unittests/test-contracts/test_ram_limit/test_ram_limit.abi @@ -0,0 +1,100 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Dec 7 11:56:43 2018", + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "printentry", + "base": "", + "fields": [ + { + "name": "from", + "type": "uint64" + }, + { + "name": "to", + "type": "uint64" + } + ] + }, + { + "name": "rmentry", + "base": "", + "fields": [ + { + "name": "from", + "type": "uint64" + }, + { + "name": "to", + "type": "uint64" + } + ] + }, + { + "name": "setentry", + "base": "", + "fields": [ + { + "name": "payer", + "type": "name" + }, + { + "name": "from", + "type": "uint64" + }, + { + "name": "to", + "type": "uint64" + }, + { + "name": "size", + "type": "uint64" + } + ] + }, + { + "name": "test", + "base": "", + "fields": [ + { + "name": "key", + "type": "uint64" + }, + { + "name": "data", + "type": "bytes" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "printentry", + "type": "printentry", + "ricardian_contract": "" + }, + { + "name": "rmentry", + "type": "rmentry", + "ricardian_contract": "" + }, + { + "name": "setentry", + "type": "setentry", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "test.table", + "type": "test", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} diff --git a/contracts/test_ram_limit/test_ram_limit.cpp b/unittests/test-contracts/test_ram_limit/test_ram_limit.cpp similarity index 52% rename from contracts/test_ram_limit/test_ram_limit.cpp rename to unittests/test-contracts/test_ram_limit/test_ram_limit.cpp index c162cea6585..0bc9c72c052 100644 --- a/contracts/test_ram_limit/test_ram_limit.cpp +++ b/unittests/test-contracts/test_ram_limit/test_ram_limit.cpp @@ -5,69 +5,66 @@ #include #include #include + #include -#include #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wsign-conversion" #pragma clang diagnostic ignored "-Wshorten-64-to-32" #pragma clang diagnostic ignored "-Wsign-compare" -class test_ram_limit : public eosio::contract { +using namespace eosio; + +CONTRACT test_ram_limit : public contract { public: + using contract::contract; + const uint32_t FIVE_MINUTES = 5*60; - test_ram_limit(account_name self) - :eosio::contract(self) - {} - - //@abi action - void setentry(account_name payer, uint64_t from, uint64_t to, uint64_t size) { + ACTION setentry( name payer, uint64_t from, uint64_t to, uint64_t size ) { const auto self = get_self(); eosio::print("test_ram_limit::setentry ", eosio::name{self}, "\n"); - test_table table(self, self); - for (int key = from; key <=to; ++key) { + test_table table( self, self.value ); + for ( int key = from; key <=to; ++key ) { auto itr = table.find(key); - if (itr != table.end()) { - table.modify(itr, payer, [size](test& t) { - t.data.assign(size, (int8_t)size); + if ( itr != table.end() ) { + table.modify( itr, payer, [size](test& t) { + t.data.assign( size, (int8_t)size ); }); } else { - table.emplace(payer, [key,size](test& t) { + table.emplace( payer, [key,size](test& t) { t.key = key; - t.data.assign(size, (int8_t)size); + t.data.assign( size, (int8_t)size ); }); } } } - //@abi action - void rmentry(uint64_t from, uint64_t to) { + ACTION rmentry( uint64_t from, uint64_t to ) { const auto self = get_self(); eosio::print("test_ram_limit::rmentry ", eosio::name{self}, "\n"); - test_table table(self, self); - for (int key = from; key <=to; ++key) { + test_table table( self, self.value ); + for ( int key = from; key <=to; ++key ) { auto itr = table.find(key); - eosio_assert (itr != table.end(), "could not find test_table entry"); + eosio_assert ( itr != table.end(), "could not find test_table entry" ); table.erase(itr); } } - //@abi action - void printentry(uint64_t from, uint64_t to) { + ACTION printentry( uint64_t from, uint64_t to ) { const auto self = get_self(); eosio::print("test_ram_limit::printout ", eosio::name{self}, ":"); - test_table table(self, self); - for (int key = from; key <=to; ++key) { + test_table table( self, self.value ); + for ( int key = from; key <= to; ++key ) { auto itr = table.find(key); eosio::print("\nkey=", key); - eosio_assert (itr != table.end(), "could not find test_table entry"); + eosio_assert ( itr != table.end(), "could not find test_table entry" ); eosio::print(" size=", itr->data.size()); } } private: - struct test { + TABLE test { uint64_t key; std::vector data; @@ -75,9 +72,9 @@ class test_ram_limit : public eosio::contract { EOSLIB_SERIALIZE( test, (key)(data) ) }; - typedef eosio::multi_index< N(test.table), test> test_table; + typedef eosio::multi_index< "test.table"_n, test> test_table; }; #pragma clang diagnostic pop -EOSIO_ABI( test_ram_limit, (setentry)(rmentry)(printentry) ) +EOSIO_DISPATCH( test_ram_limit, (setentry)(rmentry)(printentry) ) diff --git a/unittests/test-contracts/test_ram_limit/test_ram_limit.wasm b/unittests/test-contracts/test_ram_limit/test_ram_limit.wasm new file mode 100644 index 00000000000..94f25bde89c Binary files /dev/null and b/unittests/test-contracts/test_ram_limit/test_ram_limit.wasm differ diff --git a/unittests/tic_tac_toe_tests.cpp b/unittests/tic_tac_toe_tests.cpp deleted file mode 100644 index 939b4e203c5..00000000000 --- a/unittests/tic_tac_toe_tests.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-compare" -#include -#pragma GCC diagnostic pop -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#ifdef NON_VALIDATING_TEST -#define TESTER tester -#else -#define TESTER validating_tester -#endif - -using namespace eosio; -using namespace eosio::chain; -using namespace eosio::testing; -using namespace fc; - -const static uint32_t board_len = 9; -struct game { - account_name challenger; - account_name host; - account_name turn; // = account name of host/ challenger - account_name winner = N(none); // = none/ draw/ account name of host/ challenger - uint8_t board[board_len]; -}; -FC_REFLECT(game, (challenger)(host)(turn)(winner)(board)); - - -struct ttt_tester : TESTER { - void get_game(game& game, account_name scope, account_name key) { - auto* maybe_tid = find_table(N(tic.tac.toe), scope, N(games)); - if(maybe_tid == nullptr) - BOOST_FAIL("table for code=\"tic.tac.toe\" scope=\"" + scope.to_string() + "\" table=\"games\" does not exist"); - - auto* o = control->db().find(boost::make_tuple(maybe_tid->id, key)); - if(o == nullptr) - BOOST_FAIL("game for does not exist for challenger=\"" + key.to_string() + "\""); - - fc::raw::unpack(o->value.data(), o->value.size(), game); - } -}; - -BOOST_AUTO_TEST_SUITE(tic_tac_toe_tests) - -BOOST_AUTO_TEST_CASE( tic_tac_toe_game ) try { - TESTER chain; - abi_serializer abi_ser{json::from_string(tic_tac_toe_abi).as(), chain.abi_serializer_max_time}; - chain.create_account(N(tic.tac.toe)); - chain.produce_blocks(10); - - chain.set_code(N(tic.tac.toe), tic_tac_toe_wast); - chain.set_abi(N(tic.tac.toe), tic_tac_toe_abi); - - chain.produce_blocks(); - chain.create_account(N(player1)); - chain.create_account(N(player2)); - chain.produce_blocks(10); - - chain.push_action(N(tic.tac.toe), N(create), N(player1), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ); - - chain.produce_blocks(); - - chain.push_action(N(tic.tac.toe), N(move), N(player1), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player1") - ("row", 1) - ("column", 1) - ); - - BOOST_CHECK_EXCEPTION(chain.push_action(N(tic.tac.toe), N(move), N(player1), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player1") - ("row", 0) - ("column", 1) - ), eosio_assert_message_exception, eosio_assert_message_starts_with("it's not your turn yet")); - - BOOST_CHECK_EXCEPTION(chain.push_action(N(tic.tac.toe), N(move), N(player2), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player2") - ("row", 1) - ("column", 1) - ), eosio_assert_message_exception, eosio_assert_message_starts_with("not a valid movement")); - - chain.push_action(N(tic.tac.toe), N(move), N(player2), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player2") - ("row", 0) - ("column", 1) - ); - - chain.push_action(N(tic.tac.toe), N(move), N(player1), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player1") - ("row", 0) - ("column", 0 ) - ); - - chain.push_action(N(tic.tac.toe), N(move), N(player2), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player2") - ("row", 0) - ("column", 2) - ); - - chain.push_action(N(tic.tac.toe), N(move), N(player1), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player1") - ("row", 2) - ("column", 2) - ); - - BOOST_CHECK_EXCEPTION(chain.push_action(N(tic.tac.toe), N(move), N(player2), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player2") - ("row", 2) - ("column", 0) - ), eosio_assert_message_exception, eosio_assert_message_starts_with("the game has ended")); - - game current; - chain.get_table_entry(current, N(tic.tac.toe), N(player1), N(games), N(player2)); - BOOST_REQUIRE_EQUAL("player1", account_name(current.winner).to_string()); - - chain.push_action(N(tic.tac.toe), N(close), N(player1), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ); - - BOOST_CHECK_EXCEPTION(chain.push_action(N(tic.tac.toe), N(move), N(player2), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player2") - ("row", 2) - ("column", 0) - ), eosio_assert_message_exception, eosio_assert_message_starts_with("game doesn't exists")); - - BOOST_CHECK_EXCEPTION(chain.push_action(N(tic.tac.toe), N(restart), N(player2), mutable_variant_object() - ("challenger", "player2") - ("host", "player1") - ("by", "player2") - ), eosio_assert_message_exception, eosio_assert_message_starts_with("game doesn't exists")); - - chain.push_action(N(tic.tac.toe), N(create), N(player2), mutable_variant_object() - ("challenger", "player1") - ("host", "player2") - ); - - chain.push_action(N(tic.tac.toe), N(restart), N(player1), mutable_variant_object() - ("challenger", "player1") - ("host", "player2") - ("by", "player1") - ); - - // making a move and ... - chain.push_action(N(tic.tac.toe), N(move), N(player2), mutable_variant_object() - ("challenger", "player1") - ("host", "player2") - ("by", "player2") - ("row", 1) - ("column", 1) - ); - - // ... repeating to get exception to ensure restart above actually did something - BOOST_CHECK_EXCEPTION(chain.push_action(N(tic.tac.toe), N(move), N(player2), mutable_variant_object() - ("challenger", "player1") - ("host", "player2") - ("by", "player2") - ("row", 0) - ("column", 1) - ), eosio_assert_message_exception, eosio_assert_message_starts_with("it's not your turn yet")); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/wasm_tests.cpp b/unittests/wasm_tests.cpp index 101786588af..ce351e2042c 100644 --- a/unittests/wasm_tests.cpp +++ b/unittests/wasm_tests.cpp @@ -1,35 +1,31 @@ -#include -#include +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include +#include -#include #include -#include -#include #include +#include +#include #include -#include -#include +#include -#include -#include +#include -#include -#include +#include +#include #include - -#include - -#include #include +#include +#include "incbin.h" #include "test_wasts.hpp" #include "test_softfloat_wasts.hpp" -#include -#include - -#include "incbin.h" +#include #ifdef NON_VALIDATING_TEST #define TESTER tester @@ -81,7 +77,7 @@ BOOST_FIXTURE_TEST_CASE( basic_test, TESTER ) try { create_accounts( {N(asserter)} ); produce_block(); - set_code(N(asserter), asserter_wast); + set_code(N(asserter), contracts::asserter_wasm()); produce_blocks(1); transaction_id_type no_assert_id; @@ -140,7 +136,7 @@ BOOST_FIXTURE_TEST_CASE( prove_mem_reset, TESTER ) try { create_accounts( {N(asserter)} ); produce_block(); - set_code(N(asserter), asserter_wast); + set_code(N(asserter), contracts::asserter_wasm()); produce_blocks(1); // repeat the action multiple times, each time the action handler checks for the expected @@ -170,8 +166,8 @@ BOOST_FIXTURE_TEST_CASE( abi_from_variant, TESTER ) try { create_accounts( {N(asserter)} ); produce_block(); - set_code(N(asserter), asserter_wast); - set_abi(N(asserter), asserter_abi); + set_code(N(asserter), contracts::asserter_wasm()); + set_abi(N(asserter), contracts::asserter_abi().data()); produce_blocks(1); auto resolver = [&,this]( const account_name& name ) -> optional { @@ -689,45 +685,6 @@ BOOST_FIXTURE_TEST_CASE( check_global_reset, TESTER ) try { BOOST_CHECK_EQUAL(transaction_receipt::executed, receipt.status); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE( stl_test, TESTER ) try { - produce_blocks(2); - - create_accounts( {N(stltest), N(alice), N(bob)} ); - produce_block(); - - set_code(N(stltest), stltest_wast); - set_abi(N(stltest), stltest_abi); - produce_blocks(1); - - const auto& accnt = control->db().get( N(stltest) ); - abi_def abi; - BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - abi_serializer abi_ser(abi, abi_serializer_max_time); - - //send message - { - signed_transaction trx; - action msg_act; - msg_act.account = N(stltest); - msg_act.name = N(message); - msg_act.authorization = {{N(stltest), config::active_name}}; - msg_act.data = abi_ser.variant_to_binary("message", mutable_variant_object() - ("from", "bob") - ("to", "alice") - ("message","Hi Alice!"), - abi_serializer_max_time - ); - trx.actions.push_back(std::move(msg_act)); - - set_transaction_headers(trx); - trx.sign(get_private_key(N(stltest), "active"), control->get_chain_id()); - push_transaction(trx); - produce_block(); - - BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id())); - } -} FC_LOG_AND_RETHROW() /// stltest - //Make sure we can create a wasm with maximum pages, but not grow it any BOOST_FIXTURE_TEST_CASE( big_memory, TESTER ) try { produce_blocks(2); @@ -1012,9 +969,9 @@ BOOST_FIXTURE_TEST_CASE(noop, TESTER) try { create_accounts( {N(noop), N(alice)} ); produce_block(); - set_code(N(noop), noop_wast); + set_code(N(noop), contracts::noop_wasm()); - set_abi(N(noop), noop_abi); + set_abi(N(noop), contracts::noop_abi().data()); const auto& accnt = control->db().get(N(noop)); abi_def abi; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); @@ -1824,6 +1781,29 @@ BOOST_FIXTURE_TEST_CASE( getcode_checks, TESTER ) try { wasm_to_wast( wasmx.data(), wasmx.size(), true ); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE( big_maligned_host_ptr, TESTER ) try { + produce_blocks(2); + create_accounts( {N(bigmaligned)} ); + produce_block(); + + string large_maligned_host_ptr_wast_f = fc::format_string(large_maligned_host_ptr, fc::mutable_variant_object() + ("MAX_WASM_PAGES", eosio::chain::wasm_constraints::maximum_linear_memory/(64*1024)) + ("MAX_NAME_ARRAY", (eosio::chain::wasm_constraints::maximum_linear_memory-1)/sizeof(chain::account_name))); + + set_code(N(bigmaligned), large_maligned_host_ptr_wast_f.c_str()); + produce_blocks(1); + + signed_transaction trx; + action act; + act.account = N(bigmaligned); + act.name = N(); + act.authorization = vector{{N(bigmaligned),config::active_name}}; + trx.actions.push_back(act); + set_transaction_headers(trx); + trx.sign(get_private_key( N(bigmaligned), "active" ), control->get_chain_id()); + push_transaction(trx); + produce_blocks(1); +} FC_LOG_AND_RETHROW() // TODO: restore net_usage_tests #if 0 diff --git a/unittests/whitelist_blacklist_tests.cpp b/unittests/whitelist_blacklist_tests.cpp index 54b011d0e3d..d0f57fcb61a 100644 --- a/unittests/whitelist_blacklist_tests.cpp +++ b/unittests/whitelist_blacklist_tests.cpp @@ -1,16 +1,16 @@ -#include +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include #include #include -#include - #include -#include -#include +#include -#include -#include +#include #ifdef NON_VALIDATING_TEST #define TESTER tester @@ -70,8 +70,8 @@ class whitelist_blacklist_tester { if( !bootstrap ) return; chain->create_accounts({N(eosio.token), N(alice), N(bob), N(charlie)}); - chain->set_code(N(eosio.token), eosio_token_wast); - chain->set_abi(N(eosio.token), eosio_token_abi); + chain->set_code(N(eosio.token), contracts::eosio_token_wasm() ); + chain->set_abi(N(eosio.token), contracts::eosio_token_abi().data() ); chain->push_action( N(eosio.token), N(create), N(eosio.token), mvo() ( "issuer", "eosio.token" ) ( "maximum_supply", "1000000.00 TOK" ) @@ -206,13 +206,13 @@ BOOST_AUTO_TEST_CASE( contract_whitelist ) { try { test.chain->produce_blocks(); - test.chain->set_code(N(bob), eosio_token_wast); - test.chain->set_abi(N(bob), eosio_token_abi); + test.chain->set_code(N(bob), contracts::eosio_token_wasm() ); + test.chain->set_abi(N(bob), contracts::eosio_token_abi().data() ); test.chain->produce_blocks(); - test.chain->set_code(N(charlie), eosio_token_wast); - test.chain->set_abi(N(charlie), eosio_token_abi); + test.chain->set_code(N(charlie), contracts::eosio_token_wasm() ); + test.chain->set_abi(N(charlie), contracts::eosio_token_abi().data() ); test.chain->produce_blocks(); @@ -255,13 +255,13 @@ BOOST_AUTO_TEST_CASE( contract_blacklist ) { try { test.chain->produce_blocks(); - test.chain->set_code(N(bob), eosio_token_wast); - test.chain->set_abi(N(bob), eosio_token_abi); + test.chain->set_code(N(bob), contracts::eosio_token_wasm() ); + test.chain->set_abi(N(bob), contracts::eosio_token_abi().data() ); test.chain->produce_blocks(); - test.chain->set_code(N(charlie), eosio_token_wast); - test.chain->set_abi(N(charlie), eosio_token_abi); + test.chain->set_code(N(charlie), contracts::eosio_token_wasm() ); + test.chain->set_abi(N(charlie), contracts::eosio_token_abi().data() ); test.chain->produce_blocks(); @@ -298,13 +298,13 @@ BOOST_AUTO_TEST_CASE( action_blacklist ) { try { test.chain->produce_blocks(); - test.chain->set_code(N(bob), eosio_token_wast); - test.chain->set_abi(N(bob), eosio_token_abi); + test.chain->set_code(N(bob), contracts::eosio_token_wasm() ); + test.chain->set_abi(N(bob), contracts::eosio_token_abi().data() ); test.chain->produce_blocks(); - test.chain->set_code(N(charlie), eosio_token_wast); - test.chain->set_abi(N(charlie), eosio_token_abi); + test.chain->set_code(N(charlie), contracts::eosio_token_wasm() ); + test.chain->set_abi(N(charlie), contracts::eosio_token_abi().data() ); test.chain->produce_blocks(); @@ -331,7 +331,7 @@ BOOST_AUTO_TEST_CASE( blacklist_eosio ) { try { whitelist_blacklist_tester tester1; tester1.init(); tester1.chain->produce_blocks(); - tester1.chain->set_code(config::system_account_name, eosio_token_wast); + tester1.chain->set_code(config::system_account_name, contracts::eosio_token_wasm() ); tester1.chain->produce_blocks(); tester1.shutdown(); tester1.contract_blacklist = {config::system_account_name}; @@ -357,10 +357,10 @@ BOOST_AUTO_TEST_CASE( deferred_blacklist_failure ) { try { whitelist_blacklist_tester tester1; tester1.init(); tester1.chain->produce_blocks(); - tester1.chain->set_code( N(bob), deferred_test_wast ); - tester1.chain->set_abi( N(bob), deferred_test_abi ); - tester1.chain->set_code( N(charlie), deferred_test_wast ); - tester1.chain->set_abi( N(charlie), deferred_test_abi ); + tester1.chain->set_code( N(bob), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(bob), contracts::deferred_test_abi().data() ); + tester1.chain->set_code( N(charlie), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(charlie), contracts::deferred_test_abi().data() ); tester1.chain->produce_blocks(); tester1.chain->push_action( N(bob), N(defercall), N(alice), mvo() @@ -408,12 +408,12 @@ BOOST_AUTO_TEST_CASE( blacklist_onerror ) { try { whitelist_blacklist_tester tester1; tester1.init(); tester1.chain->produce_blocks(); - tester1.chain->set_code( N(bob), deferred_test_wast ); - tester1.chain->set_abi( N(bob), deferred_test_abi ); - tester1.chain->set_code( N(charlie), deferred_test_wast ); - tester1.chain->set_abi( N(charlie), deferred_test_abi ); + tester1.chain->set_code( N(bob), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(bob), contracts::deferred_test_abi().data() ); + tester1.chain->set_code( N(charlie), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(charlie), contracts::deferred_test_abi().data() ); tester1.chain->produce_blocks(); - + tester1.chain->push_action( N(bob), N(defercall), N(alice), mvo() ( "payer", "alice" ) ( "sender_id", 0 ) @@ -444,12 +444,12 @@ BOOST_AUTO_TEST_CASE( actor_blacklist_inline_deferred ) { try { whitelist_blacklist_tester tester1; tester1.init(); tester1.chain->produce_blocks(); - tester1.chain->set_code( N(alice), deferred_test_wast ); - tester1.chain->set_abi( N(alice), deferred_test_abi ); - tester1.chain->set_code( N(bob), deferred_test_wast ); - tester1.chain->set_abi( N(bob), deferred_test_abi ); - tester1.chain->set_code( N(charlie), deferred_test_wast ); - tester1.chain->set_abi( N(charlie), deferred_test_abi ); + tester1.chain->set_code( N(alice), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(alice), contracts::deferred_test_abi().data() ); + tester1.chain->set_code( N(bob), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(bob), contracts::deferred_test_abi().data() ); + tester1.chain->set_code( N(charlie), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(charlie), contracts::deferred_test_abi().data() ); tester1.chain->produce_blocks(); auto auth = authority(eosio::testing::base_tester::get_public_key("alice", "active")); @@ -587,12 +587,12 @@ BOOST_AUTO_TEST_CASE( blacklist_sender_bypass ) { try { whitelist_blacklist_tester tester1; tester1.init(); tester1.chain->produce_blocks(); - tester1.chain->set_code( N(alice), deferred_test_wast ); - tester1.chain->set_abi( N(alice), deferred_test_abi ); - tester1.chain->set_code( N(bob), deferred_test_wast ); - tester1.chain->set_abi( N(bob), deferred_test_abi ); - tester1.chain->set_code( N(charlie), deferred_test_wast ); - tester1.chain->set_abi( N(charlie), deferred_test_abi ); + tester1.chain->set_code( N(alice), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(alice), contracts::deferred_test_abi().data() ); + tester1.chain->set_code( N(bob), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(bob), contracts::deferred_test_abi().data() ); + tester1.chain->set_code( N(charlie), contracts::deferred_test_wasm() ); + tester1.chain->set_abi( N(charlie), contracts::deferred_test_abi().data() ); tester1.chain->produce_blocks(); auto auth = authority(eosio::testing::base_tester::get_public_key("alice", "active"));