Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 00b045ca2c | |||
| 3d8c4e345a | |||
| 2bce4e6407 | |||
| 6beea8a61f | |||
| 0821c7f7e6 | |||
| 6ec530e2de | |||
| 3e576c5f92 | |||
| c8327b51bb | |||
| 7bcebcaa0f | |||
| 4c1226e69c | |||
| 71ecec44f8 | |||
| 97aa4b8031 | |||
| c456d17833 | |||
| f41ca84851 | |||
| 79885499da | |||
| 1111fee4bc | |||
| 05fe45a4e6 | |||
| f1eb13a02d | |||
| 93fe429bbc | |||
| f9e91f19be | |||
| 86c38831ff | |||
| 2a13774d66 | |||
| b194862aa2 | |||
| 9e82b160c7 | |||
| c74fde2a27 | |||
| ed854f2bbd | |||
| e3976b8dc1 | |||
| 02c43ca656 | |||
| 5f763daa4c | |||
| c293d332f7 | |||
| 2d3e78619c | |||
| 3e11f790c6 | |||
| 41eaeef80e | |||
| 1ec98976b1 | |||
| 93833b8e03 | |||
| d6cd2c9a7d | |||
| ae2679e164 | |||
| 0f25eaa33a | |||
| b7b4554a18 | |||
| 20e59a92bc | |||
| 31fd1361aa | |||
| 449f37133b | |||
| feeee5eb8f | |||
| 32de87b185 | |||
| 78dd785035 | |||
| f4b39ea29e | |||
| 20f45e5923 | |||
| fc2166a46d | |||
| 39a5ba846a | |||
| e4b28a7854 | |||
| e4819c35e1 | |||
| 7b7027cbee | |||
| 74fb1615d8 | |||
| 5523010cfd | |||
| 7c106605cc | |||
| 9047d1175b | |||
| da6a068639 | |||
| a886743005 | |||
| 0dbfb1a6ed | |||
| e06fc98e81 | |||
| db657e5082 | |||
| 4a640d422e | |||
| 852f1bb285 | |||
| e059d8213e | |||
| e07fd0a0c8 | |||
| 051a893ca7 | |||
| afbcdf240b | |||
| 480374b245 | |||
| c716ac5480 | |||
| 7efec6a669 | |||
| d4bd548d61 | |||
| 0740055506 | |||
| 43873e8221 | |||
| adaec7704c | |||
| 1fa531daf8 | |||
| fa2b7fece2 | |||
| bb7fc8d145 | |||
| c3814b9e59 | |||
| 6fb28e5f7d | |||
| fa8d025ca8 | |||
| 12924afa0a | |||
| d9a4772977 | |||
| 51c4bea20a | |||
| 4359bc06f7 | |||
| efd642b151 | |||
| f1cc518341 | |||
| ebadb713e9 |
@@ -10,17 +10,15 @@ RUN apt-get update && apt-get upgrade -y && \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-7-dev \
|
||||
ninja-build \
|
||||
pkg-config \
|
||||
python3 \
|
||||
python3-numpy \
|
||||
python3-pip \
|
||||
software-properties-common \
|
||||
zlib1g-dev \
|
||||
zstd
|
||||
|
||||
RUN python3 -m pip install dataclasses
|
||||
|
||||
# GitHub's actions/checkout requires git 2.18+ but Ubuntu 18 only provides 2.17
|
||||
RUN add-apt-repository ppa:git-core/ppa && apt update && apt install -y git
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ RUN apt-get update && apt-get upgrade -y && \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-11-dev \
|
||||
ninja-build \
|
||||
python3-numpy \
|
||||
pkg-config \
|
||||
zstd
|
||||
|
||||
@@ -10,7 +10,8 @@ RUN apt-get update && apt-get upgrade -y && \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-11-dev \
|
||||
ninja-build \
|
||||
python3-numpy \
|
||||
pkg-config \
|
||||
zstd
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -28,7 +28,7 @@ try {
|
||||
let subprocesses = [];
|
||||
tests.forEach(t => {
|
||||
subprocesses.push(new Promise(resolve => {
|
||||
child_process.spawn("docker", ["run", "--security-opt", "seccomp=unconfined", "-e", "GITHUB_ACTIONS=True", "--name", t, "--init", "baseimage", "bash", "-c", `cd build; ctest --output-on-failure -R '^${t}$'`], {stdio:"inherit"}).on('close', code => resolve(code));
|
||||
child_process.spawn("docker", ["run", "--name", t, "--init", "baseimage", "bash", "-c", `cd build; ctest --output-on-failure -R '^${t}$'`], {stdio:"inherit"}).on('close', code => resolve(code));
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
@@ -120,9 +120,7 @@ jobs:
|
||||
matrix:
|
||||
platform: [ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-hightier"]
|
||||
container:
|
||||
image: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
options: --security-opt seccomp=unconfined
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download builddir
|
||||
@@ -159,7 +157,7 @@ jobs:
|
||||
uses: ./.github/actions/parallel-ctest-containers
|
||||
with:
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd", "build/TestLogs"]'
|
||||
error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd"]'
|
||||
log-tarball-prefix: ${{matrix.platform}}
|
||||
tests-label: nonparallelizable_tests
|
||||
- name: Upload logs from failed tests
|
||||
@@ -188,7 +186,7 @@ jobs:
|
||||
uses: ./.github/actions/parallel-ctest-containers
|
||||
with:
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd", "build/TestLogs"]'
|
||||
error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd"]'
|
||||
log-tarball-prefix: ${{matrix.platform}}
|
||||
tests-label: long_running_tests
|
||||
- name: Upload logs from failed tests
|
||||
|
||||
@@ -12,7 +12,6 @@ jobs:
|
||||
label: triage
|
||||
org-project: 'Team Backlog'
|
||||
project-field: Status=Todo
|
||||
skip-if-existing-project: true
|
||||
secrets:
|
||||
token: ${{secrets.ENFCIBOT_REPO_AND_PROJECTS}}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
name: "Pinned Build"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
packages: read
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
name: Build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu18, ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-beefy-long"]
|
||||
container: ${{ matrix.platform == 'ubuntu18' && 'ubuntu:bionic' || matrix.platform == 'ubuntu20' && 'ubuntu:focal' || 'ubuntu:jammy' }}
|
||||
steps:
|
||||
- name: Conditionally update git repo
|
||||
if: ${{ matrix.platform == 'ubuntu18' }}
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y software-properties-common
|
||||
apt-get update
|
||||
add-apt-repository ppa:git-core/ppa
|
||||
- name: Update and Install git
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y git
|
||||
git --version
|
||||
- name: Clone leap
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# https://github.com/actions/runner/issues/2033
|
||||
chown -R $(id -u):$(id -g) $PWD
|
||||
./scripts/install_deps.sh
|
||||
- name: Build Pinned Build
|
||||
env:
|
||||
LEAP_PINNED_INSTALL_PREFIX: /usr
|
||||
run: |
|
||||
./scripts/pinned_build.sh deps build "$(nproc)"
|
||||
- name: Upload package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: leap-${{matrix.platform}}-pinned-amd64
|
||||
path: build/leap_*.deb
|
||||
- name: Run Parallel Tests
|
||||
if: ${{ matrix.platform != 'ubuntu18' }}
|
||||
run: |
|
||||
cd build
|
||||
ctest --output-on-failure -j $(nproc) -LE "(nonparallelizable_tests|long_running_tests)" --timeout 420
|
||||
+3
-3
@@ -77,17 +77,17 @@ witness_node_data_dir
|
||||
|
||||
Testing/*
|
||||
build.tar.gz
|
||||
[Bb]uild*/*
|
||||
build/*
|
||||
build-debug/*
|
||||
deps/*
|
||||
dependencies/*
|
||||
|
||||
etc/eosio/node_*
|
||||
TestLogs*
|
||||
var/lib/node_*
|
||||
.vscode
|
||||
.idea/
|
||||
*.iws
|
||||
.DS_Store
|
||||
CMakeLists.txt.user
|
||||
|
||||
!*.swagger.*
|
||||
|
||||
|
||||
+6
-9
@@ -13,6 +13,9 @@
|
||||
[submodule "libraries/rapidjson"]
|
||||
path = libraries/rapidjson
|
||||
url = https://github.com/Tencent/rapidjson/
|
||||
[submodule "libraries/yubihsm"]
|
||||
path = libraries/yubihsm
|
||||
url = https://github.com/Yubico/yubihsm-shell
|
||||
[submodule "tests/abieos"]
|
||||
path = tests/abieos
|
||||
url = https://github.com/AntelopeIO/abieos
|
||||
@@ -22,12 +25,6 @@
|
||||
[submodule "libraries/libfc/secp256k1/secp256k1"]
|
||||
path = libraries/libfc/secp256k1/secp256k1
|
||||
url = https://github.com/bitcoin-core/secp256k1
|
||||
[submodule "libraries/prometheus/prometheus-cpp"]
|
||||
path = libraries/prometheus/prometheus-cpp
|
||||
url = https://github.com/jupp0r/prometheus-cpp.git
|
||||
[submodule "libraries/libfc/libraries/bn256"]
|
||||
path = libraries/libfc/libraries/bn256
|
||||
url = https://github.com/AntelopeIO/bn256
|
||||
[submodule "libraries/cli11/cli11"]
|
||||
path = libraries/cli11/cli11
|
||||
url = https://github.com/AntelopeIO/CLI11.git
|
||||
[submodule "libraries/libfc/libraries/ff"]
|
||||
path = libraries/libfc/libraries/ff
|
||||
url = https://github.com/AntelopeIO/libff
|
||||
|
||||
+15
-68
@@ -13,10 +13,10 @@ set( CMAKE_CXX_STANDARD 17 )
|
||||
set( CMAKE_CXX_EXTENSIONS ON )
|
||||
set( CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(VERSION_MAJOR 4)
|
||||
set(VERSION_MINOR 1)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION_SUFFIX dev)
|
||||
set(VERSION_MAJOR 3)
|
||||
set(VERSION_MINOR 2)
|
||||
set(VERSION_PATCH 4)
|
||||
#set(VERSION_SUFFIX rc2)
|
||||
|
||||
if(VERSION_SUFFIX)
|
||||
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}")
|
||||
@@ -24,12 +24,6 @@ else()
|
||||
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
endif()
|
||||
|
||||
|
||||
# Options
|
||||
option(ENABLE_WERROR "Enable `-Werror` compilation flag." Off)
|
||||
option(ENABLE_WEXTRA "Enable `-Wextra` compilation flag." Off)
|
||||
|
||||
|
||||
set( CLI_CLIENT_EXECUTABLE_NAME cleos )
|
||||
set( NODE_EXECUTABLE_NAME nodeos )
|
||||
set( KEY_STORE_EXECUTABLE_NAME keosd )
|
||||
@@ -66,6 +60,8 @@ if(APPLE AND UNIX AND "${OPENSSL_ROOT_DIR}" STREQUAL "")
|
||||
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl@3;/usr/local/opt/openssl@1.1")
|
||||
endif()
|
||||
endif()
|
||||
# fc also adds these definitions to its public interface. once fc becomes the sole importer of openssl, this should be removed
|
||||
add_definitions(-DOPENSSL_API_COMPAT=0x10100000L -DOPENSSL_NO_DEPRECATED)
|
||||
|
||||
option(ENABLE_OC "Enable eosvm-oc on supported platforms" ON)
|
||||
|
||||
@@ -132,16 +128,6 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_WERROR)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror" )
|
||||
endif()
|
||||
if(ENABLE_WEXTRA)
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra" )
|
||||
endif()
|
||||
|
||||
|
||||
option(EOSIO_ENABLE_DEVELOPER_OPTIONS "enable developer options for Leap" OFF)
|
||||
|
||||
# based on http://www.delorie.com/gnu/docs/gdb/gdb_70.html
|
||||
@@ -200,6 +186,9 @@ add_subdirectory( benchmark )
|
||||
|
||||
option(DISABLE_WASM_SPEC_TESTS "disable building of wasm spec unit tests" OFF)
|
||||
|
||||
install(FILES testnet.template DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/eosio/launcher COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testnet.template ${CMAKE_CURRENT_BINARY_DIR}/etc/eosio/launcher/testnet.template COPYONLY)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/eosio.version.in ${CMAKE_CURRENT_BINARY_DIR}/eosio.version.hpp)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/eosio.version.hpp DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
|
||||
@@ -231,59 +220,14 @@ configure_file(libraries/softfloat/COPYING.txt licen
|
||||
configure_file(libraries/wasm-jit/LICENSE licenses/leap/LICENSE.wavm COPYONLY)
|
||||
configure_file(libraries/libfc/secp256k1/secp256k1/COPYING licenses/leap/LICENSE.secp256k1 COPYONLY)
|
||||
configure_file(libraries/libfc/include/fc/crypto/webauthn_json/license.txt licenses/leap/LICENSE.rapidjson COPYONLY)
|
||||
configure_file(libraries/libfc/src/network/LICENSE.go licenses/leap/LICENSE.go COPYONLY)
|
||||
configure_file(libraries/eos-vm/LICENSE licenses/leap/LICENSE.eos-vm COPYONLY)
|
||||
configure_file(libraries/prometheus/prometheus-cpp/LICENSE licenses/leap/LICENSE.prom COPYONLY)
|
||||
configure_file(libraries/libfc/libraries/ff/LICENSE licenses/leap/LICENSE.libff COPYONLY)
|
||||
configure_file(programs/cleos/LICENSE.CLI11 licenses/leap/LICENSE.CLI11 COPYONLY)
|
||||
configure_file(libraries/yubihsm/LICENSE licenses/leap/LICENSE.yubihsm COPYONLY)
|
||||
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/licenses/leap" DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/" COMPONENT base)
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libraries/testing/contracts DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/leap_testing/libraries/testing COMPONENT dev EXCLUDE_FROM_ALL
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "*.cmake" EXCLUDE
|
||||
PATTERN "Makefile" EXCLUDE)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unittests/contracts DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/leap_testing/unittests COMPONENT dev EXCLUDE_FROM_ALL
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "*.cmake" EXCLUDE
|
||||
PATTERN "Makefile" EXCLUDE)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests/TestHarness DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/leap_testing/tests COMPONENT dev EXCLUDE_FROM_ALL
|
||||
FILES_MATCHING
|
||||
PATTERN "*.py"
|
||||
PATTERN "*.json"
|
||||
PATTERN "__pycache__" EXCLUDE
|
||||
PATTERN "CMakeFiles" EXCLUDE)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tests/launcher.py DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/leap_testing/tests COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21)
|
||||
# Cmake versions < 3.21 did not support installing symbolic links to a directory via install(FILES ...)
|
||||
# Cmake 3.21 fixed this (https://gitlab.kitware.com/cmake/cmake/-/commit/d71a7cc19d6e03f89581efdaa8d63db216184d40)
|
||||
# If/when the lowest cmake version supported becomes >= 3.21, the else block as well as the postinit and prerm scripts
|
||||
# would be a good option to remove in favor of using the facilities in cmake / cpack directly.
|
||||
|
||||
add_custom_target(link_target ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory lib/python3/dist-packages
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ../../../share/leap_testing/tests/TestHarness lib/python3/dist-packages/TestHarness
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory share/leap_testing
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ../../bin share/leap_testing/bin)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/python3/dist-packages/TestHarness DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/python3/dist-packages COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/share/leap_testing/bin DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/leap_testing COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
# The following install(CODE ...) steps are necessary for `make dev-install` to work on cmake versions < 3.21.
|
||||
# However, it can flag as an error if using `make package` instead of `make dev-install` for installation.
|
||||
# This is due to those directories and symbolic links being created in the postinit script during the package install instead.
|
||||
|
||||
# Note If/when doing `make package`, it is not a true error if you see:
|
||||
# Error creating directory "/<leap_install_dir>/lib/python3/dist-packages".
|
||||
# CMake Error: failed to create symbolic link '/<leap_install_dir>/lib/python3/dist-packages/TestHarness': no such file or directory
|
||||
# CMake Error: failed to create symbolic link '/<leap_install_dir>/share/leap_testing/bin': no such file or directory
|
||||
|
||||
install(CODE "execute_process( COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_FULL_LIBDIR}/python3/dist-packages)" COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
install(CODE "execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink ../../../share/leap_testing/tests/TestHarness ${CMAKE_INSTALL_FULL_LIBDIR}/python3/dist-packages/TestHarness)" COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
install(CODE "execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink ../../bin ${CMAKE_INSTALL_FULL_DATAROOTDIR}/leap_testing/bin)" COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
|
||||
# The `make package` installation of symlinks happens via the `postinst` script installed in cmake.package via the line below
|
||||
endif()
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/cli11/bash-completion/completions/leap-util
|
||||
${CMAKE_BINARY_DIR}/programs/leap-util/bash-completion/completions/leap-util COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/cli11/bash-completion/completions/cleos
|
||||
@@ -299,6 +243,9 @@ add_custom_target(dev-install
|
||||
USES_TERMINAL
|
||||
)
|
||||
|
||||
get_property(_CTEST_CUSTOM_TESTS_IGNORE GLOBAL PROPERTY CTEST_CUSTOM_TESTS_IGNORE)
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/CTestCustom.cmake" "SET(CTEST_CUSTOM_TESTS_IGNORE ${_CTEST_CUSTOM_TESTS_IGNORE})")
|
||||
|
||||
include(doxygen)
|
||||
|
||||
include(package.cmake)
|
||||
|
||||
@@ -56,8 +56,8 @@ find_library(libtester eosio_testing @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH
|
||||
find_library(libchain eosio_chain @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libfc fc @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libbn256 bn256 @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
|
||||
find_library(libff ff @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libwasm WASM @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libwast WAST @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libir IR @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
@@ -98,7 +98,7 @@ macro(add_eosio_test_executable test_name)
|
||||
${libchainbase}
|
||||
${libbuiltins}
|
||||
${libsecp256k1}
|
||||
${libbn256}
|
||||
${libff}
|
||||
@GMP_LIBRARY@
|
||||
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
@@ -115,7 +115,7 @@ macro(add_eosio_test_executable test_name)
|
||||
${WRAP_MAIN}
|
||||
Threads::Threads
|
||||
)
|
||||
|
||||
|
||||
#adds -ltr. Ubuntu eosio.contracts build breaks without this
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(${test_name} ${LIBRT})
|
||||
|
||||
@@ -53,8 +53,8 @@ find_library(libtester eosio_testing @CMAKE_BINARY_DIR@/libraries/testing NO_DEF
|
||||
find_library(libchain eosio_chain @CMAKE_BINARY_DIR@/libraries/chain NO_DEFAULT_PATH)
|
||||
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/libfc NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_BINARY_DIR@/libraries/libfc/secp256k1 NO_DEFAULT_PATH)
|
||||
find_library(libbn256 bn256 @CMAKE_BINARY_DIR@/libraries/libfc/libraries/bn256/src NO_DEFAULT_PATH)
|
||||
|
||||
find_library(libff ff @CMAKE_BINARY_DIR@/libraries/libfc/libraries/ff/libff NO_DEFAULT_PATH)
|
||||
find_library(libwasm WASM @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/WASM NO_DEFAULT_PATH)
|
||||
find_library(libwast WAST @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/WAST NO_DEFAULT_PATH)
|
||||
find_library(libir IR @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/IR NO_DEFAULT_PATH)
|
||||
@@ -95,7 +95,7 @@ macro(add_eosio_test_executable test_name)
|
||||
${libchainbase}
|
||||
${libbuiltins}
|
||||
${libsecp256k1}
|
||||
${libbn256}
|
||||
${libff}
|
||||
@GMP_LIBRARY@
|
||||
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
@@ -112,7 +112,7 @@ macro(add_eosio_test_executable test_name)
|
||||
${WRAP_MAIN}
|
||||
Threads::Threads
|
||||
)
|
||||
|
||||
|
||||
#adds -ltr. Ubuntu eosio.contracts build breaks without this
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(${test_name} ${LIBRT})
|
||||
|
||||
@@ -50,12 +50,12 @@ Requirements to build:
|
||||
- LLVM 7 - 11 - for Linux only
|
||||
- newer versions do not work
|
||||
- openssl 1.1+
|
||||
- libcurl
|
||||
- curl
|
||||
- libcurl 7.40.0+
|
||||
- libusb
|
||||
- git
|
||||
- GMP
|
||||
- Python 3
|
||||
- python3-numpy
|
||||
- zlib
|
||||
|
||||
### Step 1 - Clone
|
||||
@@ -111,14 +111,12 @@ Make sure you are in the root of the `leap` repo, then run the `install_depts.sh
|
||||
sudo scripts/install_deps.sh
|
||||
```
|
||||
|
||||
Next, run the pinned build script. You have to give it three arguments in the following order:
|
||||
1. A temporary folder, for all dependencies that need to be built from source.
|
||||
1. A build folder, where the binaries you need to install will be built to.
|
||||
1. The number of jobs or CPU cores/threads to use (note the [jobs flag](#step-3---build) warning above).
|
||||
Next, run the pinned build script. You have to give it three arguments, in the following order:
|
||||
- A temporary folder, for all dependencies that need to be built from source.
|
||||
- A build folder, where the binaries you need to install will be built to.
|
||||
- The number of jobs or CPU cores/threads to use (note the [jobs flag](#step-3---build) warning above).
|
||||
|
||||
> 🔒 You do not need to run this script with `sudo` or as root.
|
||||
|
||||
For example, the following command runs the `pinned_build.sh` script, specifies a `deps` and `build` folder in the root of the Leap repo for the first two arguments, then builds the packages using all of your computer's CPU threads:
|
||||
The following command runs the `pinned_build.sh` script, specifies a `deps` and `build` folder in the root of the Leap repo for the first two arguments, then builds the packages using all of your computer's CPU threads (Note: you don't need `sudo` for this command):
|
||||
```bash
|
||||
scripts/pinned_build.sh deps build "$(nproc)"
|
||||
```
|
||||
@@ -141,15 +139,16 @@ sudo apt-get install -y \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-11-dev \
|
||||
python3-numpy
|
||||
pkg-config
|
||||
```
|
||||
To build, make sure you are in the root of the `leap` repo, then run the following command:
|
||||
```bash
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/lib/llvm-11 ..
|
||||
make -j "$(nproc)" package
|
||||
make -j $(nproc) package
|
||||
```
|
||||
</details>
|
||||
|
||||
@@ -167,13 +166,11 @@ sudo apt-get install -y \
|
||||
libcurl4-openssl-dev \
|
||||
libgmp-dev \
|
||||
libssl-dev \
|
||||
libusb-1.0-0-dev \
|
||||
llvm-7-dev \
|
||||
pkg-config \
|
||||
python3 \
|
||||
python3-numpy \
|
||||
python3-pip \
|
||||
zlib1g-dev
|
||||
|
||||
python3 -m pip install dataclasses
|
||||
```
|
||||
You need to build Boost from source on this distribution:
|
||||
```bash
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
file(GLOB BENCHMARK "*.cpp")
|
||||
add_executable( benchmark ${BENCHMARK} )
|
||||
|
||||
target_link_libraries( benchmark fc Boost::program_options bn256)
|
||||
target_link_libraries( benchmark fc Boost::program_options )
|
||||
target_include_directories( benchmark PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
+36
-25
@@ -1,6 +1,6 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <bn256/bn256.h>
|
||||
#include <fc/crypto/alt_bn128.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
@@ -10,20 +10,22 @@ using bytes = std::vector<char>;
|
||||
using g1g2_pair = std::vector<std::string>;
|
||||
|
||||
void add_benchmarking() {
|
||||
const unsigned char point1[64] = {
|
||||
std::vector<unsigned char> point1_raw = {
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201, // x
|
||||
18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,}; // y
|
||||
const unsigned char point2[64] = {
|
||||
std::vector<unsigned char> point2_raw = {
|
||||
12,144,10,32,104,85,103,36,222,232,48,152,108,217,40,145,230,48,8,54,0,7,134,164,7,10,139,110,95,205,124,121, // x
|
||||
22,254,176,251,18,168,78,220,142,100,102,113,58,176,83,186,212,62,154,138,235,135,34,46,237,117,54,36,198,40,79,73,}; // y
|
||||
|
||||
unsigned char ans[64] ={};
|
||||
|
||||
22,254,176,251,18,168,78,220,142,100,102,113,58,176,83,186,212,62,154,138,235,135,34,46,237,117,54,36,198,40,79,73,}; // y
|
||||
|
||||
bytes point1, point2;
|
||||
point1.insert(point1.begin(), point1_raw.begin(), point1_raw.end());
|
||||
point2.insert(point2.begin(), point2_raw.begin(), point2_raw.end());
|
||||
|
||||
auto f = [&]() {
|
||||
auto res = bn256::g1_add(point1, point2, ans);
|
||||
if (res == -1) {
|
||||
std::cout << "alt_bn128_add failed" << std::endl;
|
||||
auto res = fc::alt_bn128_add(point1, point2);
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_add failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,18 +33,21 @@ void add_benchmarking() {
|
||||
}
|
||||
|
||||
void mul_benchmarking() {
|
||||
const unsigned char point[64] = {
|
||||
std::vector<unsigned char> point_raw = {
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201, // x
|
||||
18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,}; // y
|
||||
const unsigned char scalar[32] = {
|
||||
std::vector<unsigned char> scaler_raw = {
|
||||
25,62,182,170,104,140,135,90,37,150,0,77,2,77,146,71,54,101,113,69,177,216,157,4,229,213,33,215,169,99,150,91, }; // scaler size 256 bits
|
||||
|
||||
unsigned char ans[64] = {};
|
||||
|
||||
bytes point, scaler;
|
||||
point.insert(point.begin(), point_raw.begin(), point_raw.end());
|
||||
scaler.insert(scaler.begin(), scaler_raw.begin(), scaler_raw.end());
|
||||
|
||||
auto f = [&]() {
|
||||
auto res = bn256::g1_scalar_mul(point, scalar, ans);
|
||||
if (res == -1) {
|
||||
std::cout << "alt_bn128_mul failed" << std::endl;
|
||||
auto res = fc::alt_bn128_mul(point, scaler);
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_mul failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -50,7 +55,7 @@ void mul_benchmarking() {
|
||||
}
|
||||
|
||||
void pair_benchmarking() {
|
||||
const unsigned char g1_g2_pairs[] = {
|
||||
std::vector<unsigned char> g1_g2_pairs_raw = {
|
||||
/* pair 1 */
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201,18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,
|
||||
46,24,234,176,148,82,198,136,44,30,157,18,217,25,49,241,63,197,2,151,14,150,136,210,114,4,74,124,145,225,131,139,13,60,0,50,236,103,39,15,150,226,246,189,209,113,0,46,151,39,41,6,87,119,228,213,45,225,29,234,161,110,43,87,3,237,74,227,93,23,171,129,49,118,228,173,154,111,168,220,161,46,140,103,155,56,168,207,254,90,228,76,188,232,25,34,44,102,159,35,193,216,177,31,131,247,226,19,170,222,26,227,86,37,81,149,202,144,188,126,120,168,9,195,32,169,147,161,
|
||||
@@ -82,21 +87,27 @@ void pair_benchmarking() {
|
||||
30,204,212,77,212,159,135,173,195,194,165,112,62,248,180,204,66,73,253,99,65,111,39,171,19,211,171,203,35,66,146,20,33,241,46,6,167,133,80,76,238,165,59,232,120,58,211,157,50,212,86,191,95,6,134,164,36,227,79,58,119,98,108,171,
|
||||
48,49,12,141,166,151,158,56,136,255,197,138,114,195,39,59,71,236,82,57,149,249,170,55,187,95,193,171,14,124,45,87,7,157,47,178,153,237,194,157,142,194,100,14,40,51,61,201,244,93,61,196,154,59,14,135,209,72,102,186,14,228,228,152,40,246,109,82,93,249,92,105,191,121,77,108,20,87,3,87,167,173,171,255,189,34,155,239,218,95,181,153,222,20,120,195,27,28,47,82,113,3,218,129,54,210,185,165,206,99,126,61,217,19,237,5,12,90,148,246,128,231,63,53,37,223,204,195
|
||||
};
|
||||
|
||||
|
||||
// benchmarking 1 pair of points
|
||||
bytes g1_g2_1_pair;
|
||||
g1_g2_1_pair.insert(g1_g2_1_pair.begin(), g1_g2_pairs_raw.begin(), g1_g2_pairs_raw.begin() + 384);
|
||||
auto f_1_pair = [&]() {
|
||||
auto res = bn256::pairing_check({ g1_g2_pairs, 384}, [](){});
|
||||
if (res == -1) {
|
||||
std::cout << "alt_bn128_pair 1 pair failed" << std::endl;
|
||||
auto res = fc::alt_bn128_pair(g1_g2_1_pair, [](){});
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_pair 1 pair failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
benchmarking("alt_bn128_pair (1 pair)", f_1_pair);
|
||||
|
||||
// benchmarking 10 pair of points
|
||||
bytes g1_g2_10_pairs;
|
||||
g1_g2_10_pairs.insert(g1_g2_10_pairs.begin(), g1_g2_pairs_raw.begin(), g1_g2_pairs_raw.end());
|
||||
auto f_10_pairs = [&]() {
|
||||
auto res = bn256::pairing_check(g1_g2_pairs, [](){});
|
||||
if (res == -1) {
|
||||
std::cout << "alt_bn128_pair 10 pair failed" << std::endl;
|
||||
auto res = fc::alt_bn128_pair(g1_g2_10_pairs, [](){});
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_pair 10 pairs failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
content_title: Build Antelope from Source
|
||||
---
|
||||
|
||||
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the [`README.md`](https://github.com/AntelopeIO/leap/blob/main/README.md) file. Instructions are also included for efficiently running the tests.
|
||||
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the [`README.md`](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md) file. Instructions are also included for efficiently running the tests.
|
||||
|
||||
### Using DUNE
|
||||
As an alternative to building from source, try [Docker Utilities for Node Execution](https://github.com/AntelopeIO/DUNE) for the easiest way to get started and for multi-platform support.
|
||||
|
||||
### Building From Source
|
||||
You can also build and install Leap from source. Instructions for that currently live [here](https://github.com/AntelopeIO/leap/blob/main/README.md#build-and-install-from-source).
|
||||
You can also build and install Leap from source. Instructions for that currently live [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#build-and-install-from-source).
|
||||
|
||||
#### Building Pinned Build Binary Packages
|
||||
The pinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/main/README.md#pinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/main/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/main/README.md#step-3---build) before you build.
|
||||
The pinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#pinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#step-3---build) before you build.
|
||||
|
||||
#### Manual (non "pinned") Build Instructions
|
||||
The unpinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/main/README.md#unpinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/main/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/main/README.md#step-3---build) before you build.
|
||||
The unpinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#unpinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#step-3---build) before you build.
|
||||
|
||||
### Running Tests
|
||||
Documentation on available test suites and how to run them has moved [here](https://github.com/AntelopeIO/leap/blob/main/README.md#test).
|
||||
Documentation on available test suites and how to run them has moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#test).
|
||||
|
||||
@@ -143,7 +143,7 @@ We now have an account that is available to have a contract assigned to it, enab
|
||||
In the fourth terminal window, start a second `nodeos` instance. Notice that this command line is substantially longer than the one we used above to create the first producer. This is necessary to avoid collisions with the first `nodeos` instance. Fortunately, you can just cut and paste this command line and adjust the keys:
|
||||
|
||||
```sh
|
||||
nodeos --producer-name inita --plugin eosio::chain_api_plugin --plugin eosio::net_api_plugin --http-server-address 127.0.0.1:8889 --p2p-listen-endpoint 127.0.0.1:9877 --p2p-peer-address 127.0.0.1:9876 --config-dir node2 --data-dir node2 --signature-provider EOS6hMjoWRF2L8x9YpeqtUEcsDKAyxSuM1APicxgRU1E3oyV5sDEg=KEY:5JgbL2ZnoEAhTudReWH1RnMuQS6DBeLZt4ucV6t8aymVEuYg7sr
|
||||
nodeos --producer-name inita --plugin eosio::chain_api_plugin --plugin eosio::net_api_plugin --http-server-address 127.0.0.1:8889 --p2p-listen-endpoint 127.0.0.1:9877 --p2p-peer-address 127.0.0.1:9876 --config-dir node2 --data-dir node2 --private-key [\"EOS6hMjoWRF2L8x9YpeqtUEcsDKAyxSuM1APicxgRU1E3oyV5sDEg\",\"5JgbL2ZnoEAhTudReWH1RnMuQS6DBeLZt4ucV6t8aymVEuYg7sr\"]
|
||||
```
|
||||
|
||||
The output from this new node will show a little activity but will stop reporting until the last step in this tutorial, when the `inita` account is registered as a producer account and activated. Here is some example output from a newly started node. Your output might look a little different, depending on how much time you took entering each of these commands. Furthermore, this example is only the last few lines of output:
|
||||
|
||||
@@ -63,9 +63,6 @@ Config Options for eosio::chain_plugin:
|
||||
--blocks-dir arg (="blocks") the location of the blocks directory
|
||||
(absolute path or relative to
|
||||
application data dir)
|
||||
--state-dir arg (="state") the location of the state directory
|
||||
(absolute path or relative to
|
||||
application data dir)
|
||||
--protocol-features-dir arg (="protocol_features")
|
||||
the location of the protocol_features
|
||||
directory (absolute path or relative to
|
||||
@@ -119,18 +116,35 @@ Config Options for eosio::chain_plugin:
|
||||
subjective whitelist/blacklist checks
|
||||
applied to them (may specify multiple
|
||||
times)
|
||||
--read-mode arg (=head) Database read mode ("head",
|
||||
"irreversible").
|
||||
--read-mode arg (=speculative) Database read mode ("speculative",
|
||||
"head", "read-only", "irreversible").
|
||||
In "speculative" mode: database
|
||||
contains state changes by transactions
|
||||
in the blockchain up to the head block
|
||||
as well as some transactions not yet
|
||||
included in the blockchain.
|
||||
In "head" mode: database contains state
|
||||
changes up to the head block;
|
||||
changes by only transactions in the
|
||||
blockchain up to the head block;
|
||||
transactions received by the node are
|
||||
relayed if valid.
|
||||
In "read-only" mode: (DEPRECATED: see
|
||||
p2p-accept-transactions &
|
||||
api-accept-transactions) database
|
||||
contains state changes by only
|
||||
transactions in the blockchain up to
|
||||
the head block; transactions received
|
||||
via the P2P network are not relayed and
|
||||
transactions cannot be pushed via the
|
||||
chain API.
|
||||
In "irreversible" mode: database
|
||||
contains state changes up to the last
|
||||
irreversible block; transactions
|
||||
received via the P2P network are not
|
||||
relayed and transactions cannot be
|
||||
pushed via the chain API.
|
||||
contains state changes by only
|
||||
transactions in the blockchain up to
|
||||
the last irreversible block;
|
||||
transactions received via the P2P
|
||||
network are not relayed and
|
||||
transactions cannot be pushed via the
|
||||
chain API.
|
||||
|
||||
--api-accept-transactions arg (=1) Allow API transactions to be evaluated
|
||||
and relayed if valid.
|
||||
@@ -207,16 +221,9 @@ Config Options for eosio::chain_plugin:
|
||||
transaction's Finality Status will
|
||||
remain available from being first
|
||||
identified.
|
||||
--integrity-hash-on-start Log the state integrity hash on startup
|
||||
--integrity-hash-on-stop Log the state integrity hash on
|
||||
shutdown
|
||||
--block-log-retain-blocks arg If set to greater than 0, periodically
|
||||
prune the block log to store only
|
||||
configured number of most recent
|
||||
blocks.
|
||||
If set to 0, no blocks are be written
|
||||
to the block log; block log file is
|
||||
removed after startup.
|
||||
--block-log-retain-blocks arg if set, periodically prune the block
|
||||
log to store only configured number of
|
||||
most recent blocks
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
## Description
|
||||
|
||||
The `http_client_plugin` is an internal utility plugin, providing the `producer_plugin` the ability to use securely an external `keosd` instance as its block signer. It can only be used when the `producer_plugin` is configured to produce blocks.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
# config.ini
|
||||
plugin = eosio::http_client_plugin
|
||||
https-client-root-cert = "path/to/my/certificate.pem"
|
||||
https-client-validate-peers = 1
|
||||
```
|
||||
```sh
|
||||
# command-line
|
||||
nodeos ... --plugin eosio::http_client_plugin \
|
||||
--https-client-root-cert "path/to/my/certificate.pem" \
|
||||
--https-client-validate-peers 1
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
These can be specified from both the `nodeos` command-line or the `config.ini` file:
|
||||
|
||||
```console
|
||||
Config Options for eosio::http_client_plugin:
|
||||
--https-client-root-cert arg PEM encoded trusted root certificate
|
||||
(or path to file containing one) used
|
||||
to validate any TLS connections made.
|
||||
(may specify multiple times)
|
||||
|
||||
--https-client-validate-peers arg (=1)
|
||||
true: validate that the peer
|
||||
certificates are valid and trusted,
|
||||
false: ignore cert errors
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
* [`producer_plugin`](../producer_plugin/index.md)
|
||||
@@ -29,10 +29,20 @@ Config Options for eosio::http_plugin:
|
||||
The local IP and port to listen for
|
||||
incoming http connections; set blank to
|
||||
disable.
|
||||
--https-server-address arg The local IP and port to listen for
|
||||
incoming https connections; leave blank
|
||||
to disable.
|
||||
--https-certificate-chain-file arg Filename with the certificate chain to
|
||||
present on https connections. PEM
|
||||
format. Required for https.
|
||||
--https-private-key-file arg Filename with https private key in PEM
|
||||
format. Required for https
|
||||
--https-ecdh-curve arg (=secp384r1) Configure https ECDH curve to use:
|
||||
secp384r1 or prime256v1
|
||||
--access-control-allow-origin arg Specify the Access-Control-Allow-Origin
|
||||
to be returned on each request
|
||||
to be returned on each request.
|
||||
--access-control-allow-headers arg Specify the Access-Control-Allow-Header
|
||||
s to be returned on each request
|
||||
s to be returned on each request.
|
||||
--access-control-max-age arg Specify the Access-Control-Max-Age to
|
||||
be returned on each request.
|
||||
--access-control-allow-credentials Specify if Access-Control-Allow-Credent
|
||||
@@ -45,13 +55,7 @@ Config Options for eosio::http_plugin:
|
||||
should use for processing http
|
||||
requests. -1 for unlimited. 429 error
|
||||
response when exceeded.
|
||||
--http-max-in-flight-requests arg (=-1)
|
||||
Maximum number of requests http_plugin
|
||||
should use for processing http
|
||||
requests. 429 error response when
|
||||
exceeded.
|
||||
--http-max-response-time-ms arg (=30) Maximum time for processing a request,
|
||||
-1 for unlimited
|
||||
--http-max-response-time-ms arg (=30) Maximum time for processing a request.
|
||||
--verbose-http-errors Append the error log to HTTP responses
|
||||
--http-validate-host arg (=1) If set to false, then any incoming
|
||||
"Host" header is considered valid
|
||||
@@ -62,9 +66,6 @@ Config Options for eosio::http_plugin:
|
||||
by default.
|
||||
--http-threads arg (=2) Number of worker threads in http thread
|
||||
pool
|
||||
--http-keep-alive arg (=1) If set to false, do not keep HTTP
|
||||
connections alive, even if client
|
||||
requests.
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
@@ -11,7 +11,9 @@ For information on specific plugins, just select from the list below:
|
||||
* [`chain_api_plugin`](chain_api_plugin/index.md)
|
||||
* [`chain_plugin`](chain_plugin/index.md)
|
||||
* [`db_size_api_plugin`](db_size_api_plugin/index.md)
|
||||
* [`http_client_plugin`](http_client_plugin/index.md)
|
||||
* [`http_plugin`](http_plugin/index.md)
|
||||
* [`login_plugin`](login_plugin/index.md)
|
||||
* [`net_api_plugin`](net_api_plugin/index.md)
|
||||
* [`net_plugin`](net_plugin/index.md)
|
||||
* [`producer_plugin`](producer_plugin/index.md)
|
||||
@@ -19,6 +21,7 @@ For information on specific plugins, just select from the list below:
|
||||
* [`test_control_api_plugin`](test_control_api_plugin/index.md)
|
||||
* [`test_control_plugin`](test_control_plugin/index.md)
|
||||
* [`trace_api_plugin`](trace_api_plugin/index.md)
|
||||
* [`txn_test_gen_plugin`](txn_test_gen_plugin/index.md)
|
||||
|
||||
[[info | Nodeos is modular]]
|
||||
| Plugins add incremental functionality to `nodeos`. Unlike runtime plugins, `nodeos` plugins are built at compile-time.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
## Description
|
||||
|
||||
The `login_plugin` supports the concept of applications authenticating with the Antelope blockchain. The `login_plugin` API allows an application to verify whether an account is allowed to sign in order to satisfy a specified authority.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
# config.ini
|
||||
plugin = eosio::login_plugin
|
||||
[options]
|
||||
```
|
||||
```sh
|
||||
# command-line
|
||||
nodeos ... --plugin eosio::login_plugin [options]
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
These can be specified from both the `nodeos` command-line or the `config.ini` file:
|
||||
|
||||
```console
|
||||
Config Options for eosio::login_plugin:
|
||||
--max-login-requests arg (=1000000) The maximum number of pending login
|
||||
requests
|
||||
--max-login-timeout arg (=60) The maximum timeout for pending login
|
||||
requests (in seconds)
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
* [`chain_plugin`](../chain_plugin/index.md)
|
||||
* [`http_plugin`](../http_plugin/index.md)
|
||||
|
||||
### Load Dependency Examples
|
||||
|
||||
```console
|
||||
# config.ini
|
||||
plugin = eosio::chain_plugin
|
||||
[options]
|
||||
plugin = eosio::http_plugin
|
||||
[options]
|
||||
```
|
||||
```sh
|
||||
# command-line
|
||||
nodeos ... --plugin eosio::chain_plugin [options] \
|
||||
--plugin eosio::http_plugin [options]
|
||||
```
|
||||
@@ -39,6 +39,10 @@ Config Options for eosio::producer_plugin:
|
||||
-p [ --producer-name ] arg ID of producer controlled by this node
|
||||
(e.g. inita; may specify multiple
|
||||
times)
|
||||
--private-key arg (DEPRECATED - Use signature-provider
|
||||
instead) Tuple of [public key, WIF
|
||||
private key] (may specify multiple
|
||||
times)
|
||||
--signature-provider arg (=EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV=KEY:5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3)
|
||||
Key=Value pairs in the form
|
||||
<public-key>=<provider-spec>
|
||||
@@ -51,7 +55,7 @@ Config Options for eosio::producer_plugin:
|
||||
form <provider-type>
|
||||
:<data>
|
||||
|
||||
<provider-type> is KEY, KEOSD, or SE
|
||||
<provider-type> is KEY, or KEOSD
|
||||
|
||||
KEY:<data> is a string form of
|
||||
a valid EOS
|
||||
@@ -64,6 +68,10 @@ Config Options for eosio::producer_plugin:
|
||||
and the approptiate
|
||||
wallet(s) are
|
||||
unlocked
|
||||
--keosd-provider-timeout arg (=5) Limits the maximum time (in
|
||||
milliseconds) that is allowed for
|
||||
sending blocks to a keosd provider for
|
||||
signing
|
||||
--greylist-account arg account that can not access to extended
|
||||
CPU/NET virtual resources
|
||||
--greylist-limit arg (=1000) Limit (between 1 and 1000) on the
|
||||
@@ -98,10 +106,9 @@ Config Options for eosio::producer_plugin:
|
||||
--max-scheduled-transaction-time-per-block-ms arg (=100)
|
||||
Maximum wall-clock time, in
|
||||
milliseconds, spent retiring scheduled
|
||||
transactions (and incoming transactions
|
||||
according to incoming-defer-ratio) in
|
||||
any block before returning to normal
|
||||
transaction processing.
|
||||
transactions in any block before
|
||||
returning to normal transaction
|
||||
processing.
|
||||
--subjective-cpu-leeway-us arg (=31000)
|
||||
Time in microseconds allowed for a
|
||||
transaction that starts with
|
||||
@@ -122,6 +129,8 @@ Config Options for eosio::producer_plugin:
|
||||
transaction queue. Exceeding this value
|
||||
will subjectively drop transaction with
|
||||
resource exhaustion.
|
||||
--disable-api-persisted-trx Disable the re-apply of API
|
||||
transactions.
|
||||
--disable-subjective-billing arg (=1) Disable subjective CPU billing for
|
||||
API/P2P transactions
|
||||
--disable-subjective-account-billing arg
|
||||
|
||||
@@ -42,9 +42,6 @@ Config Options for eosio::state_history_plugin:
|
||||
incoming connections. Caution: only
|
||||
expose this port to your internal
|
||||
network.
|
||||
--state-history-unix-socket-path arg the path (relative to data-dir) to
|
||||
create a unix socket upon which to
|
||||
listen for incoming connections.
|
||||
--trace-history-debug-mode enable debug mode for trace history
|
||||
--state-history-log-retain-blocks arg if set, periodically prune the state
|
||||
history files to store only configured
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
## Description
|
||||
|
||||
The `txn_test_gen_plugin` is used for transaction test purposes.
|
||||
|
||||
[[info | For More Information]]
|
||||
For more information, check the [txn_test_gen_plugin/README.md](https://github.com/AntelopeIO/leap/tree/main/plugins/txn_test_gen_plugin) on the `AntelopeIO/leap` repository.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
# config.ini
|
||||
plugin = eosio::txn_test_gen_plugin
|
||||
[options]
|
||||
```
|
||||
```sh
|
||||
# command-line
|
||||
nodeos ... --plugin eosio::txn_test_gen_plugin [options]
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
These can be specified from both the `nodeos` command-line or the `config.ini` file:
|
||||
|
||||
```console
|
||||
Config Options for eosio::txn_test_gen_plugin:
|
||||
--txn-reference-block-lag arg (=0) Lag in number of blocks from the head
|
||||
block when selecting the reference
|
||||
block for transactions (-1 means Last
|
||||
Irreversible Block)
|
||||
--txn-test-gen-threads arg (=2) Number of worker threads in
|
||||
txn_test_gen thread pool
|
||||
--txn-test-gen-account-prefix arg (=txn.test.)
|
||||
Prefix to use for accounts generated
|
||||
and used by this plugin
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
None
|
||||
@@ -81,7 +81,7 @@ Sample `logging.json`:
|
||||
- Answers the question: is this useful information for a user that is monitoring the log output. Care should be taken not to create excessive log output; similar to `info` level logging.
|
||||
- Enabling `debug` level logging should provide greater insight into behavior without overwhelming the output with log entries.
|
||||
- `debug` level should not be used for *trace* level logging; to that end, use `all` (see below).
|
||||
- Like `info`, no `debug` level logging should be produced for every transaction. There are specific transaction level loggers dedicated to transaction level logging: `transaction`, `transaction_trace_failure`, `transaction_trace_success`, `transaction_failure_tracing`, `transaction_success_tracing`, `transient_trx_success_tracing`, `transient_trx_failure_tracing`.
|
||||
- Like `info`, no `debug` level logging should be produced for every transaction. There are specific transaction level loggers dedicated to transaction level logging: `transaction`, `transaction_trace_failure`, `transaction_trace_success`, `transaction_failure_tracing`, `transaction_success_tracing`.
|
||||
* `all` (trace) - For logging that would be overwhelming if `debug` level logging were used.
|
||||
- Can be used for trace level logging. Only used in a few places and not completely supported.
|
||||
- *Note*: In the future a different logging library may provide better trace level logging support. The current logging framework is not performant enough to enable excess trace level output.
|
||||
|
||||
@@ -27,17 +27,38 @@ The `nodeos` service provides query access to the chain database via the HTTP [R
|
||||
|
||||
The `nodeos` service can be run in different "read" modes. These modes control how the node operates and how it processes blocks and transactions:
|
||||
|
||||
- `speculative`: this includes the side effects of confirmed and unconfirmed transactions.
|
||||
- `head`: this only includes the side effects of confirmed transactions, this mode processes unconfirmed transactions but does not include them.
|
||||
- `read-only`: this mode is deprecated. Similar functionality can be achieved by combining options: `read-mode = head`, `p2p-accept-transactions = false`, `api-accept-transactions = false`. When these options are set, the local database will contain state changes made by transactions in the chain up to the head block. Also, transactions received via the P2P network are not relayed and transactions cannot be pushed via the chain API.
|
||||
- `irreversible`: this mode also includes confirmed transactions only up to those included in the last irreversible block.
|
||||
|
||||
A transaction is considered confirmed when a `nodeos` instance has received, processed, and written it to a block on the blockchain, i.e. it is in the head block or an earlier block.
|
||||
|
||||
### Speculative Mode
|
||||
|
||||
Clients such as `cleos` and the RPC API, will see database state as of the current head block plus changes made by all transactions known to this node but potentially not included in the chain, unconfirmed transactions for example.
|
||||
|
||||
Speculative mode is low latency but fragile, there is no guarantee that the transactions reflected in the state will be included in the chain OR that they will reflected in the same order the state implies.
|
||||
|
||||
This mode features the lowest latency, but is the least consistent.
|
||||
|
||||
In speculative mode `nodeos` is able to execute transactions which have TaPoS (Transaction as Proof of Stake) pointing to any valid block in a fork considered to be the best fork by this node.
|
||||
|
||||
### Head Mode
|
||||
|
||||
Clients such as `cleos` and the RPC API will see database state as of the current head block of the chain. Since current head block is not yet irreversible and short-lived forks are possible, state read in this mode may become inaccurate if `nodeos` switches to a better fork.
|
||||
Clients such as `cleos` and the RPC API will see database state as of the current head block of the chain. Since current head block is not yet irreversible and short-lived forks are possible, state read in this mode may become inaccurate if `nodeos` switches to a better fork. Note that this is also true of speculative mode.
|
||||
|
||||
This mode represents a good trade-off between highly consistent views of the data and latency.
|
||||
|
||||
In this mode `nodeos` is able to execute transactions which have TaPoS pointing to any valid block in a fork considered to be the best fork by this node.
|
||||
|
||||
### Read-Only Mode
|
||||
|
||||
[[caution | Deprecation Notice]]
|
||||
| The explicit `read-mode = read-only` mode is deprecated. Similar functionality can now be achieved in `head` mode by combining options: `read-mode = head`, `p2p-accept-transactions = false`, `api-accept-transactions = false`.
|
||||
|
||||
Clients such as `cleos` and the RPC API will see database state as of the current head block of the chain. It **will not** include changes made by transactions known to this node but not included in the chain, such as unconfirmed transactions.
|
||||
|
||||
### Irreversible Mode
|
||||
|
||||
When `nodeos` is configured to be in irreversible read mode, it will still track the most up-to-date blocks in the fork database, but the state will lag behind the current best head block, sometimes referred to as the fork DB head, to always reflect the state of the last irreversible block.
|
||||
|
||||
@@ -44,6 +44,16 @@ Config Options for eosio::http_plugin:
|
||||
--http-server-address arg The local IP and port to listen for
|
||||
incoming http connections; leave blank
|
||||
to disable.
|
||||
--https-server-address arg The local IP and port to listen for
|
||||
incoming https connections; leave blank
|
||||
to disable.
|
||||
--https-certificate-chain-file arg Filename with the certificate chain to
|
||||
present on https connections. PEM
|
||||
format. Required for https.
|
||||
--https-private-key-file arg Filename with https private key in PEM
|
||||
format. Required for https
|
||||
--https-ecdh-curve arg (=secp384r1) Configure https ECDH curve to use:
|
||||
secp384r1 or prime256v1
|
||||
--access-control-allow-origin arg Specify the Access-Control-Allow-Origin
|
||||
to be returned on each request.
|
||||
--access-control-allow-headers arg Specify the Access-Control-Allow-Header
|
||||
@@ -81,6 +91,11 @@ Config Options for eosio::wallet_plugin:
|
||||
number of seconds of inactivity.
|
||||
Activity is defined as any wallet
|
||||
command e.g. list-wallets.
|
||||
--yubihsm-url URL Override default URL of
|
||||
http://localhost:12345 for connecting
|
||||
to yubihsm-connector
|
||||
--yubihsm-authkey key_num Enables YubiHSM support using given
|
||||
Authkey
|
||||
|
||||
Application Config Options:
|
||||
--plugin arg Plugin(s) to enable, may be specified
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
content_title: How To Attach a YubiHSM Hard Wallet
|
||||
link_text: How To Attach a YubiHSM Hard Wallet
|
||||
---
|
||||
|
||||
## Goal
|
||||
|
||||
Attach a YubiHSM as a hard wallet
|
||||
|
||||
## Before you begin
|
||||
|
||||
* Install the currently supported version of `keosd`
|
||||
|
||||
* Install YubiHSM2 Software Toolkit (YubiHSM2 SDK)
|
||||
|
||||
* Create an AuthKey with at least the following Capabilities:
|
||||
|
||||
* sign-ecdsa
|
||||
* generate-asymmetric-key
|
||||
* export-wrapped
|
||||
|
||||
* **Delete the default AuthKey**
|
||||
|
||||
[[warning | Security]]
|
||||
| It is extremely important to create a new AuthKey and remove the default AuthKey before proceed to the following steps.
|
||||
|
||||
## Steps
|
||||
|
||||
### Configure `keosd`
|
||||
|
||||
There are two options to connect `keosd` to YubiHSM:
|
||||
|
||||
#### Using a YubiHSM connector
|
||||
|
||||
By default, `keosd` will connect to the YubiHSM connector on the default host and port. If a non-default URL is used, set the `--yubihsm-url` option or `yubihsm-url` in `config.ini` with the correct connector URL
|
||||
|
||||
#### Directly connect via USB
|
||||
|
||||
`keosd` also can directly connect to YubiHSM via USB protocol
|
||||
|
||||
If this option is used, set `keosd` startup option as the below:
|
||||
|
||||
```sh
|
||||
--yubihsm-url=ysb://
|
||||
```
|
||||
|
||||
### Start `keosd` with AuthKey:
|
||||
|
||||
```sh
|
||||
--yubihsm-authkey Your_AuthKey_Object_Number
|
||||
```
|
||||
|
||||
if a YubiHSM connector is used, check the YubiHSM connector is up and running by visiting YubiHSM URL:
|
||||
http://YubiHSM_HOST:YubiHSM_PORT/connector/status ((Default HOST and Port: http://127.0.0.1:12345)
|
||||
|
||||
You should see something like this:
|
||||
|
||||
```console
|
||||
status=OK
|
||||
serial=*
|
||||
version=2.0.0
|
||||
pid=666
|
||||
address=localhost
|
||||
port=12345
|
||||
```
|
||||
|
||||
### Unlock YubiHSM wallet with the password of AuthKey using the following option:
|
||||
|
||||
```sh
|
||||
cleos wallet unlock -n YubiHSM --password YOUR_AUTHKEY_PASSWORD
|
||||
```
|
||||
|
||||
After unlocking the wallet, you can use `cleos wallet` commands as usual. Beware as a part of security mechanism, some wallet subcommands, such as retrieve private keys, or remove a key, are not supported when a YubiHSM is used
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
content_title: Keosd How-to Guides
|
||||
---
|
||||
|
||||
* [How to attach a YubiHSM hard wallet](how-to-attach-a-yubihsm-hard-wallet.md)
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
content_title: eosio-blocklog
|
||||
link_text: eosio-blocklog
|
||||
---
|
||||
|
||||
`eosio-blocklog` is a command-line interface (CLI) utility that allows node operators to perform low-level tasks on the block logs created by a `nodeos` instance. `eosio-blocklog` can perform one of the following operations:
|
||||
|
||||
* Convert a range of blocks to JSON format, as single objects or array.
|
||||
* Generate `blocks.index` from `blocks.log` in blocks directory.
|
||||
* Trim `blocks.log` and `blocks.index` between a range of blocks.
|
||||
* Perform consistency test between `blocks.log` and `blocks.index`.
|
||||
* Output the results of the operation to a file or `stdout` (default).
|
||||
|
||||
## Usage
|
||||
```sh
|
||||
eosio-blocklog <options> ...
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
Option (=default) | Description
|
||||
-|-
|
||||
`--blocks-dir arg (="blocks")` | The location of the blocks directory (absolute path or relative to the current directory)
|
||||
`-o [ --output-file ] arg` | The file to write the generated output to (absolute or relative path). If not specified then output is to `stdout`
|
||||
`-f [ --first ] arg (=0)` | The first block number to log or the first block to keep if `trim-blocklog` specified
|
||||
`-l [ --last ] arg (=4294967295)` | the last block number to log or the last block to keep if `trim-blocklog` specified
|
||||
`--no-pretty-print` | Do not pretty print the output. Useful if piping to `jq` to improve performance
|
||||
`--as-json-array` | Print out JSON blocks wrapped in JSON array (otherwise the output is free-standing JSON objects)
|
||||
`--make-index` | Create `blocks.index` from `blocks.log`. Must give `blocks-dir` location. Give `output-file` relative to current directory or absolute path (default is `<blocks-dir>/blocks.index`)
|
||||
`--trim-blocklog` | Trim `blocks.log` and `blocks.index`. Must give `blocks-dir` and `first` and/or `last` options.
|
||||
`--smoke-test` | Quick test that `blocks.log` and `blocks.index` are well formed and agree with each other
|
||||
`-h [ --help ]` | Print this help message and exit
|
||||
|
||||
## Remarks
|
||||
|
||||
When `eosio-blocklog` is launched, the utility attempts to perform the specified operation, then yields the following possible outcomes:
|
||||
* If successful, the selected operation is performed and the utility terminates with a zero error code (no error).
|
||||
* If unsuccessful, the utility outputs an error to `stderr` and terminates with a non-zero error code (indicating an error).
|
||||
@@ -5,4 +5,5 @@ link_text: Antelope Utilities
|
||||
|
||||
This section contains documentation for additional utilities that complement or extend `nodeos` and potentially other Antelope software:
|
||||
|
||||
* [eosio-blocklog](eosio-blocklog.md) - Low-level utility for node operators to interact with block log files.
|
||||
* [trace_api_util](trace_api_util.md) - Low-level utility for performing tasks associated with the [Trace API](../01_nodeos/03_plugins/trace_api_plugin/index.md).
|
||||
|
||||
@@ -3,7 +3,6 @@ set(FC_INSTALL_COMPONENT "dev")
|
||||
set(APPBASE_INSTALL_COMPONENT "dev")
|
||||
set(SOFTFLOAT_INSTALL_COMPONENT "dev")
|
||||
set(EOSVM_INSTALL_COMPONENT "dev")
|
||||
set(BN256_INSTALL_COMPONENT "dev")
|
||||
|
||||
add_subdirectory( libfc )
|
||||
add_subdirectory( builtins )
|
||||
@@ -12,7 +11,6 @@ add_subdirectory( wasm-jit )
|
||||
add_subdirectory( chainbase )
|
||||
set(APPBASE_ENABLE_AUTO_VERSION OFF CACHE BOOL "enable automatic discovery of version via 'git describe'")
|
||||
add_subdirectory( appbase )
|
||||
add_subdirectory( custom_appbase )
|
||||
add_subdirectory( chain )
|
||||
add_subdirectory( testing )
|
||||
add_subdirectory( version )
|
||||
@@ -28,4 +26,23 @@ set(ENABLE_PROFILE OFF CACHE BOOL "Enable for profile builds")
|
||||
if(eos-vm IN_LIST EOSIO_WASM_RUNTIMES OR eos-vm-jit IN_LIST EOSIO_WASM_RUNTIMES)
|
||||
add_subdirectory( eos-vm )
|
||||
endif()
|
||||
add_subdirectory( prometheus )
|
||||
|
||||
#yubihsm's openssl discovery is via pkg-config instead of find_package. Help it out on macOS otherwise openssl's pkgconfig
|
||||
# files may not be found down in the /opt/homebrew/opt directory
|
||||
if(APPLE)
|
||||
get_filename_component(OPENSSL_LIB_PATH "${OPENSSL_CRYPTO_LIBRARY}" DIRECTORY)
|
||||
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${OPENSSL_LIB_PATH}/pkgconfig")
|
||||
endif()
|
||||
set(ENABLE_STATIC ON)
|
||||
set(CMAKE_MACOSX_RPATH OFF)
|
||||
set(BUILD_ONLY_LIB ON CACHE BOOL "Library only build")
|
||||
message(STATUS "Starting yubihsm configuration...")
|
||||
add_subdirectory( yubihsm EXCLUDE_FROM_ALL )
|
||||
target_compile_options(yubihsm_static PRIVATE -fno-lto -fcommon)
|
||||
message(STATUS "yubihsm configuration complete")
|
||||
|
||||
get_property(_CTEST_CUSTOM_TESTS_IGNORE GLOBAL PROPERTY CTEST_CUSTOM_TESTS_IGNORE)
|
||||
set_property(GLOBAL PROPERTY CTEST_CUSTOM_TESTS_IGNORE
|
||||
"change_authkey import_ed decrypt_ec decrypt_rsa ssh logs generate_rsa import_ec echo\
|
||||
yubico_otp wrap_data wrap info import_rsa import_authkey generate_hmac generate_ec\
|
||||
attest pbkdf2 parsing ${_CTEST_CUSTOM_TESTS_IGNORE}")
|
||||
|
||||
+1
-1
Submodule libraries/appbase updated: fe1e8ae173...78062207ea
@@ -42,7 +42,7 @@ if("eos-vm-oc" IN_LIST EOSIO_WASM_RUNTIMES)
|
||||
endif()
|
||||
|
||||
llvm_map_components_to_libnames(LLVM_LIBS support core passes mcjit native orcjit)
|
||||
include_directories(SYSTEM ${LLVM_INCLUDE_DIRS})
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
add_definitions(${LLVM_DEFINITIONS})
|
||||
|
||||
option(EOSVMOC_ENABLE_DEVELOPER_OPTIONS "enable developer options for EOS VM OC" OFF)
|
||||
@@ -128,7 +128,7 @@ add_library( eosio_chain
|
||||
${HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries( eosio_chain PUBLIC bn256 fc chainbase eosio_rapidjson Logging IR WAST WASM Runtime
|
||||
target_link_libraries( eosio_chain PUBLIC fc chainbase eosio_rapidjson Logging IR WAST WASM Runtime
|
||||
softfloat builtins ${CHAIN_EOSVM_LIBRARIES} ${LLVM_LIBS} ${CHAIN_RT_LINKAGE}
|
||||
)
|
||||
target_include_directories( eosio_chain
|
||||
|
||||
@@ -70,9 +70,9 @@ namespace eosio { namespace chain {
|
||||
);
|
||||
}
|
||||
|
||||
abi_serializer::abi_serializer( abi_def abi, const yield_function_t& yield ) {
|
||||
abi_serializer::abi_serializer( const abi_def& abi, const yield_function_t& yield ) {
|
||||
configure_built_in_types();
|
||||
set_abi(std::move(abi), yield);
|
||||
set_abi(abi, yield);
|
||||
}
|
||||
|
||||
abi_serializer::abi_serializer( const abi_def& abi, const fc::microseconds& max_serialization_time) {
|
||||
@@ -128,19 +128,11 @@ namespace eosio { namespace chain {
|
||||
built_in_types.emplace("extended_asset", pack_unpack<extended_asset>());
|
||||
}
|
||||
|
||||
void abi_serializer::set_abi(abi_def abi, const yield_function_t& yield) {
|
||||
void abi_serializer::set_abi(const abi_def& abi, const yield_function_t& yield) {
|
||||
impl::abi_traverse_context ctx(yield);
|
||||
|
||||
EOS_ASSERT(starts_with(abi.version, "eosio::abi/1."), unsupported_abi_version_exception, "ABI has an unsupported version");
|
||||
|
||||
size_t types_size = abi.types.size();
|
||||
size_t structs_size = abi.structs.size();
|
||||
size_t actions_size = abi.actions.size();
|
||||
size_t tables_size = abi.tables.size();
|
||||
size_t error_messages_size = abi.error_messages.size();
|
||||
size_t variants_size = abi.variants.value.size();
|
||||
size_t action_results_size = abi.action_results.value.size();
|
||||
|
||||
typedefs.clear();
|
||||
structs.clear();
|
||||
actions.clear();
|
||||
@@ -149,41 +141,41 @@ namespace eosio { namespace chain {
|
||||
variants.clear();
|
||||
action_results.clear();
|
||||
|
||||
for( auto& st : abi.structs )
|
||||
structs[st.name] = std::move(st);
|
||||
for( const auto& st : abi.structs )
|
||||
structs[st.name] = st;
|
||||
|
||||
for( auto& td : abi.types ) {
|
||||
for( const auto& td : abi.types ) {
|
||||
EOS_ASSERT(!_is_type(td.new_type_name, ctx), duplicate_abi_type_def_exception,
|
||||
"type already exists", ("new_type_name",impl::limit_size(td.new_type_name)));
|
||||
typedefs[std::move(td.new_type_name)] = std::move(td.type);
|
||||
typedefs[td.new_type_name] = td.type;
|
||||
}
|
||||
|
||||
for( auto& a : abi.actions )
|
||||
actions[std::move(a.name)] = std::move(a.type);
|
||||
for( const auto& a : abi.actions )
|
||||
actions[a.name] = a.type;
|
||||
|
||||
for( auto& t : abi.tables )
|
||||
tables[std::move(t.name)] = std::move(t.type);
|
||||
for( const auto& t : abi.tables )
|
||||
tables[t.name] = t.type;
|
||||
|
||||
for( auto& e : abi.error_messages )
|
||||
error_messages[std::move(e.error_code)] = std::move(e.error_msg);
|
||||
for( const auto& e : abi.error_messages )
|
||||
error_messages[e.error_code] = e.error_msg;
|
||||
|
||||
for( auto& v : abi.variants.value )
|
||||
variants[v.name] = std::move(v);
|
||||
for( const auto& v : abi.variants.value )
|
||||
variants[v.name] = v;
|
||||
|
||||
for( auto& r : abi.action_results.value )
|
||||
action_results[std::move(r.name)] = std::move(r.result_type);
|
||||
for( const auto& r : abi.action_results.value )
|
||||
action_results[r.name] = r.result_type;
|
||||
|
||||
/**
|
||||
* The ABI vector may contain duplicates which would make it
|
||||
* an invalid ABI
|
||||
*/
|
||||
EOS_ASSERT( typedefs.size() == types_size, duplicate_abi_type_def_exception, "duplicate type definition detected" );
|
||||
EOS_ASSERT( structs.size() == structs_size, duplicate_abi_struct_def_exception, "duplicate struct definition detected" );
|
||||
EOS_ASSERT( actions.size() == actions_size, duplicate_abi_action_def_exception, "duplicate action definition detected" );
|
||||
EOS_ASSERT( tables.size() == tables_size, duplicate_abi_table_def_exception, "duplicate table definition detected" );
|
||||
EOS_ASSERT( error_messages.size() == error_messages_size, duplicate_abi_err_msg_def_exception, "duplicate error message definition detected" );
|
||||
EOS_ASSERT( variants.size() == variants_size, duplicate_abi_variant_def_exception, "duplicate variant definition detected" );
|
||||
EOS_ASSERT( action_results.size() == action_results_size, duplicate_abi_action_results_def_exception, "duplicate action results definition detected" );
|
||||
EOS_ASSERT( typedefs.size() == abi.types.size(), duplicate_abi_type_def_exception, "duplicate type definition detected" );
|
||||
EOS_ASSERT( structs.size() == abi.structs.size(), duplicate_abi_struct_def_exception, "duplicate struct definition detected" );
|
||||
EOS_ASSERT( actions.size() == abi.actions.size(), duplicate_abi_action_def_exception, "duplicate action definition detected" );
|
||||
EOS_ASSERT( tables.size() == abi.tables.size(), duplicate_abi_table_def_exception, "duplicate table definition detected" );
|
||||
EOS_ASSERT( error_messages.size() == abi.error_messages.size(), duplicate_abi_err_msg_def_exception, "duplicate error message definition detected" );
|
||||
EOS_ASSERT( variants.size() == abi.variants.value.size(), duplicate_abi_variant_def_exception, "duplicate variant definition detected" );
|
||||
EOS_ASSERT( action_results.size() == abi.action_results.value.size(), duplicate_abi_action_results_def_exception, "duplicate action results definition detected" );
|
||||
|
||||
validate(ctx);
|
||||
}
|
||||
@@ -543,14 +535,15 @@ namespace eosio { namespace chain {
|
||||
bool disallow_additional_fields = false;
|
||||
for( uint32_t i = 0; i < st.fields.size(); ++i ) {
|
||||
const auto& field = st.fields[i];
|
||||
if( vo.contains( string(field.name).c_str() ) ) {
|
||||
bool present = vo.contains(string(field.name).c_str());
|
||||
if( present || is_optional(field.type) ) {
|
||||
if( disallow_additional_fields )
|
||||
EOS_THROW( pack_exception, "Unexpected field '${f}' found in input object while processing struct '${p}'",
|
||||
("f", ctx.maybe_shorten(field.name))("p", ctx.get_path_string()) );
|
||||
{
|
||||
auto h1 = ctx.push_to_path( impl::field_path_item{ .parent_struct_itr = s_itr, .field_ordinal = i } );
|
||||
auto h2 = ctx.disallow_extensions_unless( &field == &st.fields.back() );
|
||||
_variant_to_binary(_remove_bin_extension(field.type), vo[field.name], ds, ctx);
|
||||
_variant_to_binary(_remove_bin_extension(field.type), present ? vo[field.name] : fc::variant(nullptr), ds, ctx);
|
||||
}
|
||||
} else if( ends_with(field.type, "$") && ctx.extensions_allowed() ) {
|
||||
disallow_additional_fields = true;
|
||||
|
||||
@@ -75,7 +75,7 @@ void apply_context::exec_one()
|
||||
privileged = receiver_account->is_privileged();
|
||||
auto native = control.find_apply_handler( receiver, act->account, act->name );
|
||||
if( native ) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_speculative_block() ) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
@@ -89,7 +89,7 @@ void apply_context::exec_one()
|
||||
|| control.is_builtin_activated( builtin_protocol_feature_t::forward_setcode )
|
||||
)
|
||||
) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_speculative_block() ) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
@@ -182,7 +182,7 @@ void apply_context::exec_one()
|
||||
print_debug(receiver, trace);
|
||||
}
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()))
|
||||
if (auto dm_logger = control.get_deep_mind_logger())
|
||||
{
|
||||
dm_logger->on_end_action();
|
||||
}
|
||||
@@ -289,7 +289,7 @@ void apply_context::require_recipient( account_name recipient ) {
|
||||
schedule_action( action_ordinal, recipient, false )
|
||||
);
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_require_recipient();
|
||||
}
|
||||
}
|
||||
@@ -316,12 +316,12 @@ void apply_context::execute_inline( action&& a ) {
|
||||
EOS_ASSERT( code != nullptr, action_validate_exception,
|
||||
"inline action's code account ${account} does not exist", ("account", a.account) );
|
||||
|
||||
bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_speculative_block();
|
||||
bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block();
|
||||
flat_set<account_name> actors;
|
||||
|
||||
bool disallow_send_to_self_bypass = control.is_builtin_activated( builtin_protocol_feature_t::restrict_action_to_self );
|
||||
bool send_to_self = (a.account == receiver);
|
||||
bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act->account) && control.is_speculative_block());
|
||||
bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act->account) && control.is_producing_block());
|
||||
|
||||
flat_set<permission_level> inherited_authorizations;
|
||||
if( inherit_parent_authorizations ) {
|
||||
@@ -347,14 +347,14 @@ void apply_context::execute_inline( action&& a ) {
|
||||
control.check_actor_list( actors );
|
||||
}
|
||||
|
||||
if( !privileged && control.is_speculative_block() ) {
|
||||
if( !privileged && control.is_producing_block() ) {
|
||||
const auto& chain_config = control.get_global_properties().configuration;
|
||||
EOS_ASSERT( a.data.size() < std::min(chain_config.max_inline_action_size, control.get_max_nonprivileged_inline_action_size()),
|
||||
inline_action_too_big_nonprivileged,
|
||||
"inline action too big for nonprivileged account ${account}", ("account", a.account));
|
||||
}
|
||||
// No need to check authorization if replaying irreversible blocks or contract is privileged
|
||||
if( !control.skip_auth_check() && !privileged && !trx_context.is_read_only() ) {
|
||||
if( !control.skip_auth_check() && !privileged ) {
|
||||
try {
|
||||
control.get_authorization_manager()
|
||||
.check_authorization( {a},
|
||||
@@ -363,7 +363,7 @@ void apply_context::execute_inline( action&& a ) {
|
||||
control.pending_block_time() - trx_context.published,
|
||||
std::bind(&transaction_context::checktime, &this->trx_context),
|
||||
false,
|
||||
trx_context.is_dry_run(), // check_but_dont_fail
|
||||
trx_context.is_read_only,
|
||||
inherited_authorizations
|
||||
);
|
||||
|
||||
@@ -373,7 +373,7 @@ void apply_context::execute_inline( action&& a ) {
|
||||
} catch( const fc::exception& e ) {
|
||||
if( disallow_send_to_self_bypass || !send_to_self ) {
|
||||
throw;
|
||||
} else if( control.is_speculative_block() ) {
|
||||
} else if( control.is_producing_block() ) {
|
||||
subjective_block_production_exception new_exception(FC_LOG_MESSAGE( error, "Authorization failure with inline action sent to self"));
|
||||
for (const auto& log: e.get_log()) {
|
||||
new_exception.append_log(log);
|
||||
@@ -383,7 +383,7 @@ void apply_context::execute_inline( action&& a ) {
|
||||
} catch( ... ) {
|
||||
if( disallow_send_to_self_bypass || !send_to_self ) {
|
||||
throw;
|
||||
} else if( control.is_speculative_block() ) {
|
||||
} else if( control.is_producing_block() ) {
|
||||
EOS_THROW(subjective_block_production_exception, "Unexpected exception occurred validating inline action sent to self");
|
||||
}
|
||||
}
|
||||
@@ -394,7 +394,7 @@ void apply_context::execute_inline( action&& a ) {
|
||||
schedule_action( std::move(a), inline_receiver, false )
|
||||
);
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_send_inline();
|
||||
}
|
||||
}
|
||||
@@ -407,7 +407,7 @@ void apply_context::execute_context_free_inline( action&& a ) {
|
||||
EOS_ASSERT( a.authorization.size() == 0, action_validate_exception,
|
||||
"context-free actions cannot have authorizations" );
|
||||
|
||||
if( !privileged && control.is_speculative_block() ) {
|
||||
if( !privileged && control.is_producing_block() ) {
|
||||
const auto& chain_config = control.get_global_properties().configuration;
|
||||
EOS_ASSERT( a.data.size() < std::min(chain_config.max_inline_action_size, control.get_max_nonprivileged_inline_action_size()),
|
||||
inline_action_too_big_nonprivileged,
|
||||
@@ -419,17 +419,16 @@ void apply_context::execute_context_free_inline( action&& a ) {
|
||||
schedule_action( std::move(a), inline_receiver, true )
|
||||
);
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_send_context_free_inline();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ) {
|
||||
EOS_ASSERT( !trx_context.is_read_only(), transaction_exception, "cannot schedule a deferred transaction from within a readonly transaction" );
|
||||
EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" );
|
||||
|
||||
bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_speculative_block()
|
||||
bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block()
|
||||
&& !control.sender_avoids_whitelist_blacklist_enforcement( receiver );
|
||||
trx_context.validate_referenced_accounts( trx, enforce_actor_whitelist_blacklist );
|
||||
|
||||
@@ -531,7 +530,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
|
||||
} catch( const fc::exception& e ) {
|
||||
if( disallow_send_to_self_bypass || !is_sending_only_to_self(receiver) ) {
|
||||
throw;
|
||||
} else if( control.is_speculative_block() ) {
|
||||
} else if( control.is_producing_block() ) {
|
||||
subjective_block_production_exception new_exception(FC_LOG_MESSAGE( error, "Authorization failure with sent deferred transaction consisting only of actions to self"));
|
||||
for (const auto& log: e.get_log()) {
|
||||
new_exception.append_log(log);
|
||||
@@ -541,7 +540,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
|
||||
} catch( ... ) {
|
||||
if( disallow_send_to_self_bypass || !is_sending_only_to_self(receiver) ) {
|
||||
throw;
|
||||
} else if( control.is_speculative_block() ) {
|
||||
} else if( control.is_producing_block() ) {
|
||||
EOS_THROW(subjective_block_production_exception, "Unexpected exception occurred validating sent deferred transaction consisting only of actions to self");
|
||||
}
|
||||
}
|
||||
@@ -553,12 +552,12 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
|
||||
|
||||
bool replace_deferred_activated = control.is_builtin_activated(builtin_protocol_feature_t::replace_deferred);
|
||||
|
||||
EOS_ASSERT( replace_deferred_activated || !control.is_speculative_block()
|
||||
EOS_ASSERT( replace_deferred_activated || !control.is_producing_block()
|
||||
|| control.all_subjective_mitigations_disabled(),
|
||||
subjective_block_production_exception,
|
||||
"Replacing a deferred transaction is temporarily disabled." );
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", ptr->id)), "deferred_trx", "cancel", "deferred_trx_cancel");
|
||||
}
|
||||
|
||||
@@ -576,7 +575,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
|
||||
trx_id_for_new_obj = ptr->trx_id;
|
||||
}
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_cancel_deferred(deep_mind_handler::operation_qualifier::modify, *ptr);
|
||||
}
|
||||
|
||||
@@ -593,7 +592,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
|
||||
|
||||
trx_size = gtx.set( trx );
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_send_deferred(deep_mind_handler::operation_qualifier::modify, gtx);
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", gtx.id)), "deferred_trx", "update", "deferred_trx_add");
|
||||
}
|
||||
@@ -610,7 +609,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
|
||||
|
||||
trx_size = gtx.set( trx );
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_send_deferred(deep_mind_handler::operation_qualifier::none, gtx);
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", gtx.id)), "deferred_trx", "add", "deferred_trx_add");
|
||||
}
|
||||
@@ -627,11 +626,10 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
|
||||
}
|
||||
|
||||
bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, account_name sender ) {
|
||||
EOS_ASSERT( !trx_context.is_read_only(), transaction_exception, "cannot cancel a deferred transaction from within a readonly transaction" );
|
||||
auto& generated_transaction_idx = db.get_mutable_index<generated_transaction_multi_index>();
|
||||
const auto* gto = db.find<generated_transaction_object,by_sender_id>(boost::make_tuple(sender, sender_id));
|
||||
if ( gto ) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_cancel_deferred(deep_mind_handler::operation_qualifier::none, *gto);
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", gto->id)), "deferred_trx", "cancel", "deferred_trx_cancel");
|
||||
}
|
||||
@@ -672,7 +670,7 @@ const table_id_object& apply_context::find_or_create_table( name code, name scop
|
||||
return *existing_tid;
|
||||
}
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
std::string event_id = RAM_EVENT_ID("${code}:${scope}:${table}",
|
||||
("code", code)
|
||||
("scope", scope)
|
||||
@@ -689,14 +687,14 @@ const table_id_object& apply_context::find_or_create_table( name code, name scop
|
||||
t_id.table = table;
|
||||
t_id.payer = payer;
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_create_table(t_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void apply_context::remove_table( const table_id_object& tid ) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
std::string event_id = RAM_EVENT_ID("${code}:${scope}:${table}",
|
||||
("code", tid.code)
|
||||
("scope", tid.scope)
|
||||
@@ -707,7 +705,7 @@ void apply_context::remove_table( const table_id_object& tid ) {
|
||||
|
||||
update_db_usage(tid.payer, - config::billable_size_v<table_id_object>);
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_remove_table(tid);
|
||||
}
|
||||
|
||||
@@ -780,13 +778,11 @@ int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t b
|
||||
}
|
||||
|
||||
int apply_context::db_store_i64( name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) {
|
||||
EOS_ASSERT( !trx_context.is_read_only(), table_operation_not_permitted, "cannot store a db record when executing a readonly transaction" );
|
||||
return db_store_i64( receiver, scope, table, payer, id, buffer, buffer_size);
|
||||
}
|
||||
|
||||
int apply_context::db_store_i64( name code, name scope, name table, const account_name& payer, uint64_t id, const char* buffer, size_t buffer_size ) {
|
||||
// require_write_lock( scope );
|
||||
EOS_ASSERT( !trx_context.is_read_only(), table_operation_not_permitted, "cannot store a db record when executing a readonly transaction" );
|
||||
const auto& tab = find_or_create_table( code, scope, table, payer );
|
||||
auto tableid = tab.id;
|
||||
|
||||
@@ -805,7 +801,7 @@ int apply_context::db_store_i64( name code, name scope, name table, const accoun
|
||||
|
||||
int64_t billable_size = (int64_t)(buffer_size + config::billable_size_v<key_value_object>);
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
std::string event_id = RAM_EVENT_ID("${table_code}:${scope}:${table_name}:${primkey}",
|
||||
("table_code", tab.code)
|
||||
("scope", tab.scope)
|
||||
@@ -817,7 +813,7 @@ int apply_context::db_store_i64( name code, name scope, name table, const accoun
|
||||
|
||||
update_db_usage( payer, billable_size);
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_db_store_i64(tab, obj);
|
||||
}
|
||||
|
||||
@@ -826,7 +822,6 @@ int apply_context::db_store_i64( name code, name scope, name table, const accoun
|
||||
}
|
||||
|
||||
void apply_context::db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size ) {
|
||||
EOS_ASSERT( !trx_context.is_read_only(), table_operation_not_permitted, "cannot update a db record when executing a readonly transaction" );
|
||||
const key_value_object& obj = keyval_cache.get( iterator );
|
||||
|
||||
const auto& table_obj = keyval_cache.get_table( obj.t_id );
|
||||
@@ -841,7 +836,7 @@ void apply_context::db_update_i64( int iterator, account_name payer, const char*
|
||||
if( payer == account_name() ) payer = obj.payer;
|
||||
|
||||
std::string event_id;
|
||||
if (control.get_deep_mind_logger(trx_context.is_transient()) != nullptr) {
|
||||
if (control.get_deep_mind_logger() != nullptr) {
|
||||
event_id = RAM_EVENT_ID("${table_code}:${scope}:${table_name}:${primkey}",
|
||||
("table_code", table_obj.code)
|
||||
("scope", table_obj.scope)
|
||||
@@ -852,27 +847,27 @@ void apply_context::db_update_i64( int iterator, account_name payer, const char*
|
||||
|
||||
if( account_name(obj.payer) != payer ) {
|
||||
// refund the existing payer
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()))
|
||||
if (auto dm_logger = control.get_deep_mind_logger())
|
||||
{
|
||||
dm_logger->on_ram_trace(std::string(event_id), "table_row", "remove", "primary_index_update_remove_old_payer");
|
||||
}
|
||||
update_db_usage( obj.payer, -(old_size) );
|
||||
// charge the new payer
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()))
|
||||
if (auto dm_logger = control.get_deep_mind_logger())
|
||||
{
|
||||
dm_logger->on_ram_trace(std::move(event_id), "table_row", "add", "primary_index_update_add_new_payer");
|
||||
}
|
||||
update_db_usage( payer, (new_size));
|
||||
} else if(old_size != new_size) {
|
||||
// charge/refund the existing payer the difference
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient()))
|
||||
if (auto dm_logger = control.get_deep_mind_logger())
|
||||
{
|
||||
dm_logger->on_ram_trace(std::move(event_id) , "table_row", "update", "primary_index_update");
|
||||
}
|
||||
update_db_usage( obj.payer, new_size - old_size);
|
||||
}
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_db_update_i64(table_obj, obj, payer, buffer, buffer_size);
|
||||
}
|
||||
|
||||
@@ -883,7 +878,6 @@ void apply_context::db_update_i64( int iterator, account_name payer, const char*
|
||||
}
|
||||
|
||||
void apply_context::db_remove_i64( int iterator ) {
|
||||
EOS_ASSERT( !trx_context.is_read_only(), table_operation_not_permitted, "cannot remove a db record when executing a readonly transaction" );
|
||||
const key_value_object& obj = keyval_cache.get( iterator );
|
||||
|
||||
const auto& table_obj = keyval_cache.get_table( obj.t_id );
|
||||
@@ -891,7 +885,7 @@ void apply_context::db_remove_i64( int iterator ) {
|
||||
|
||||
// require_write_lock( table_obj.scope );
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
std::string event_id = RAM_EVENT_ID("${table_code}:${scope}:${table_name}:${primkey}",
|
||||
("table_code", table_obj.code)
|
||||
("scope", table_obj.scope)
|
||||
@@ -903,7 +897,7 @@ void apply_context::db_remove_i64( int iterator ) {
|
||||
|
||||
update_db_usage( obj.payer, -(obj.value.size() + config::billable_size_v<key_value_object>) );
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_db_remove_i64(table_obj, obj);
|
||||
}
|
||||
|
||||
@@ -1035,27 +1029,17 @@ int apply_context::db_end_i64( name code, name scope, name table ) {
|
||||
|
||||
uint64_t apply_context::next_global_sequence() {
|
||||
const auto& p = control.get_dynamic_global_properties();
|
||||
if ( trx_context.is_read_only() ) {
|
||||
// To avoid confusion of duplicated global sequence number, hard code to be 0.
|
||||
return 0;
|
||||
} else {
|
||||
db.modify( p, [&]( auto& dgp ) {
|
||||
++dgp.global_action_sequence;
|
||||
});
|
||||
return p.global_action_sequence;
|
||||
}
|
||||
db.modify( p, [&]( auto& dgp ) {
|
||||
++dgp.global_action_sequence;
|
||||
});
|
||||
return p.global_action_sequence;
|
||||
}
|
||||
|
||||
uint64_t apply_context::next_recv_sequence( const account_metadata_object& receiver_account ) {
|
||||
if ( trx_context.is_read_only() ) {
|
||||
// To avoid confusion of duplicated receive sequence number, hard code to be 0.
|
||||
return 0;
|
||||
} else {
|
||||
db.modify( receiver_account, [&]( auto& ra ) {
|
||||
++ra.recv_sequence;
|
||||
});
|
||||
return receiver_account.recv_sequence;
|
||||
}
|
||||
db.modify( receiver_account, [&]( auto& ra ) {
|
||||
++ra.recv_sequence;
|
||||
});
|
||||
return receiver_account.recv_sequence;
|
||||
}
|
||||
uint64_t apply_context::next_auth_sequence( account_name actor ) {
|
||||
const auto& amo = db.get<account_metadata_object,by_name>( actor );
|
||||
|
||||
@@ -134,7 +134,6 @@ namespace eosio { namespace chain {
|
||||
permission_name name,
|
||||
permission_id_type parent,
|
||||
const authority& auth,
|
||||
bool is_trx_transient,
|
||||
time_point initial_creation_time
|
||||
)
|
||||
{
|
||||
@@ -159,7 +158,7 @@ namespace eosio { namespace chain {
|
||||
p.last_updated = creation_time;
|
||||
p.auth = auth;
|
||||
|
||||
if (auto dm_logger = _control.get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = _control.get_deep_mind_logger()) {
|
||||
dm_logger->on_create_permission(p);
|
||||
}
|
||||
});
|
||||
@@ -170,7 +169,6 @@ namespace eosio { namespace chain {
|
||||
permission_name name,
|
||||
permission_id_type parent,
|
||||
authority&& auth,
|
||||
bool is_trx_transient,
|
||||
time_point initial_creation_time
|
||||
)
|
||||
{
|
||||
@@ -195,20 +193,20 @@ namespace eosio { namespace chain {
|
||||
p.last_updated = creation_time;
|
||||
p.auth = std::move(auth);
|
||||
|
||||
if (auto dm_logger = _control.get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = _control.get_deep_mind_logger()) {
|
||||
dm_logger->on_create_permission(p);
|
||||
}
|
||||
});
|
||||
return perm;
|
||||
}
|
||||
|
||||
void authorization_manager::modify_permission( const permission_object& permission, const authority& auth, bool is_trx_transient ) {
|
||||
void authorization_manager::modify_permission( const permission_object& permission, const authority& auth ) {
|
||||
for(const key_weight& k: auth.keys)
|
||||
EOS_ASSERT(k.key.which() < _db.get<protocol_state_object>().num_supported_key_types, unactivated_key_type,
|
||||
"Unactivated key type used when modifying permission");
|
||||
|
||||
_db.modify( permission, [&](permission_object& po) {
|
||||
auto dm_logger = _control.get_deep_mind_logger(is_trx_transient);
|
||||
auto dm_logger = _control.get_deep_mind_logger();
|
||||
|
||||
std::optional<permission_object> old_permission;
|
||||
if (dm_logger) {
|
||||
@@ -218,13 +216,13 @@ namespace eosio { namespace chain {
|
||||
po.auth = auth;
|
||||
po.last_updated = _control.pending_block_time();
|
||||
|
||||
if (auto dm_logger = _control.get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = _control.get_deep_mind_logger()) {
|
||||
dm_logger->on_modify_permission(*old_permission, po);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void authorization_manager::remove_permission( const permission_object& permission, bool is_trx_transient ) {
|
||||
void authorization_manager::remove_permission( const permission_object& permission ) {
|
||||
const auto& index = _db.template get_index<permission_index, by_parent>();
|
||||
auto range = index.equal_range(permission.id);
|
||||
EOS_ASSERT( range.first == range.second, action_validate_exception,
|
||||
@@ -232,7 +230,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
_db.get_mutable_index<permission_usage_index>().remove_object( permission.usage_id._id );
|
||||
|
||||
if (auto dm_logger = _control.get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = _control.get_deep_mind_logger()) {
|
||||
dm_logger->on_remove_permission(permission);
|
||||
}
|
||||
|
||||
@@ -559,8 +557,8 @@ namespace eosio { namespace chain {
|
||||
|
||||
}
|
||||
|
||||
if( !allow_unused_keys || check_but_dont_fail) {
|
||||
EOS_ASSERT( checker.all_keys_used(), tx_irrelevant_sig,
|
||||
if( !allow_unused_keys ) {
|
||||
EOS_ASSERT( checker.all_keys_used() || check_but_dont_fail, tx_irrelevant_sig,
|
||||
"transaction bears irrelevant signatures from these keys: ${keys}",
|
||||
("keys", checker.unused_keys()) );
|
||||
}
|
||||
|
||||
+1350
-1506
File diff suppressed because it is too large
Load Diff
+179
-245
@@ -34,7 +34,6 @@
|
||||
#include <fc/variant_object.hpp>
|
||||
|
||||
#include <new>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
@@ -156,7 +155,7 @@ struct pending_state {
|
||||
|
||||
maybe_session _db_session;
|
||||
block_stage_type _block_stage;
|
||||
controller::block_status _block_status = controller::block_status::ephemeral;
|
||||
controller::block_status _block_status = controller::block_status::incomplete;
|
||||
std::optional<block_id_type> _producer_block_id;
|
||||
controller::block_report _block_report{};
|
||||
|
||||
@@ -225,38 +224,30 @@ struct controller_impl {
|
||||
std::optional<pending_state> pending;
|
||||
block_state_ptr head;
|
||||
fork_database fork_db;
|
||||
wasm_interface wasmif;
|
||||
resource_limits_manager resource_limits;
|
||||
authorization_manager authorization;
|
||||
protocol_feature_manager protocol_features;
|
||||
controller::config conf;
|
||||
const chain_id_type chain_id; // read by thread_pool threads, value will not be changed
|
||||
bool replaying = false;
|
||||
db_read_mode read_mode = db_read_mode::HEAD;
|
||||
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
|
||||
std::optional<fc::microseconds> subjective_cpu_leeway;
|
||||
bool trusted_producer_light_validation = false;
|
||||
uint32_t snapshot_head_block = 0;
|
||||
struct chain; // chain is a namespace so use an embedded type for the named_thread_pool tag
|
||||
named_thread_pool<chain> thread_pool;
|
||||
named_thread_pool thread_pool;
|
||||
platform_timer timer;
|
||||
deep_mind_handler* deep_mind_logger = nullptr;
|
||||
bool okay_to_print_integrity_hash_on_stop = false;
|
||||
|
||||
std::thread::id main_thread_id;
|
||||
thread_local static platform_timer timer; // a copy for main thread and each read-only thread
|
||||
#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
|
||||
thread_local static vm::wasm_allocator wasm_alloc; // a copy for main thread and each read-only thread
|
||||
vm::wasm_allocator wasm_alloc;
|
||||
#endif
|
||||
// Ideally wasmif should be thread_local which must be a static.
|
||||
// Unittests can create multiple controller objects (testers) at the same time,
|
||||
// which overwrites the same static wasmif, is used for eosvmoc too.
|
||||
wasm_interface wasmif; // used by main thread and all threads for EOSVMOC
|
||||
thread_local static std::unique_ptr<wasm_interface> wasmif_thread_local; // a copy for each read-only thread, used by eos-vm and eos-vm-jit
|
||||
|
||||
typedef pair<scope_name,action_name> handler_key;
|
||||
map< account_name, map<handler_key, apply_handler> > apply_handlers;
|
||||
unordered_map< builtin_protocol_feature_t, std::function<void(controller_impl&)>, enum_hash<builtin_protocol_feature_t> > protocol_feature_activation_handlers;
|
||||
|
||||
|
||||
void pop_block() {
|
||||
auto prev = fork_db.get_block( head->header.previous );
|
||||
|
||||
@@ -265,7 +256,7 @@ struct controller_impl {
|
||||
prev = fork_db.root();
|
||||
}
|
||||
|
||||
if ( read_mode == db_read_mode::HEAD ) {
|
||||
if ( read_mode == db_read_mode::SPECULATIVE ) {
|
||||
EOS_ASSERT( head->block, block_validate_exception, "attempting to pop a block that was sparsely loaded from a snapshot");
|
||||
}
|
||||
|
||||
@@ -301,17 +292,16 @@ struct controller_impl {
|
||||
db( cfg.state_dir,
|
||||
cfg.read_only ? database::read_only : database::read_write,
|
||||
cfg.state_size, false, cfg.db_map_mode ),
|
||||
blog( cfg.blocks_dir, cfg.blog ),
|
||||
blog( cfg.blocks_dir, cfg.prune_config ),
|
||||
fork_db( cfg.blocks_dir / config::reversible_blocks_dir_name ),
|
||||
resource_limits( db, [&s](bool is_trx_transient) { return s.get_deep_mind_logger(is_trx_transient); }),
|
||||
wasmif( cfg.wasm_runtime, cfg.eosvmoc_tierup, db, cfg.state_dir, cfg.eosvmoc_config, !cfg.profile_accounts.empty() ),
|
||||
resource_limits( db, [&s]() { return s.get_deep_mind_logger(); }),
|
||||
authorization( s, db ),
|
||||
protocol_features( std::move(pfs), [&s](bool is_trx_transient) { return s.get_deep_mind_logger(is_trx_transient); } ),
|
||||
protocol_features( std::move(pfs), [&s]() { return s.get_deep_mind_logger(); } ),
|
||||
conf( cfg ),
|
||||
chain_id( chain_id ),
|
||||
read_mode( cfg.read_mode ),
|
||||
thread_pool(),
|
||||
main_thread_id( std::this_thread::get_id() ),
|
||||
wasmif( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty() )
|
||||
thread_pool( "chain", cfg.thread_pool_size )
|
||||
{
|
||||
fork_db.open( [this]( block_timestamp_type timestamp,
|
||||
const flat_set<digest_type>& cur_features,
|
||||
@@ -319,11 +309,6 @@ struct controller_impl {
|
||||
{ check_protocol_features( timestamp, cur_features, new_features ); }
|
||||
);
|
||||
|
||||
thread_pool.start( cfg.thread_pool_size, [this]( const fc::exception& e ) {
|
||||
elog( "Exception in chain thread pool, exiting: ${e}", ("e", e.to_detail_string()) );
|
||||
if( shutdown ) shutdown();
|
||||
} );
|
||||
|
||||
set_activation_handler<builtin_protocol_feature_t::preactivate_feature>();
|
||||
set_activation_handler<builtin_protocol_feature_t::replace_deferred>();
|
||||
set_activation_handler<builtin_protocol_feature_t::get_sender>();
|
||||
@@ -337,7 +322,7 @@ struct controller_impl {
|
||||
set_activation_handler<builtin_protocol_feature_t::crypto_primitives>();
|
||||
|
||||
self.irreversible_block.connect([this](const block_state_ptr& bsp) {
|
||||
get_wasm_interface().current_lib(bsp->block_num);
|
||||
wasmif.current_lib(bsp->block_num);
|
||||
});
|
||||
|
||||
|
||||
@@ -393,10 +378,7 @@ struct controller_impl {
|
||||
}
|
||||
|
||||
void dmlog_applied_transaction(const transaction_trace_ptr& t) {
|
||||
// dmlog_applied_transaction is called by push_scheduled_transaction
|
||||
// where transient transactions are not possible, and by push_transaction
|
||||
// only when the transaction is not transient
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_applied_transaction(self.head_block_num() + 1, t);
|
||||
}
|
||||
}
|
||||
@@ -404,21 +386,20 @@ struct controller_impl {
|
||||
void log_irreversible() {
|
||||
EOS_ASSERT( fork_db.root(), fork_database_exception, "fork database not properly initialized" );
|
||||
|
||||
const block_id_type log_head_id = blog.head_id();
|
||||
const bool valid_log_head = !log_head_id.empty();
|
||||
const auto& log_head = blog.head();
|
||||
|
||||
const auto lib_num = valid_log_head ? block_header::num_from_id(log_head_id) : (blog.first_block_num() - 1);
|
||||
auto lib_num = log_head ? log_head->block_num() : (blog.first_block_num() - 1);
|
||||
|
||||
auto root_id = fork_db.root()->id;
|
||||
|
||||
if( valid_log_head ) {
|
||||
EOS_ASSERT( root_id == log_head_id, fork_database_exception, "fork database root does not match block log head" );
|
||||
if( log_head ) {
|
||||
EOS_ASSERT( root_id == blog.head_id(), fork_database_exception, "fork database root does not match block log head" );
|
||||
} else {
|
||||
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. root block number: ${block_num}, lib: ${lib_num}", ("block_num", fork_db.root()->block_num) ("lib_num", lib_num) );
|
||||
}
|
||||
|
||||
const auto fork_head = fork_db_head();
|
||||
auto fork_head = (read_mode == db_read_mode::IRREVERSIBLE) ? fork_db.pending_head() : fork_db.head();
|
||||
|
||||
if( fork_head->dpos_irreversible_blocknum <= lib_num )
|
||||
return;
|
||||
@@ -429,7 +410,7 @@ struct controller_impl {
|
||||
std::vector<std::future<std::vector<char>>> v;
|
||||
v.reserve( branch.size() );
|
||||
for( auto bitr = branch.rbegin(); bitr != branch.rend(); ++bitr ) {
|
||||
v.emplace_back( post_async_task( thread_pool.get_executor(), [b=(*bitr)->block]() { return fc::raw::pack(*b); } ) );
|
||||
v.emplace_back( async_thread_pool( thread_pool.get_executor(), [b=(*bitr)->block]() { return fc::raw::pack(*b); } ) );
|
||||
}
|
||||
auto it = v.begin();
|
||||
|
||||
@@ -497,9 +478,10 @@ struct controller_impl {
|
||||
|
||||
void replay(std::function<bool()> check_shutdown) {
|
||||
auto blog_head = blog.head();
|
||||
if( !blog_head && !fork_db.root() ) {
|
||||
if( !fork_db.root() ) {
|
||||
fork_db.reset( *head );
|
||||
return;
|
||||
if (!blog_head)
|
||||
return;
|
||||
}
|
||||
|
||||
replaying = true;
|
||||
@@ -583,8 +565,8 @@ struct controller_impl {
|
||||
ilog( "Starting initialization from snapshot, this may take a significant amount of time" );
|
||||
try {
|
||||
snapshot->validate();
|
||||
if( auto blog_head = blog.head() ) {
|
||||
read_from_snapshot( snapshot, blog.first_block_num(), blog_head->block_num() );
|
||||
if( blog.head() ) {
|
||||
read_from_snapshot( snapshot, blog.first_block_num(), blog.head()->block_num() );
|
||||
} else {
|
||||
read_from_snapshot( snapshot, 0, std::numeric_limits<uint32_t>::max() );
|
||||
const uint32_t lib_num = head->block_num;
|
||||
@@ -600,6 +582,10 @@ struct controller_impl {
|
||||
elog( "Failed initialization from snapshot - db storage not configured to have enough storage for the provided snapshot, please increase and retry snapshot" );
|
||||
shutdown();
|
||||
}
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown, const genesis_state& genesis) {
|
||||
@@ -633,6 +619,10 @@ struct controller_impl {
|
||||
blog.reset( genesis, head->block );
|
||||
}
|
||||
init(check_shutdown);
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown) {
|
||||
@@ -642,15 +632,15 @@ struct controller_impl {
|
||||
this->shutdown = shutdown;
|
||||
uint32_t lib_num = fork_db.root()->block_num;
|
||||
auto first_block_num = blog.first_block_num();
|
||||
if( auto blog_head = blog.head() ) {
|
||||
EOS_ASSERT( first_block_num <= lib_num && lib_num <= blog_head->block_num(),
|
||||
if( blog.head() ) {
|
||||
EOS_ASSERT( first_block_num <= lib_num && lib_num <= blog.head()->block_num(),
|
||||
block_log_exception,
|
||||
"block log (ranging from ${block_log_first_num} to ${block_log_last_num}) does not contain the last irreversible block (${fork_db_lib})",
|
||||
("block_log_first_num", first_block_num)
|
||||
("block_log_last_num", blog_head->block_num())
|
||||
("block_log_last_num", blog.head()->block_num())
|
||||
("fork_db_lib", lib_num)
|
||||
);
|
||||
lib_num = blog_head->block_num();
|
||||
lib_num = blog.head()->block_num();
|
||||
} else {
|
||||
if( first_block_num != (lib_num + 1) ) {
|
||||
blog.reset( chain_id, lib_num + 1 );
|
||||
@@ -663,6 +653,10 @@ struct controller_impl {
|
||||
head = fork_db.head();
|
||||
|
||||
init(check_shutdown);
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -713,8 +707,7 @@ struct controller_impl {
|
||||
|
||||
protocol_features.init( db );
|
||||
|
||||
// At startup, no transaction specific logging is possible
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_startup(db, head->block_num);
|
||||
}
|
||||
|
||||
@@ -1030,23 +1023,22 @@ struct controller_impl {
|
||||
});
|
||||
|
||||
const auto& owner_permission = authorization.create_permission(name, config::owner_name, 0,
|
||||
owner, false, initial_timestamp );
|
||||
owner, initial_timestamp );
|
||||
const auto& active_permission = authorization.create_permission(name, config::active_name, owner_permission.id,
|
||||
active, false, initial_timestamp );
|
||||
active, initial_timestamp );
|
||||
|
||||
resource_limits.initialize_account(name, false);
|
||||
resource_limits.initialize_account(name);
|
||||
|
||||
int64_t ram_delta = config::overhead_per_account_ram_bytes;
|
||||
ram_delta += 2*config::billable_size_v<permission_object>;
|
||||
ram_delta += owner_permission.auth.get_billable_size();
|
||||
ram_delta += active_permission.auth.get_billable_size();
|
||||
|
||||
// This is only called at startup, no transaction specific logging is possible
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${name}", ("name", name)), "account", "add", "newaccount");
|
||||
}
|
||||
|
||||
resource_limits.add_pending_ram_usage(name, ram_delta, false); // false for doing dm logging
|
||||
resource_limits.add_pending_ram_usage(name, ram_delta);
|
||||
resource_limits.verify_account_ram_usage(name);
|
||||
}
|
||||
|
||||
@@ -1099,24 +1091,17 @@ struct controller_impl {
|
||||
config::majority_producers_permission_name,
|
||||
active_permission.id,
|
||||
active_producers_authority,
|
||||
false,
|
||||
genesis.initial_timestamp );
|
||||
authorization.create_permission( config::producers_account_name,
|
||||
config::minority_producers_permission_name,
|
||||
majority_permission.id,
|
||||
active_producers_authority,
|
||||
false,
|
||||
genesis.initial_timestamp );
|
||||
|
||||
}
|
||||
|
||||
// The returned scoped_exit should not exceed the lifetime of the pending which existed when make_block_restore_point was called.
|
||||
fc::scoped_exit<std::function<void()>> make_block_restore_point( bool is_read_only = false ) {
|
||||
if ( is_read_only ) {
|
||||
std::function<void()> callback = []() { };
|
||||
return fc::make_scoped_exit( std::move(callback) );
|
||||
}
|
||||
|
||||
fc::scoped_exit<std::function<void()>> make_block_restore_point() {
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
auto orig_trx_receipts_size = bb._pending_trx_receipts.size();
|
||||
auto orig_trx_metas_size = bb._pending_trx_metas.size();
|
||||
@@ -1163,14 +1148,14 @@ struct controller_impl {
|
||||
etrx.set_reference_block( self.head_block_id() );
|
||||
}
|
||||
|
||||
transaction_checktime_timer trx_timer(timer);
|
||||
const packed_transaction trx( std::move( etrx ) );
|
||||
transaction_context trx_context( self, trx, std::move(trx_timer), start );
|
||||
|
||||
if (auto dm_logger = get_deep_mind_logger(trx_context.is_transient())) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_onerror(etrx);
|
||||
}
|
||||
|
||||
transaction_checktime_timer trx_timer(timer);
|
||||
const packed_transaction trx( std::move( etrx ) );
|
||||
transaction_context trx_context( self, trx, trx.id(), std::move(trx_timer), start );
|
||||
|
||||
trx_context.block_deadline = block_deadline;
|
||||
trx_context.max_transaction_time_subjective = max_transaction_time;
|
||||
trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time;
|
||||
@@ -1219,13 +1204,12 @@ struct controller_impl {
|
||||
}
|
||||
|
||||
int64_t remove_scheduled_transaction( const generated_transaction_object& gto ) {
|
||||
// deferred transactions cannot be transient.
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", gto.id)), "deferred_trx", "remove", "deferred_trx_removed");
|
||||
}
|
||||
|
||||
int64_t ram_delta = -(config::billable_size_v<generated_transaction_object> + gto.packed_trx.size());
|
||||
resource_limits.add_pending_ram_usage( gto.payer, ram_delta, false ); // false for doing dm logging
|
||||
resource_limits.add_pending_ram_usage( gto.payer, ram_delta );
|
||||
// No need to verify_account_ram_usage since we are only reducing memory
|
||||
|
||||
db.remove( gto );
|
||||
@@ -1273,7 +1257,7 @@ struct controller_impl {
|
||||
{ try {
|
||||
|
||||
auto start = fc::time_point::now();
|
||||
const bool validating = !self.is_speculative_block();
|
||||
const bool validating = !self.is_producing_block();
|
||||
EOS_ASSERT( !validating || explicit_billed_cpu_time, transaction_exception, "validating requires explicit billing" );
|
||||
|
||||
maybe_session undo_session;
|
||||
@@ -1330,8 +1314,8 @@ struct controller_impl {
|
||||
|
||||
uint32_t cpu_time_to_bill_us = billed_cpu_time_us;
|
||||
|
||||
transaction_checktime_timer trx_timer( timer );
|
||||
transaction_context trx_context( self, *trx->packed_trx(), std::move(trx_timer) );
|
||||
transaction_checktime_timer trx_timer(timer);
|
||||
transaction_context trx_context( self, *trx->packed_trx(), gtrx.trx_id, std::move(trx_timer) );
|
||||
trx_context.leeway = fc::microseconds(0); // avoid stealing cpu resource
|
||||
trx_context.block_deadline = block_deadline;
|
||||
trx_context.max_transaction_time_subjective = max_transaction_time;
|
||||
@@ -1348,8 +1332,7 @@ struct controller_impl {
|
||||
trace->except_ptr = std::current_exception();
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
|
||||
// deferred transactions cannot be transient
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_fail_deferred();
|
||||
}
|
||||
};
|
||||
@@ -1357,7 +1340,7 @@ struct controller_impl {
|
||||
try {
|
||||
trx_context.init_for_deferred_trx( gtrx.published );
|
||||
|
||||
if( trx_context.enforce_whiteblacklist && self.is_speculative_block() ) {
|
||||
if( trx_context.enforce_whiteblacklist && pending->_block_status == controller::block_status::incomplete ) {
|
||||
flat_set<account_name> actors;
|
||||
for( const auto& act : trx->packed_trx()->get_transaction().actions ) {
|
||||
for( const auto& auth : act.authorization ) {
|
||||
@@ -1530,7 +1513,7 @@ struct controller_impl {
|
||||
transaction_trace_ptr trace;
|
||||
try {
|
||||
auto start = fc::time_point::now();
|
||||
const bool check_auth = !self.skip_auth_check() && !trx->implicit() && !trx->is_read_only();
|
||||
const bool check_auth = !self.skip_auth_check() && !trx->implicit;
|
||||
const fc::microseconds sig_cpu_usage = trx->signature_cpu_usage();
|
||||
|
||||
if( !explicit_billed_cpu_time ) {
|
||||
@@ -1545,8 +1528,8 @@ struct controller_impl {
|
||||
|
||||
const signed_transaction& trn = trx->packed_trx()->get_signed_transaction();
|
||||
transaction_checktime_timer trx_timer(timer);
|
||||
transaction_context trx_context(self, *trx->packed_trx(), std::move(trx_timer), start, trx->get_trx_type());
|
||||
if ((bool)subjective_cpu_leeway && self.is_speculative_block()) {
|
||||
transaction_context trx_context(self, *trx->packed_trx(), trx->id(), std::move(trx_timer), start, trx->read_only);
|
||||
if ((bool)subjective_cpu_leeway && pending->_block_status == controller::block_status::incomplete) {
|
||||
trx_context.leeway = *subjective_cpu_leeway;
|
||||
}
|
||||
trx_context.block_deadline = block_deadline;
|
||||
@@ -1565,7 +1548,7 @@ struct controller_impl {
|
||||
};
|
||||
|
||||
try {
|
||||
if( trx->implicit() ) {
|
||||
if( trx->implicit ) {
|
||||
trx_context.init_for_implicit_trx();
|
||||
trx_context.enforce_whiteblacklist = false;
|
||||
} else {
|
||||
@@ -1583,20 +1566,20 @@ struct controller_impl {
|
||||
trx_context.delay,
|
||||
[&trx_context](){ trx_context.checktime(); },
|
||||
false,
|
||||
trx->is_dry_run()
|
||||
trx->read_only
|
||||
);
|
||||
}
|
||||
trx_context.exec();
|
||||
trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
|
||||
|
||||
auto restore = make_block_restore_point( trx->is_read_only() );
|
||||
auto restore = make_block_restore_point();
|
||||
|
||||
trx->billed_cpu_time_us = trx_context.billed_cpu_time_us;
|
||||
if (!trx->implicit() && !trx->is_read_only()) {
|
||||
if (!trx->implicit) {
|
||||
transaction_receipt::status_enum s = (trx_context.delay == fc::seconds(0))
|
||||
? transaction_receipt::executed
|
||||
: transaction_receipt::delayed;
|
||||
trace->receipt = push_receipt(*trx->packed_trx(), s, trx_context.billed_cpu_time_us, trace->net_usage);
|
||||
trx->billed_cpu_time_us = trx_context.billed_cpu_time_us;
|
||||
std::get<building_block>(pending->_block_stage)._pending_trx_metas.emplace_back(trx);
|
||||
} else {
|
||||
transaction_receipt_header r;
|
||||
@@ -1606,37 +1589,30 @@ struct controller_impl {
|
||||
trace->receipt = r;
|
||||
}
|
||||
|
||||
if ( !trx->is_read_only() ) {
|
||||
fc::move_append( std::get<building_block>(pending->_block_stage)._action_receipt_digests,
|
||||
std::move(trx_context.executed_action_receipt_digests) );
|
||||
if ( !trx->is_dry_run() ) {
|
||||
// call the accept signal but only once for this transaction
|
||||
if (!trx->accepted) {
|
||||
trx->accepted = true;
|
||||
emit(self.accepted_transaction, trx);
|
||||
}
|
||||
fc::move_append( std::get<building_block>(pending->_block_stage)._action_receipt_digests,
|
||||
std::move(trx_context.executed_action_receipt_digests) );
|
||||
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
// call the accept signal but only once for this transaction
|
||||
if (!trx->read_only) {
|
||||
if (!trx->accepted) {
|
||||
trx->accepted = true;
|
||||
emit(self.accepted_transaction, trx);
|
||||
}
|
||||
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
}
|
||||
|
||||
if ( trx->is_transient() ) {
|
||||
// remove trx from pending block by not canceling 'restore'
|
||||
trx_context.undo(); // this will happen automatically in destructor, but make it more explicit
|
||||
} else if ( pending->_block_status == controller::block_status::ephemeral ) {
|
||||
// An ephemeral block will never become a full block, but on a producer node the trxs should be saved
|
||||
// in the un-applied transaction queue for execution during block production. For a non-producer node
|
||||
// save the trxs in the un-applied transaction queue for use during block validation to skip signature
|
||||
// recovery.
|
||||
restore.cancel(); // maintain trx metas for abort block
|
||||
trx_context.undo(); // this will happen automatically in destructor, but make it more explicit
|
||||
|
||||
if ( (read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete) || trx->read_only ) {
|
||||
//this may happen automatically in destructor, but I prefer make it more explicit
|
||||
trx_context.undo();
|
||||
} else {
|
||||
restore.cancel();
|
||||
trx_context.squash();
|
||||
}
|
||||
|
||||
if( !trx->is_transient() ) {
|
||||
if( !trx->read_only ) {
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
@@ -1659,7 +1635,7 @@ struct controller_impl {
|
||||
handle_exception(wrapper);
|
||||
}
|
||||
|
||||
if (!trx->is_transient()) {
|
||||
if (!trx->read_only) {
|
||||
emit(self.accepted_transaction, trx);
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
@@ -1685,8 +1661,7 @@ struct controller_impl {
|
||||
|
||||
emit( self.block_start, head->block_num + 1 );
|
||||
|
||||
// at block level, no transaction specific logging is possible
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
// The head block represents the block just before this one that is about to start, so add 1 to get this block num
|
||||
dm_logger->on_start_block(head->block_num + 1);
|
||||
}
|
||||
@@ -1711,9 +1686,8 @@ struct controller_impl {
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
const auto& pbhs = bb._pending_block_header_state;
|
||||
|
||||
// block status is either ephemeral or incomplete. Modify state of speculative block only if we are building a
|
||||
// speculative incomplete block (otherwise we need clean state for head mode, ephemeral block)
|
||||
if ( pending->_block_status != controller::block_status::ephemeral )
|
||||
// modify state of speculative block only if we are in speculative read mode (otherwise we need clean state for head or read-only modes)
|
||||
if ( read_mode == db_read_mode::SPECULATIVE || pending->_block_status != controller::block_status::incomplete )
|
||||
{
|
||||
const auto& pso = db.get<protocol_state_object>();
|
||||
|
||||
@@ -1854,17 +1828,17 @@ struct controller_impl {
|
||||
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
|
||||
auto action_merkle_fut = post_async_task( thread_pool.get_executor(),
|
||||
[ids{std::move( bb._action_receipt_digests )}]() mutable {
|
||||
return merkle( std::move( ids ) );
|
||||
} );
|
||||
auto action_merkle_fut = async_thread_pool( thread_pool.get_executor(),
|
||||
[ids{std::move( bb._action_receipt_digests )}]() mutable {
|
||||
return merkle( std::move( ids ) );
|
||||
} );
|
||||
const bool calc_trx_merkle = !std::holds_alternative<checksum256_type>(bb._trx_mroot_or_receipt_digests);
|
||||
std::future<checksum256_type> trx_merkle_fut;
|
||||
if( calc_trx_merkle ) {
|
||||
trx_merkle_fut = post_async_task( thread_pool.get_executor(),
|
||||
[ids{std::move( std::get<digests_t>(bb._trx_mroot_or_receipt_digests) )}]() mutable {
|
||||
return merkle( std::move( ids ) );
|
||||
} );
|
||||
trx_merkle_fut = async_thread_pool( thread_pool.get_executor(),
|
||||
[ids{std::move( std::get<digests_t>(bb._trx_mroot_or_receipt_digests) )}]() mutable {
|
||||
return merkle( std::move( ids ) );
|
||||
} );
|
||||
}
|
||||
|
||||
// Update resource limits:
|
||||
@@ -1938,8 +1912,7 @@ struct controller_impl {
|
||||
EOS_ASSERT( bsp == head, fork_database_exception, "committed block did not become the new head in fork database");
|
||||
}
|
||||
|
||||
// at block level, no transaction specific logging is possible
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_accepted_block(bsp);
|
||||
}
|
||||
|
||||
@@ -2190,7 +2163,7 @@ struct controller_impl {
|
||||
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b ) {
|
||||
EOS_ASSERT( b, block_validate_exception, "null block" );
|
||||
|
||||
return post_async_task( thread_pool.get_executor(), [b, id, control=this]() {
|
||||
return async_thread_pool( thread_pool.get_executor(), [b, id, control=this]() {
|
||||
// no reason for a block_state if fork_db already knows about block
|
||||
auto existing = control->fork_db.get_block( id );
|
||||
EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) );
|
||||
@@ -2334,8 +2307,7 @@ struct controller_impl {
|
||||
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) );
|
||||
|
||||
// not possible to log transaction specific infor when switching forks
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_switch_forks(head->id, new_head->id);
|
||||
}
|
||||
|
||||
@@ -2654,65 +2626,23 @@ struct controller_impl {
|
||||
trx.set_reference_block( self.head_block_id() );
|
||||
}
|
||||
|
||||
// onblock transaction cannot be transient
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_onblock(trx);
|
||||
}
|
||||
|
||||
return trx;
|
||||
}
|
||||
|
||||
inline deep_mind_handler* get_deep_mind_logger(bool is_trx_transient) const {
|
||||
// do not perform deep mind logging for read-only and dry-run transactions
|
||||
return is_trx_transient ? nullptr : deep_mind_logger;
|
||||
inline deep_mind_handler* get_deep_mind_logger() const {
|
||||
return deep_mind_logger;
|
||||
}
|
||||
|
||||
uint32_t earliest_available_block_num() const {
|
||||
return (blog.first_block_num() != 0) ? blog.first_block_num() : fork_db.root()->block_num;
|
||||
}
|
||||
|
||||
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|
||||
bool is_eos_vm_oc_enabled() const {
|
||||
return ( conf.eosvmoc_tierup || conf.wasm_runtime == wasm_interface::vm_type::eos_vm_oc );
|
||||
}
|
||||
#endif
|
||||
|
||||
// only called from non-main threads (read-only trx execution threads)
|
||||
// when producer_plugin starts them
|
||||
void init_thread_local_data() {
|
||||
EOS_ASSERT( !is_main_thread(), misc_exception, "init_thread_local_data called on the main thread");
|
||||
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|
||||
if ( is_eos_vm_oc_enabled() )
|
||||
// EOSVMOC needs further initialization of its thread local data
|
||||
wasmif.init_thread_local_data();
|
||||
else
|
||||
#endif
|
||||
// Non-EOSVMOC needs a wasmif per thread
|
||||
wasmif_thread_local = std::make_unique<wasm_interface>( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty());
|
||||
}
|
||||
|
||||
bool is_main_thread() { return main_thread_id == std::this_thread::get_id(); };
|
||||
|
||||
wasm_interface& get_wasm_interface() {
|
||||
if ( is_main_thread()
|
||||
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|
||||
|| is_eos_vm_oc_enabled()
|
||||
#endif
|
||||
)
|
||||
return wasmif;
|
||||
else
|
||||
return *wasmif_thread_local;
|
||||
}
|
||||
|
||||
block_state_ptr fork_db_head() const;
|
||||
}; /// controller_impl
|
||||
|
||||
thread_local platform_timer controller_impl::timer;
|
||||
#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
|
||||
thread_local eosio::vm::wasm_allocator controller_impl::wasm_alloc;
|
||||
#endif
|
||||
thread_local std::unique_ptr<wasm_interface> controller_impl::wasmif_thread_local;
|
||||
|
||||
const resource_limits_manager& controller::get_resource_limits_manager()const
|
||||
{
|
||||
return my->resource_limits;
|
||||
@@ -2783,14 +2713,14 @@ chainbase::database& controller::mutable_db()const { return my->db; }
|
||||
|
||||
const fork_database& controller::fork_db()const { return my->fork_db; }
|
||||
|
||||
void controller::preactivate_feature( const digest_type& feature_digest, bool is_trx_transient ) {
|
||||
void controller::preactivate_feature( const digest_type& feature_digest ) {
|
||||
const auto& pfs = my->protocol_features.get_protocol_feature_set();
|
||||
auto cur_time = pending_block_time();
|
||||
|
||||
auto status = pfs.is_recognized( feature_digest, cur_time );
|
||||
switch( status ) {
|
||||
case protocol_feature_set::recognized_t::unrecognized:
|
||||
if( is_speculative_block() ) {
|
||||
if( is_producing_block() ) {
|
||||
EOS_THROW( subjective_block_production_exception,
|
||||
"protocol feature with digest '${digest}' is unrecognized", ("digest", feature_digest) );
|
||||
} else {
|
||||
@@ -2799,7 +2729,7 @@ void controller::preactivate_feature( const digest_type& feature_digest, bool is
|
||||
}
|
||||
break;
|
||||
case protocol_feature_set::recognized_t::disabled:
|
||||
if( is_speculative_block() ) {
|
||||
if( is_producing_block() ) {
|
||||
EOS_THROW( subjective_block_production_exception,
|
||||
"protocol feature with digest '${digest}' is disabled", ("digest", feature_digest) );
|
||||
} else {
|
||||
@@ -2808,7 +2738,7 @@ void controller::preactivate_feature( const digest_type& feature_digest, bool is
|
||||
}
|
||||
break;
|
||||
case protocol_feature_set::recognized_t::too_early:
|
||||
if( is_speculative_block() ) {
|
||||
if( is_producing_block() ) {
|
||||
EOS_THROW( subjective_block_production_exception,
|
||||
"${timestamp} is too early for the earliest allowed activation time of the protocol feature with digest '${digest}'", ("digest", feature_digest)("timestamp", cur_time) );
|
||||
} else {
|
||||
@@ -2819,7 +2749,7 @@ void controller::preactivate_feature( const digest_type& feature_digest, bool is
|
||||
case protocol_feature_set::recognized_t::ready:
|
||||
break;
|
||||
default:
|
||||
if( is_speculative_block() ) {
|
||||
if( is_producing_block() ) {
|
||||
EOS_THROW( subjective_block_production_exception, "unexpected recognized_t status" );
|
||||
} else {
|
||||
EOS_THROW( protocol_feature_bad_block_exception, "unexpected recognized_t status" );
|
||||
@@ -2880,7 +2810,7 @@ void controller::preactivate_feature( const digest_type& feature_digest, bool is
|
||||
("digest", feature_digest)
|
||||
);
|
||||
|
||||
if (auto dm_logger = get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
const auto feature = pfs.get_protocol_feature(feature_digest);
|
||||
|
||||
dm_logger->on_preactivate_feature(feature);
|
||||
@@ -2911,10 +2841,32 @@ void controller::validate_protocol_features( const vector<digest_type>& features
|
||||
features_to_activate );
|
||||
}
|
||||
|
||||
void controller::start_block( block_timestamp_type when, uint16_t confirm_block_count )
|
||||
{
|
||||
validate_db_available_size();
|
||||
|
||||
EOS_ASSERT( !my->pending, block_validate_exception, "pending block already exists" );
|
||||
|
||||
vector<digest_type> new_protocol_feature_activations;
|
||||
|
||||
const auto& pso = my->db.get<protocol_state_object>();
|
||||
if( pso.preactivated_protocol_features.size() > 0 ) {
|
||||
for( const auto& f : pso.preactivated_protocol_features ) {
|
||||
new_protocol_feature_activations.emplace_back( f );
|
||||
}
|
||||
}
|
||||
|
||||
if( new_protocol_feature_activations.size() > 0 ) {
|
||||
validate_protocol_features( new_protocol_feature_activations );
|
||||
}
|
||||
|
||||
my->start_block( when, confirm_block_count, new_protocol_feature_activations,
|
||||
block_status::incomplete, std::optional<block_id_type>(), fc::time_point::maximum() );
|
||||
}
|
||||
|
||||
void controller::start_block( block_timestamp_type when,
|
||||
uint16_t confirm_block_count,
|
||||
const vector<digest_type>& new_protocol_feature_activations,
|
||||
block_status bs,
|
||||
const fc::time_point& deadline )
|
||||
{
|
||||
validate_db_available_size();
|
||||
@@ -2923,10 +2875,8 @@ void controller::start_block( block_timestamp_type when,
|
||||
validate_protocol_features( new_protocol_feature_activations );
|
||||
}
|
||||
|
||||
EOS_ASSERT( bs == block_status::incomplete || bs == block_status::ephemeral, block_validate_exception, "speculative block type required" );
|
||||
|
||||
my->start_block( when, confirm_block_count, new_protocol_feature_activations,
|
||||
bs, std::optional<block_id_type>(), deadline );
|
||||
block_status::incomplete, std::optional<block_id_type>(), deadline );
|
||||
}
|
||||
|
||||
block_state_ptr controller::finalize_block( block_report& br, const signer_callback_type& signer_callback ) {
|
||||
@@ -2991,7 +2941,7 @@ transaction_trace_ptr controller::push_transaction( const transaction_metadata_p
|
||||
int64_t subjective_cpu_bill_us ) {
|
||||
validate_db_available_size();
|
||||
EOS_ASSERT( get_read_mode() != db_read_mode::IRREVERSIBLE, transaction_type_exception, "push transaction not allowed in irreversible mode" );
|
||||
EOS_ASSERT( trx && !trx->implicit() && !trx->scheduled(), transaction_type_exception, "Implicit/Scheduled transaction not allowed" );
|
||||
EOS_ASSERT( trx && !trx->implicit && !trx->scheduled, transaction_type_exception, "Implicit/Scheduled transaction not allowed" );
|
||||
return my->push_transaction(trx, block_deadline, max_transaction_time, billed_cpu_time_us, explicit_billed_cpu_time, subjective_cpu_bill_us );
|
||||
}
|
||||
|
||||
@@ -3065,23 +3015,36 @@ block_state_ptr controller::head_block_state()const {
|
||||
return my->head;
|
||||
}
|
||||
|
||||
block_state_ptr controller_impl::fork_db_head() const {
|
||||
if( read_mode == db_read_mode::IRREVERSIBLE ) {
|
||||
// When in IRREVERSIBLE mode fork_db blocks are marked valid when they become irreversible so that
|
||||
// fork_db.head() returns irreversible block
|
||||
// Use pending_head since this method should return the chain head and not last irreversible.
|
||||
return fork_db.pending_head();
|
||||
} else {
|
||||
return fork_db.head();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t controller::fork_db_head_block_num()const {
|
||||
return my->fork_db_head()->block_num;
|
||||
return my->fork_db.head()->block_num;
|
||||
}
|
||||
|
||||
block_id_type controller::fork_db_head_block_id()const {
|
||||
return my->fork_db_head()->id;
|
||||
return my->fork_db.head()->id;
|
||||
}
|
||||
|
||||
time_point controller::fork_db_head_block_time()const {
|
||||
return my->fork_db.head()->header.timestamp;
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -3145,7 +3108,7 @@ const global_property_object& controller::get_global_properties()const {
|
||||
return my->db.get<global_property_object>();
|
||||
}
|
||||
|
||||
signed_block_ptr controller::fetch_block_by_id( const block_id_type& id )const {
|
||||
signed_block_ptr controller::fetch_block_by_id( block_id_type id )const {
|
||||
auto state = my->fork_db.get_block(id);
|
||||
if( state && state->block ) return state->block;
|
||||
auto bptr = my->blog.read_block_by_num( block_header::num_from_id(id) );
|
||||
@@ -3153,14 +3116,6 @@ signed_block_ptr controller::fetch_block_by_id( const block_id_type& id )const {
|
||||
return signed_block_ptr();
|
||||
}
|
||||
|
||||
std::optional<signed_block_header> controller::fetch_block_header_by_id( const block_id_type& id )const {
|
||||
auto state = my->fork_db.get_block(id);
|
||||
if( state && state->block ) return state->header;
|
||||
auto result = my->blog.read_block_header_by_num( block_header::num_from_id(id) );
|
||||
if( result && result->calculate_id() == id ) return result;
|
||||
return {};
|
||||
}
|
||||
|
||||
signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const { try {
|
||||
auto blk_state = fetch_block_state_by_number( block_num );
|
||||
if( blk_state ) {
|
||||
@@ -3170,25 +3125,25 @@ signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const {
|
||||
return my->blog.read_block_by_num(block_num);
|
||||
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
|
||||
|
||||
std::optional<signed_block_header> controller::fetch_block_header_by_number( uint32_t block_num )const { try {
|
||||
auto blk_state = fetch_block_state_by_number( block_num );
|
||||
if( blk_state ) {
|
||||
return blk_state->header;
|
||||
}
|
||||
|
||||
return my->blog.read_block_header_by_num(block_num);
|
||||
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
|
||||
|
||||
block_state_ptr controller::fetch_block_state_by_id( block_id_type id )const {
|
||||
auto state = my->fork_db.get_block(id);
|
||||
return state;
|
||||
}
|
||||
|
||||
block_state_ptr controller::fetch_block_state_by_number( uint32_t block_num )const { try {
|
||||
return my->fork_db.search_on_branch( fork_db_head_block_id(), block_num );
|
||||
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 my->fork_db.search_on_branch( my->fork_db.head()->id, block_num );
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
|
||||
|
||||
block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try {
|
||||
const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)block_num);
|
||||
|
||||
if( block_header::num_from_id(tapos_block_summary.block_id) == block_num )
|
||||
return tapos_block_summary.block_id;
|
||||
|
||||
const auto& blog_head = my->blog.head();
|
||||
|
||||
bool find_in_blog = (blog_head && block_num <= blog_head->block_num());
|
||||
@@ -3387,7 +3342,7 @@ const apply_handler* controller::find_apply_handler( account_name receiver, acco
|
||||
return nullptr;
|
||||
}
|
||||
wasm_interface& controller::get_wasm_interface() {
|
||||
return my->get_wasm_interface();
|
||||
return my->wasmif;
|
||||
}
|
||||
|
||||
const account_object& controller::get_account( account_name name )const
|
||||
@@ -3419,14 +3374,14 @@ bool controller::is_building_block()const {
|
||||
return my->pending.has_value();
|
||||
}
|
||||
|
||||
bool controller::is_speculative_block()const {
|
||||
bool controller::is_producing_block()const {
|
||||
if( !my->pending ) return false;
|
||||
|
||||
return (my->pending->_block_status == block_status::incomplete || my->pending->_block_status == block_status::ephemeral );
|
||||
return (my->pending->_block_status == block_status::incomplete);
|
||||
}
|
||||
|
||||
bool controller::is_ram_billing_in_notify_allowed()const {
|
||||
return my->conf.disable_all_subjective_mitigations || !is_speculative_block() || my->conf.allow_ram_billing_in_notify;
|
||||
return my->conf.disable_all_subjective_mitigations || !is_producing_block() || my->conf.allow_ram_billing_in_notify;
|
||||
}
|
||||
|
||||
uint32_t controller::configured_subjective_signature_length_limit()const {
|
||||
@@ -3538,9 +3493,7 @@ void controller::add_to_ram_correction( account_name account, uint64_t ram_bytes
|
||||
} );
|
||||
}
|
||||
|
||||
// on_add_ram_correction is only called for deferred transaction
|
||||
// (in apply_context::schedule_deferred_transaction)
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_add_ram_correction(*ptr, ram_bytes);
|
||||
}
|
||||
}
|
||||
@@ -3549,8 +3502,8 @@ bool controller::all_subjective_mitigations_disabled()const {
|
||||
return my->conf.disable_all_subjective_mitigations;
|
||||
}
|
||||
|
||||
deep_mind_handler* controller::get_deep_mind_logger(bool is_trx_transient)const {
|
||||
return my->get_deep_mind_logger(is_trx_transient);
|
||||
deep_mind_handler* controller::get_deep_mind_logger()const {
|
||||
return my->get_deep_mind_logger();
|
||||
}
|
||||
|
||||
void controller::enable_deep_mind(deep_mind_handler* logger) {
|
||||
@@ -3567,12 +3520,6 @@ vm::wasm_allocator& controller::get_wasm_allocator() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|
||||
bool controller::is_eos_vm_oc_enabled() const {
|
||||
return my->is_eos_vm_oc_enabled();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::optional<uint64_t> controller::convert_exception_to_error_code( const fc::exception& e ) {
|
||||
const chain_exception* e_ptr = dynamic_cast<const chain_exception*>( &e );
|
||||
|
||||
@@ -3670,22 +3617,10 @@ void controller::replace_account_keys( name account, name permission, const publ
|
||||
p.auth = authority(key);
|
||||
});
|
||||
int64_t new_size = (int64_t)(chain::config::billable_size_v<permission_object> + perm->auth.get_billable_size());
|
||||
rlm.add_pending_ram_usage(account, new_size - old_size, false); // false for doing dm logging
|
||||
rlm.add_pending_ram_usage(account, new_size - old_size);
|
||||
rlm.verify_account_ram_usage(account);
|
||||
}
|
||||
|
||||
void controller::set_db_read_only_mode() {
|
||||
mutable_db().set_read_only_mode();
|
||||
}
|
||||
|
||||
void controller::unset_db_read_only_mode() {
|
||||
mutable_db().unset_read_only_mode();
|
||||
}
|
||||
|
||||
void controller::init_thread_local_data() {
|
||||
my->init_thread_local_data();
|
||||
}
|
||||
|
||||
/// Protocol feature activation handlers:
|
||||
|
||||
template<>
|
||||
@@ -3715,12 +3650,11 @@ void controller_impl::on_activation<builtin_protocol_feature_t::replace_deferred
|
||||
("name", itr->name)("adjust", itr->ram_correction)("current", current_ram_usage) );
|
||||
}
|
||||
|
||||
// This method is only called for deferred transaction
|
||||
if (auto dm_logger = get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", itr->id._id)), "deferred_trx", "correction", "deferred_trx_ram_correction");
|
||||
}
|
||||
|
||||
resource_limits.add_pending_ram_usage( itr->name, ram_delta, false ); // false for doing dm logging
|
||||
resource_limits.add_pending_ram_usage( itr->name, ram_delta );
|
||||
db.remove( *itr );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ void validate_authority_precondition( const apply_context& context, const author
|
||||
}
|
||||
}
|
||||
|
||||
if( context.trx_context.enforce_whiteblacklist && context.control.is_speculative_block() ) {
|
||||
if( context.trx_context.enforce_whiteblacklist && context.control.is_producing_block() ) {
|
||||
for( const auto& p : auth.keys ) {
|
||||
context.control.check_key_list( p.key );
|
||||
}
|
||||
@@ -65,7 +65,6 @@ void validate_authority_precondition( const apply_context& context, const author
|
||||
* This method is called assuming precondition_system_newaccount succeeds a
|
||||
*/
|
||||
void apply_eosio_newaccount(apply_context& context) {
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), action_validate_exception, "newaccount not allowed in read-only transaction" );
|
||||
auto create = context.get_action().data_as<newaccount>();
|
||||
try {
|
||||
context.require_authorization(create.creator);
|
||||
@@ -108,18 +107,18 @@ void apply_eosio_newaccount(apply_context& context) {
|
||||
}
|
||||
|
||||
const auto& owner_permission = authorization.create_permission( create.name, config::owner_name, 0,
|
||||
std::move(create.owner), context.trx_context.is_transient() );
|
||||
std::move(create.owner) );
|
||||
const auto& active_permission = authorization.create_permission( create.name, config::active_name, owner_permission.id,
|
||||
std::move(create.active), context.trx_context.is_transient() );
|
||||
std::move(create.active) );
|
||||
|
||||
context.control.get_mutable_resource_limits_manager().initialize_account(create.name, context.trx_context.is_transient());
|
||||
context.control.get_mutable_resource_limits_manager().initialize_account(create.name);
|
||||
|
||||
int64_t ram_delta = config::overhead_per_account_ram_bytes;
|
||||
ram_delta += 2*config::billable_size_v<permission_object>;
|
||||
ram_delta += owner_permission.auth.get_billable_size();
|
||||
ram_delta += active_permission.auth.get_billable_size();
|
||||
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${name}", ("name", create.name)), "account", "add", "newaccount");
|
||||
}
|
||||
|
||||
@@ -128,7 +127,6 @@ void apply_eosio_newaccount(apply_context& context) {
|
||||
} FC_CAPTURE_AND_RETHROW( (create) ) }
|
||||
|
||||
void apply_eosio_setcode(apply_context& context) {
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), action_validate_exception, "setcode not allowed in read-only transaction" );
|
||||
auto& db = context.db;
|
||||
auto act = context.get_action().data_as<setcode>();
|
||||
context.require_authorization(act.account);
|
||||
@@ -196,7 +194,7 @@ void apply_eosio_setcode(apply_context& context) {
|
||||
});
|
||||
|
||||
if (new_size != old_size) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
const char* operation = "update";
|
||||
if (old_size <= 0) {
|
||||
operation = "add";
|
||||
@@ -212,7 +210,6 @@ void apply_eosio_setcode(apply_context& context) {
|
||||
}
|
||||
|
||||
void apply_eosio_setabi(apply_context& context) {
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), action_validate_exception, "setabi ot allowed in read-only transaction" );
|
||||
auto& db = context.db;
|
||||
auto act = context.get_action().data_as<setabi>();
|
||||
|
||||
@@ -235,7 +232,7 @@ void apply_eosio_setabi(apply_context& context) {
|
||||
});
|
||||
|
||||
if (new_size != old_size) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
const char* operation = "update";
|
||||
if (old_size <= 0) {
|
||||
operation = "add";
|
||||
@@ -251,7 +248,6 @@ void apply_eosio_setabi(apply_context& context) {
|
||||
}
|
||||
|
||||
void apply_eosio_updateauth(apply_context& context) {
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), action_validate_exception, "updateauth not allowed in read-only transaction" );
|
||||
|
||||
auto update = context.get_action().data_as<updateauth>();
|
||||
context.require_authorization(update.account); // only here to mark the single authority on this action as used
|
||||
@@ -301,21 +297,21 @@ void apply_eosio_updateauth(apply_context& context) {
|
||||
|
||||
int64_t old_size = (int64_t)(config::billable_size_v<permission_object> + permission->auth.get_billable_size());
|
||||
|
||||
authorization.modify_permission( *permission, update.auth, context.trx_context.is_transient() );
|
||||
authorization.modify_permission( *permission, update.auth );
|
||||
|
||||
int64_t new_size = (int64_t)(config::billable_size_v<permission_object> + permission->auth.get_billable_size());
|
||||
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", permission->id)), "auth", "update", "updateauth_update");
|
||||
}
|
||||
|
||||
context.add_ram_usage( permission->owner, new_size - old_size );
|
||||
} else {
|
||||
const auto& p = authorization.create_permission( update.account, update.permission, parent_id, update.auth, context.trx_context.is_transient() );
|
||||
const auto& p = authorization.create_permission( update.account, update.permission, parent_id, update.auth );
|
||||
|
||||
int64_t new_size = (int64_t)(config::billable_size_v<permission_object> + p.auth.get_billable_size());
|
||||
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", p.id)), "auth", "add", "updateauth_create");
|
||||
}
|
||||
|
||||
@@ -326,8 +322,6 @@ void apply_eosio_updateauth(apply_context& context) {
|
||||
void apply_eosio_deleteauth(apply_context& context) {
|
||||
// context.require_write_lock( config::eosio_auth_scope );
|
||||
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), action_validate_exception, "deleteauth not allowed in read-only transaction" );
|
||||
|
||||
auto remove = context.get_action().data_as<deleteauth>();
|
||||
context.require_authorization(remove.account); // only here to mark the single authority on this action as used
|
||||
|
||||
@@ -350,11 +344,11 @@ void apply_eosio_deleteauth(apply_context& context) {
|
||||
const auto& permission = authorization.get_permission({remove.account, remove.permission});
|
||||
int64_t old_size = config::billable_size_v<permission_object> + permission.auth.get_billable_size();
|
||||
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", permission.id)), "auth", "remove", "deleteauth");
|
||||
}
|
||||
|
||||
authorization.remove_permission( permission, context.trx_context.is_transient() );
|
||||
authorization.remove_permission( permission );
|
||||
|
||||
context.add_ram_usage( remove.account, -old_size );
|
||||
|
||||
@@ -363,8 +357,6 @@ void apply_eosio_deleteauth(apply_context& context) {
|
||||
void apply_eosio_linkauth(apply_context& context) {
|
||||
// context.require_write_lock( config::eosio_auth_scope );
|
||||
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), action_validate_exception, "linkauth not allowed in read-only transaction" );
|
||||
|
||||
auto requirement = context.get_action().data_as<linkauth>();
|
||||
try {
|
||||
EOS_ASSERT(!requirement.requirement.empty(), action_validate_exception, "Required permission cannot be empty");
|
||||
@@ -409,7 +401,7 @@ void apply_eosio_linkauth(apply_context& context) {
|
||||
link.required_permission = requirement.requirement;
|
||||
});
|
||||
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", l.id)), "auth_link", "add", "linkauth");
|
||||
}
|
||||
|
||||
@@ -425,8 +417,6 @@ void apply_eosio_linkauth(apply_context& context) {
|
||||
void apply_eosio_unlinkauth(apply_context& context) {
|
||||
// context.require_write_lock( config::eosio_auth_scope );
|
||||
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), action_validate_exception, "unlinkauth not allowed in read-only transaction" );
|
||||
|
||||
auto& db = context.db;
|
||||
auto unlink = context.get_action().data_as<unlinkauth>();
|
||||
|
||||
@@ -436,7 +426,7 @@ void apply_eosio_unlinkauth(apply_context& context) {
|
||||
auto link = db.find<permission_link_object, by_action_name>(link_key);
|
||||
EOS_ASSERT(link != nullptr, action_validate_exception, "Attempting to unlink authority, but no link found");
|
||||
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", link->id)), "auth_link", "remove", "unlinkauth");
|
||||
}
|
||||
|
||||
@@ -449,7 +439,6 @@ void apply_eosio_unlinkauth(apply_context& context) {
|
||||
}
|
||||
|
||||
void apply_eosio_canceldelay(apply_context& context) {
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), action_validate_exception, "canceldelay not allowed in read-only transaction" );
|
||||
auto cancel = context.get_action().data_as<canceldelay>();
|
||||
context.require_authorization(cancel.canceling_auth.actor); // only here to mark the single authority on this action as used
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ struct abi_serializer {
|
||||
using yield_function_t = fc::optional_delegate<void(size_t)>;
|
||||
|
||||
abi_serializer(){ configure_built_in_types(); }
|
||||
abi_serializer( abi_def abi, const yield_function_t& yield );
|
||||
abi_serializer( const abi_def& abi, const yield_function_t& yield );
|
||||
[[deprecated("use the overload with yield_function_t[=create_yield_function(max_serialization_time)]")]]
|
||||
abi_serializer( const abi_def& abi, const fc::microseconds& max_serialization_time );
|
||||
void set_abi( abi_def abi, const yield_function_t& yield );
|
||||
void set_abi( const abi_def& abi, const yield_function_t& yield );
|
||||
[[deprecated("use the overload with yield_function_t[=create_yield_function(max_serialization_time)]")]]
|
||||
void set_abi(const abi_def& abi, const fc::microseconds& max_serialization_time);
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include <eosio/chain/controller.hpp>
|
||||
#include <eosio/chain/transaction.hpp>
|
||||
#include <eosio/chain/transaction_context.hpp>
|
||||
#include <eosio/chain/contract_table_objects.hpp>
|
||||
#include <eosio/chain/deep_mind.hpp>
|
||||
#include <fc/utility.hpp>
|
||||
@@ -14,6 +13,7 @@ namespace chainbase { class database; }
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
class controller;
|
||||
class transaction_context;
|
||||
|
||||
class apply_context {
|
||||
private:
|
||||
@@ -177,7 +177,6 @@ class apply_context {
|
||||
int store( uint64_t scope, uint64_t table, const account_name& payer,
|
||||
uint64_t id, secondary_key_proxy_const_type value )
|
||||
{
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), table_operation_not_permitted, "cannot store a db record when executing a readonly transaction" );
|
||||
EOS_ASSERT( payer != account_name(), invalid_table_payer, "must specify a valid account to pay for new record" );
|
||||
|
||||
// context.require_write_lock( scope );
|
||||
@@ -194,7 +193,7 @@ class apply_context {
|
||||
context.db.modify( tab, [&]( auto& t ) {
|
||||
++t.count;
|
||||
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
std::string event_id = RAM_EVENT_ID("${code}:${scope}:${table}:${index_name}",
|
||||
("code", t.code)
|
||||
("scope", t.scope)
|
||||
@@ -212,13 +211,12 @@ class apply_context {
|
||||
}
|
||||
|
||||
void remove( int iterator ) {
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), table_operation_not_permitted, "cannot remove a db record when executing a readonly transaction" );
|
||||
const auto& obj = itr_cache.get( iterator );
|
||||
|
||||
const auto& table_obj = itr_cache.get_table( obj.t_id );
|
||||
EOS_ASSERT( table_obj.code == context.receiver, table_access_violation, "db access violation" );
|
||||
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient())) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger()) {
|
||||
std::string event_id = RAM_EVENT_ID("${code}:${scope}:${table}:${index_name}",
|
||||
("code", table_obj.code)
|
||||
("scope", table_obj.scope)
|
||||
@@ -245,7 +243,6 @@ class apply_context {
|
||||
}
|
||||
|
||||
void update( int iterator, account_name payer, secondary_key_proxy_const_type secondary ) {
|
||||
EOS_ASSERT( !context.trx_context.is_read_only(), table_operation_not_permitted, "cannot update a db record when executing a readonly transaction" );
|
||||
const auto& obj = itr_cache.get( iterator );
|
||||
|
||||
const auto& table_obj = itr_cache.get_table( obj.t_id );
|
||||
@@ -258,7 +255,7 @@ class apply_context {
|
||||
int64_t billing_size = config::billable_size_v<ObjectType>;
|
||||
|
||||
std::string event_id;
|
||||
if (context.control.get_deep_mind_logger(context.trx_context.is_transient()) != nullptr) {
|
||||
if (context.control.get_deep_mind_logger() != nullptr) {
|
||||
event_id = RAM_EVENT_ID("${code}:${scope}:${table}:${index_name}",
|
||||
("code", table_obj.code)
|
||||
("scope", table_obj.scope)
|
||||
@@ -268,12 +265,12 @@ class apply_context {
|
||||
}
|
||||
|
||||
if( obj.payer != payer ) {
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient()))
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger())
|
||||
{
|
||||
dm_logger->on_ram_trace(std::string(event_id), "secondary_index", "remove", "secondary_index_remove");
|
||||
}
|
||||
context.update_db_usage( obj.payer, -(billing_size) );
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger(context.trx_context.is_transient()))
|
||||
if (auto dm_logger = context.control.get_deep_mind_logger())
|
||||
{
|
||||
dm_logger->on_ram_trace(std::move(event_id), "secondary_index", "add", "secondary_index_update_add_new_payer");
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace eosio { namespace chain {
|
||||
permission_name name,
|
||||
permission_id_type parent,
|
||||
const authority& auth,
|
||||
bool is_trx_transient,
|
||||
time_point initial_creation_time = time_point()
|
||||
);
|
||||
|
||||
@@ -39,13 +38,12 @@ namespace eosio { namespace chain {
|
||||
permission_name name,
|
||||
permission_id_type parent,
|
||||
authority&& auth,
|
||||
bool is_trx_transient,
|
||||
time_point initial_creation_time = time_point()
|
||||
);
|
||||
|
||||
void modify_permission( const permission_object& permission, const authority& auth, bool is_trx_transient );
|
||||
void modify_permission( const permission_object& permission, const authority& auth );
|
||||
|
||||
void remove_permission( const permission_object& permission, bool is_trx_transient );
|
||||
void remove_permission( const permission_object& permission );
|
||||
|
||||
void update_permission_usage( const permission_object& permission );
|
||||
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
#include <fc/filesystem.hpp>
|
||||
#include <eosio/chain/block.hpp>
|
||||
#include <eosio/chain/genesis_state.hpp>
|
||||
#include <eosio/chain/block_log_config.hpp>
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
namespace detail { struct block_log_impl; }
|
||||
namespace detail { class block_log_impl; }
|
||||
|
||||
/* The block log is an external append only log of the blocks with a header. Blocks should only
|
||||
* be written to the log after they irreverisble as the log is append only. The log is a doubly
|
||||
@@ -35,15 +34,18 @@ namespace eosio { namespace chain {
|
||||
* An optional "pruned" mode can be activated which stores a 4 byte trailer on the log file indicating
|
||||
* how many blocks at the end of the log are valid. Any earlier blocks in the log are assumed destroyed
|
||||
* and unreadable due to reclamation for purposes of saving space.
|
||||
*
|
||||
* Object thread-safe. Not safe to have multiple block_log objects to same data_dir.
|
||||
*/
|
||||
|
||||
struct block_log_prune_config {
|
||||
uint32_t prune_blocks; //number of blocks to prune to when doing a prune
|
||||
size_t prune_threshold = 4*1024*1024; //(approximately) how many bytes need to be added before a prune is performed
|
||||
std::optional<size_t> vacuum_on_close; //when set, a vacuum is performed on dtor if log contains less than this many live bytes
|
||||
};
|
||||
|
||||
class block_log {
|
||||
public:
|
||||
explicit block_log(const fc::path& data_dir, const block_log_config& config = block_log_config{});
|
||||
block_log(block_log&& other) noexcept;
|
||||
block_log(const fc::path& data_dir, std::optional<block_log_prune_config> prune_config);
|
||||
block_log(block_log&& other);
|
||||
~block_log();
|
||||
|
||||
void append(const signed_block_ptr& b, const block_id_type& id);
|
||||
@@ -52,11 +54,12 @@ namespace eosio { namespace chain {
|
||||
void flush();
|
||||
void reset( const genesis_state& gs, const signed_block_ptr& genesis_block );
|
||||
void reset( const chain_id_type& chain_id, uint32_t first_block_num );
|
||||
void remove(); // remove blocks.log and blocks.index
|
||||
|
||||
signed_block_ptr read_block(uint64_t file_pos)const;
|
||||
void read_block_header(block_header& bh, uint64_t file_pos)const;
|
||||
signed_block_ptr read_block_by_num(uint32_t block_num)const;
|
||||
std::optional<signed_block_header> read_block_header_by_num(uint32_t block_num)const;
|
||||
block_id_type read_block_id_by_num(uint32_t block_num)const;
|
||||
|
||||
signed_block_ptr read_block_by_id(const block_id_type& id)const {
|
||||
return read_block_by_num(block_header::num_from_id(id));
|
||||
}
|
||||
@@ -64,11 +67,10 @@ namespace eosio { namespace chain {
|
||||
/**
|
||||
* Return offset of block in file, or block_log::npos if it does not exist.
|
||||
*/
|
||||
|
||||
signed_block_ptr read_head()const; //use blocklog
|
||||
signed_block_ptr head()const;
|
||||
block_id_type head_id()const;
|
||||
|
||||
uint64_t get_block_pos(uint32_t block_num) const;
|
||||
signed_block_ptr read_head()const;
|
||||
const signed_block_ptr& head()const;
|
||||
const block_id_type& head_id()const;
|
||||
uint32_t first_block_num() const;
|
||||
|
||||
static const uint64_t npos = std::numeric_limits<uint64_t>::max();
|
||||
@@ -76,10 +78,6 @@ namespace eosio { namespace chain {
|
||||
static const uint32_t min_supported_version;
|
||||
static const uint32_t max_supported_version;
|
||||
|
||||
/**
|
||||
* All static methods expected to be called on quiescent block log
|
||||
*/
|
||||
|
||||
static fc::path repair_log( const fc::path& data_dir, uint32_t truncate_at_block = 0, const char* reversible_block_dir_name="" );
|
||||
|
||||
static std::optional<genesis_state> extract_genesis_state( const fc::path& data_dir );
|
||||
@@ -96,24 +94,37 @@ namespace eosio { namespace chain {
|
||||
|
||||
static bool is_pruned_log(const fc::path& data_dir);
|
||||
|
||||
static void extract_block_range(const fc::path& block_dir, const fc::path&output_dir, block_num_type start, block_num_type end);
|
||||
static bool extract_block_range(const fc::path& block_dir, const fc::path&output_dir, block_num_type& start, block_num_type& end, bool rename_input=false);
|
||||
|
||||
static bool trim_blocklog_front(const fc::path& block_dir, const fc::path& temp_dir, uint32_t truncate_at_block);
|
||||
static int trim_blocklog_end(const fc::path& block_dir, uint32_t n);
|
||||
|
||||
// used for unit test to generate older version blocklog
|
||||
static void set_initial_version(uint32_t);
|
||||
uint32_t version() const;
|
||||
uint64_t get_block_pos(uint32_t block_num) const;
|
||||
|
||||
/**
|
||||
* @param n Only test 1 block out of every n blocks. If n is 0, the interval is adjusted so that at most 8 blocks are tested.
|
||||
*/
|
||||
static void smoke_test(const fc::path& block_dir, uint32_t n);
|
||||
|
||||
static void split_blocklog(const fc::path& block_dir, const fc::path& dest_dir, uint32_t stride);
|
||||
static void merge_blocklogs(const fc::path& block_dir, const fc::path& dest_dir);
|
||||
private:
|
||||
void open(const fc::path& data_dir);
|
||||
void construct_index();
|
||||
|
||||
std::unique_ptr<detail::block_log_impl> my;
|
||||
};
|
||||
|
||||
//to derive blknum_offset==14 see block_header.hpp and note on disk struct is packed
|
||||
// block_timestamp_type timestamp; //bytes 0:3
|
||||
// account_name producer; //bytes 4:11
|
||||
// uint16_t confirmed; //bytes 12:13
|
||||
// block_id_type previous; //bytes 14:45, low 4 bytes is big endian block number of previous block
|
||||
|
||||
struct trim_data { //used by trim_blocklog_front(), trim_blocklog_end(), and smoke_test()
|
||||
trim_data(fc::path block_dir);
|
||||
~trim_data();
|
||||
uint64_t block_index(uint32_t n) const;
|
||||
uint64_t block_pos(uint32_t n);
|
||||
fc::path block_file_name, index_file_name; //full pathname for blocks.log and blocks.index
|
||||
uint32_t version = 0; //blocklog version
|
||||
uint32_t first_block = 0; //first block in blocks.log
|
||||
uint32_t last_block = 0; //last block in blocks.log
|
||||
FILE* blk_in = nullptr; //C style files for reading blocks.log and blocks.index
|
||||
FILE* ind_in = nullptr; //C style files for reading blocks.log and blocks.index
|
||||
//we use low level file IO because it is distinctly faster than C++ filebuf or iostream
|
||||
uint64_t first_block_pos = 0; //file position in blocks.log for the first block in the log
|
||||
genesis_state gs;
|
||||
chain_id_type chain_id;
|
||||
|
||||
static constexpr int blknum_offset{14}; //offset from start of block to 4 byte block number, valid for the only allowed versions
|
||||
};
|
||||
} }
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <variant>
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
struct basic_blocklog_config {};
|
||||
|
||||
struct empty_blocklog_config {};
|
||||
|
||||
struct partitioned_blocklog_config {
|
||||
bfs::path retained_dir;
|
||||
bfs::path archive_dir;
|
||||
uint32_t stride = UINT32_MAX;
|
||||
uint32_t max_retained_files = UINT32_MAX;
|
||||
};
|
||||
|
||||
struct prune_blocklog_config {
|
||||
uint32_t prune_blocks; // number of blocks to prune to when doing a prune
|
||||
size_t prune_threshold =
|
||||
4 * 1024 * 1024; //(approximately) how many bytes need to be added before a prune is performed
|
||||
std::optional<size_t>
|
||||
vacuum_on_close; // when set, a vacuum is performed on dtor if log contains less than this many live bytes
|
||||
};
|
||||
|
||||
using block_log_config =
|
||||
std::variant<basic_blocklog_config, empty_blocklog_config, partitioned_blocklog_config, prune_blocklog_config>;
|
||||
|
||||
}} // namespace eosio::chain
|
||||
@@ -37,10 +37,6 @@ namespace chain {
|
||||
|
||||
void reflector_init()const;
|
||||
|
||||
static chain_id_type empty_chain_id() {
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
chain_id_type() = default;
|
||||
|
||||
|
||||
@@ -48,7 +48,9 @@ namespace eosio { namespace chain {
|
||||
class fork_database;
|
||||
|
||||
enum class db_read_mode {
|
||||
SPECULATIVE,
|
||||
HEAD,
|
||||
READ_ONLY,
|
||||
IRREVERSIBLE
|
||||
};
|
||||
|
||||
@@ -68,7 +70,7 @@ namespace eosio { namespace chain {
|
||||
flat_set< pair<account_name, action_name> > action_blacklist;
|
||||
flat_set<public_key_type> key_blacklist;
|
||||
path blocks_dir = chain::config::default_blocks_dir_name;
|
||||
block_log_config blog;
|
||||
std::optional<block_log_prune_config> prune_config;
|
||||
path state_dir = chain::config::default_state_dir_name;
|
||||
uint64_t state_size = chain::config::default_state_size;
|
||||
uint64_t state_guard_size = chain::config::default_state_guard_size;
|
||||
@@ -90,7 +92,7 @@ namespace eosio { namespace chain {
|
||||
eosvmoc::config eosvmoc_config;
|
||||
bool eosvmoc_tierup = false;
|
||||
|
||||
db_read_mode read_mode = db_read_mode::HEAD;
|
||||
db_read_mode read_mode = db_read_mode::SPECULATIVE;
|
||||
validation_mode block_validation_mode = validation_mode::FULL;
|
||||
|
||||
pinnable_mapped_file::map_mode db_map_mode = pinnable_mapped_file::map_mode::mapped;
|
||||
@@ -106,8 +108,7 @@ namespace eosio { namespace chain {
|
||||
irreversible = 0, ///< this block has already been applied before by this node and is considered irreversible
|
||||
validated = 1, ///< this is a complete block signed by a valid producer and has been previously applied by this node and therefore validated but it is not yet irreversible
|
||||
complete = 2, ///< this is a complete block signed by a valid producer but is not yet irreversible nor has it yet been applied by this node
|
||||
incomplete = 3, ///< this is an incomplete block being produced by a producer
|
||||
ephemeral = 4 ///< this is an incomplete block created for speculative execution of trxs, will always be aborted
|
||||
incomplete = 3, ///< this is an incomplete block (either being produced by a producer or speculatively produced by a node)
|
||||
};
|
||||
|
||||
controller( const config& cfg, const chain_id_type& chain_id );
|
||||
@@ -119,19 +120,27 @@ namespace eosio { namespace chain {
|
||||
void startup( std::function<void()> shutdown, std::function<bool()> check_shutdown, const genesis_state& genesis);
|
||||
void startup( std::function<void()> shutdown, std::function<bool()> check_shutdown);
|
||||
|
||||
void preactivate_feature( const digest_type& feature_digest, bool is_trx_transient );
|
||||
void preactivate_feature( const digest_type& feature_digest );
|
||||
|
||||
vector<digest_type> get_preactivated_protocol_features()const;
|
||||
|
||||
void validate_protocol_features( const vector<digest_type>& features_to_activate )const;
|
||||
|
||||
/**
|
||||
* Starts a new pending block session upon which new transactions can be pushed.
|
||||
* Starts a new pending block session upon which new transactions can
|
||||
* be pushed.
|
||||
*
|
||||
* Will only activate protocol features that have been pre-activated.
|
||||
*/
|
||||
void start_block( block_timestamp_type time = block_timestamp_type(), uint16_t confirm_block_count = 0 );
|
||||
|
||||
/**
|
||||
* Starts a new pending block session upon which new transactions can
|
||||
* be pushed.
|
||||
*/
|
||||
void start_block( block_timestamp_type time,
|
||||
uint16_t confirm_block_count,
|
||||
const vector<digest_type>& new_protocol_feature_activations,
|
||||
block_status bs,
|
||||
const fc::time_point& deadline = fc::time_point::maximum() );
|
||||
|
||||
/**
|
||||
@@ -221,6 +230,13 @@ namespace eosio { namespace chain {
|
||||
|
||||
uint32_t fork_db_head_block_num()const;
|
||||
block_id_type fork_db_head_block_id()const;
|
||||
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;
|
||||
@@ -236,19 +252,13 @@ namespace eosio { namespace chain {
|
||||
block_id_type last_irreversible_block_id() const;
|
||||
time_point last_irreversible_block_time() const;
|
||||
|
||||
// thread-safe
|
||||
signed_block_ptr fetch_block_by_number( uint32_t block_num )const;
|
||||
// thread-safe
|
||||
signed_block_ptr fetch_block_by_id( const block_id_type& id )const;
|
||||
// thread-safe
|
||||
std::optional<signed_block_header> fetch_block_header_by_number( uint32_t block_num )const;
|
||||
// thread-safe
|
||||
std::optional<signed_block_header> fetch_block_header_by_id( const block_id_type& id )const;
|
||||
// return block_state from forkdb, thread-safe
|
||||
signed_block_ptr fetch_block_by_id( block_id_type id )const;
|
||||
|
||||
block_state_ptr fetch_block_state_by_number( uint32_t block_num )const;
|
||||
// return block_state from forkdb, thread-safe
|
||||
block_state_ptr fetch_block_state_by_id( block_id_type id )const;
|
||||
// thread-safe
|
||||
|
||||
block_id_type get_block_id_for_num( uint32_t block_num )const;
|
||||
|
||||
sha256 calculate_integrity_hash();
|
||||
@@ -260,7 +270,7 @@ namespace eosio { namespace chain {
|
||||
void check_action_list( account_name code, action_name action )const;
|
||||
void check_key_list( const public_key_type& key )const;
|
||||
bool is_building_block()const;
|
||||
bool is_speculative_block()const;
|
||||
bool is_producing_block()const;
|
||||
|
||||
bool is_ram_billing_in_notify_allowed()const;
|
||||
|
||||
@@ -310,13 +320,12 @@ namespace eosio { namespace chain {
|
||||
void add_to_ram_correction( account_name account, uint64_t ram_bytes );
|
||||
bool all_subjective_mitigations_disabled()const;
|
||||
|
||||
deep_mind_handler* get_deep_mind_logger(bool is_trx_transient) const;
|
||||
deep_mind_handler* get_deep_mind_logger() const;
|
||||
void enable_deep_mind( deep_mind_handler* logger );
|
||||
uint32_t earliest_available_block_num() const;
|
||||
|
||||
#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
|
||||
vm::wasm_allocator& get_wasm_allocator();
|
||||
bool is_eos_vm_oc_enabled() const;
|
||||
#endif
|
||||
|
||||
static std::optional<uint64_t> convert_exception_to_error_code( const fc::exception& e );
|
||||
@@ -348,8 +357,9 @@ namespace eosio { namespace chain {
|
||||
if( n.good() ) {
|
||||
try {
|
||||
const auto& a = get_account( n );
|
||||
if( abi_def abi; abi_serializer::to_abi( a.abi, abi ))
|
||||
return abi_serializer( std::move(abi), yield );
|
||||
abi_def abi;
|
||||
if( abi_serializer::to_abi( a.abi, abi ))
|
||||
return abi_serializer( abi, yield );
|
||||
} FC_CAPTURE_AND_LOG((n))
|
||||
}
|
||||
return std::optional<abi_serializer>();
|
||||
@@ -370,10 +380,6 @@ namespace eosio { namespace chain {
|
||||
void replace_producer_keys( const public_key_type& key );
|
||||
void replace_account_keys( name account, name permission, const public_key_type& key );
|
||||
|
||||
void set_db_read_only_mode();
|
||||
void unset_db_read_only_mode();
|
||||
void init_thread_local_data();
|
||||
|
||||
private:
|
||||
friend class apply_context;
|
||||
friend class transaction_context;
|
||||
|
||||
@@ -573,12 +573,6 @@ namespace eosio { namespace chain {
|
||||
3170011, "The signer returned no valid block signatures" )
|
||||
FC_DECLARE_DERIVED_EXCEPTION( unsupported_multiple_block_signatures, producer_exception,
|
||||
3170012, "The signer returned multiple signatures but that is not supported" )
|
||||
FC_DECLARE_DERIVED_EXCEPTION( duplicate_snapshot_request, producer_exception,
|
||||
3170013, "Snapshot has been already scheduled with specified parameters" )
|
||||
FC_DECLARE_DERIVED_EXCEPTION( snapshot_request_not_found, producer_exception,
|
||||
3170014, "Snapshot request not found" )
|
||||
FC_DECLARE_DERIVED_EXCEPTION( invalid_snapshot_request, producer_exception,
|
||||
3170015, "Invalid snapshot request" )
|
||||
|
||||
FC_DECLARE_DERIVED_EXCEPTION( reversible_blocks_exception, chain_exception,
|
||||
3180000, "Reversible Blocks exception" )
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
#pragma once
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/iostreams/device/mapped_file.hpp>
|
||||
#include <fc/io/cfile.hpp>
|
||||
#include <fc/io/datastream.hpp>
|
||||
#include <regex>
|
||||
|
||||
namespace eosio {
|
||||
namespace chain {
|
||||
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
template <typename Lambda>
|
||||
void for_each_file_in_dir_matches(const bfs::path& dir, std::string pattern, Lambda&& lambda) {
|
||||
const std::regex my_filter(pattern);
|
||||
std::smatch what;
|
||||
bfs::directory_iterator end_itr; // Default ctor yields past-the-end
|
||||
for (bfs::directory_iterator p(dir); p != end_itr; ++p) {
|
||||
// Skip if not a file
|
||||
if (!bfs::is_regular_file(p->status()))
|
||||
continue;
|
||||
// skip if it does not match the pattern
|
||||
if (!std::regex_match(p->path().filename().string(), what, my_filter))
|
||||
continue;
|
||||
lambda(p->path());
|
||||
}
|
||||
}
|
||||
|
||||
struct null_verifier {
|
||||
template <typename LogData>
|
||||
void verify(const LogData&, const bfs::path&) {}
|
||||
};
|
||||
|
||||
template <typename LogData, typename LogIndex, typename LogVerifier = null_verifier>
|
||||
struct log_catalog {
|
||||
using block_num_t = uint32_t;
|
||||
|
||||
struct mapped_type {
|
||||
block_num_t last_block_num;
|
||||
bfs::path filename_base;
|
||||
};
|
||||
using collection_t = boost::container::flat_map<block_num_t, mapped_type>;
|
||||
using size_type = typename collection_t::size_type;
|
||||
static constexpr size_type npos = std::numeric_limits<size_type>::max();
|
||||
|
||||
bfs::path retained_dir;
|
||||
bfs::path archive_dir;
|
||||
size_type max_retained_files = std::numeric_limits<size_type>::max();
|
||||
collection_t collection;
|
||||
size_type active_index = npos;
|
||||
LogData log_data;
|
||||
LogIndex log_index;
|
||||
LogVerifier verifier;
|
||||
|
||||
bool empty() const { return collection.empty(); }
|
||||
|
||||
block_num_t first_block_num() const {
|
||||
if (empty())
|
||||
return std::numeric_limits<block_num_t>::max();
|
||||
return collection.begin()->first;
|
||||
}
|
||||
|
||||
block_num_t last_block_num() const {
|
||||
if (empty())
|
||||
return std::numeric_limits<block_num_t>::min();
|
||||
return collection.rbegin()->second.last_block_num;
|
||||
}
|
||||
|
||||
static bfs::path make_absolute_dir(const bfs::path& base_dir, bfs::path new_dir) {
|
||||
if (new_dir.is_relative())
|
||||
new_dir = base_dir / new_dir;
|
||||
|
||||
if (!bfs::is_directory(new_dir))
|
||||
bfs::create_directories(new_dir);
|
||||
|
||||
return new_dir;
|
||||
}
|
||||
|
||||
void open(const bfs::path& log_dir, const bfs::path& retained_path, const bfs::path& archive_path, const char* name,
|
||||
const char* suffix_pattern = R"(-\d+-\d+\.log)") {
|
||||
|
||||
retained_dir = make_absolute_dir(log_dir, retained_path.empty() ? log_dir : retained_path);
|
||||
if (!archive_path.empty()) {
|
||||
archive_dir = make_absolute_dir(log_dir, archive_path);
|
||||
}
|
||||
|
||||
for_each_file_in_dir_matches(retained_dir, std::string(name) + suffix_pattern, [this](bfs::path path) {
|
||||
auto log_path = path;
|
||||
auto index_path = path.replace_extension("index");
|
||||
auto path_without_extension = log_path.parent_path() / log_path.stem().string();
|
||||
|
||||
LogData log(log_path);
|
||||
|
||||
verifier.verify(log, log_path);
|
||||
|
||||
// check if index file matches the log file
|
||||
if (!index_matches_data(index_path, log))
|
||||
log.construct_index(index_path);
|
||||
|
||||
auto existing_itr = collection.find(log.first_block_num());
|
||||
if (existing_itr != collection.end()) {
|
||||
if (log.last_block_num() <= existing_itr->second.last_block_num) {
|
||||
wlog("${log_path} contains the overlapping range with ${existing_path}.log, dropping ${log_path} "
|
||||
"from catalog",
|
||||
("log_path", log_path.string())("existing_path", existing_itr->second.filename_base.string()));
|
||||
return;
|
||||
} else {
|
||||
wlog(
|
||||
"${log_path} contains the overlapping range with ${existing_path}.log, droping ${existing_path}.log "
|
||||
"from catelog",
|
||||
("log_path", log_path.string())("existing_path", existing_itr->second.filename_base.string()));
|
||||
}
|
||||
}
|
||||
|
||||
collection.insert_or_assign(log.first_block_num(), mapped_type{log.last_block_num(), path_without_extension});
|
||||
});
|
||||
}
|
||||
|
||||
bool index_matches_data(const bfs::path& index_path, LogData& log) const {
|
||||
if (!bfs::exists(index_path))
|
||||
return false;
|
||||
|
||||
auto num_blocks_in_index = bfs::file_size(index_path) / sizeof(uint64_t);
|
||||
if (num_blocks_in_index != log.num_blocks())
|
||||
return false;
|
||||
|
||||
// make sure the last 8 bytes of index and log matches
|
||||
fc::cfile index_file;
|
||||
index_file.set_file_path(index_path);
|
||||
index_file.open("r");
|
||||
index_file.seek_end(-sizeof(uint64_t));
|
||||
uint64_t pos;
|
||||
index_file.read(reinterpret_cast<char*>(&pos), sizeof(pos));
|
||||
return pos == log.last_block_position();
|
||||
}
|
||||
|
||||
std::optional<uint64_t> get_block_position(uint32_t block_num) {
|
||||
try {
|
||||
if (active_index != npos) {
|
||||
auto active_item = collection.nth(active_index);
|
||||
if (active_item->first <= block_num && block_num <= active_item->second.last_block_num) {
|
||||
return log_index.nth_block_position(block_num - log_data.first_block_num());
|
||||
}
|
||||
}
|
||||
if (block_num < first_block_num())
|
||||
return {};
|
||||
|
||||
auto it = --collection.upper_bound(block_num);
|
||||
|
||||
if (block_num <= it->second.last_block_num) {
|
||||
auto name = it->second.filename_base;
|
||||
log_data.open(name.replace_extension("log"));
|
||||
log_index.open(name.replace_extension("index"));
|
||||
active_index = collection.index_of(it);
|
||||
return log_index.nth_block_position(block_num - log_data.first_block_num());
|
||||
}
|
||||
return {};
|
||||
} catch (...) {
|
||||
active_index = npos;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
fc::datastream<fc::cfile>* ro_stream_for_block(uint32_t block_num) {
|
||||
auto pos = get_block_position(block_num);
|
||||
if (pos) {
|
||||
return &log_data.ro_stream_at(*pos);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename ...Rest>
|
||||
auto ro_stream_for_block(uint32_t block_num, Rest&& ...rest) -> std::optional<decltype( std::declval<LogData>().ro_stream_at(0, std::forward<Rest&&>(rest)...))> {
|
||||
auto pos = get_block_position(block_num);
|
||||
if (pos) {
|
||||
return log_data.ro_stream_at(*pos, std::forward<Rest&&>(rest)...);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<block_id_type> id_for_block(uint32_t block_num) {
|
||||
auto pos = get_block_position(block_num);
|
||||
if (pos) {
|
||||
return log_data.block_id_at(*pos);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static void rename_if_not_exists(bfs::path old_name, bfs::path new_name) {
|
||||
if (!bfs::exists(new_name)) {
|
||||
bfs::rename(old_name, new_name);
|
||||
} else {
|
||||
bfs::remove(old_name);
|
||||
wlog("${new_name} already exists, just removing ${old_name}",
|
||||
("old_name", old_name.string())("new_name", new_name.string()));
|
||||
}
|
||||
}
|
||||
|
||||
static void rename_bundle(bfs::path orig_path, bfs::path new_path) {
|
||||
rename_if_not_exists(orig_path.replace_extension(".log"), new_path.replace_extension(".log"));
|
||||
rename_if_not_exists(orig_path.replace_extension(".index"), new_path.replace_extension(".index"));
|
||||
}
|
||||
|
||||
/// Add a new entry into the catalog.
|
||||
///
|
||||
/// Notice that \c start_block_num must be monotonically increasing between the invocations of this function
|
||||
/// so that the new entry would be inserted at the end of the flat_map; otherwise, \c active_index would be
|
||||
/// invalidated and the mapping between the log data their block range would be wrong. This function is only used
|
||||
/// during the splitting of block log. Using this function for other purpose should make sure if the monotonically
|
||||
/// increasing block num guarantee can be met.
|
||||
void add(uint32_t start_block_num, uint32_t end_block_num, const bfs::path& dir, const char* name) {
|
||||
|
||||
const int bufsize = 64;
|
||||
char buf[bufsize];
|
||||
snprintf(buf, bufsize, "%s-%u-%u", name, start_block_num, end_block_num);
|
||||
bfs::path new_path = retained_dir / buf;
|
||||
rename_bundle(dir / name, new_path);
|
||||
size_type items_to_erase = 0;
|
||||
collection.emplace(start_block_num, mapped_type{end_block_num, new_path});
|
||||
if (collection.size() >= max_retained_files) {
|
||||
items_to_erase =
|
||||
max_retained_files > 0 ? collection.size() - max_retained_files : collection.size();
|
||||
|
||||
for (auto it = collection.begin(); it < collection.begin() + items_to_erase; ++it) {
|
||||
auto orig_name = it->second.filename_base;
|
||||
if (archive_dir.empty()) {
|
||||
// delete the old files when no backup dir is specified
|
||||
bfs::remove(orig_name.replace_extension("log"));
|
||||
bfs::remove(orig_name.replace_extension("index"));
|
||||
} else {
|
||||
// move the the archive dir
|
||||
rename_bundle(orig_name, archive_dir / orig_name.filename());
|
||||
}
|
||||
}
|
||||
collection.erase(collection.begin(), collection.begin() + items_to_erase);
|
||||
active_index = active_index == npos || active_index < items_to_erase
|
||||
? npos
|
||||
: active_index - items_to_erase;
|
||||
}
|
||||
}
|
||||
|
||||
/// Truncate the catalog so that the log/index bundle containing the block with \c block_num
|
||||
/// would be rename to \c new_name; the log/index bundles with blocks strictly higher
|
||||
/// than \c block_num would be deleted, and all the renamed/removed entries would be erased
|
||||
/// from the catalog.
|
||||
///
|
||||
/// \return if nonzero, it's the starting block number for the log/index bundle being renamed.
|
||||
uint32_t truncate(uint32_t block_num, bfs::path new_name) {
|
||||
if (collection.empty())
|
||||
return 0;
|
||||
|
||||
auto remove_files = [](typename collection_t::const_reference v) {
|
||||
auto name = v.second.filename_base;
|
||||
bfs::remove(name.replace_extension("log"));
|
||||
bfs::remove(name.replace_extension("index"));
|
||||
};
|
||||
|
||||
active_index = npos;
|
||||
auto it = collection.upper_bound(block_num);
|
||||
|
||||
if (it == collection.begin() || block_num > (it - 1)->second.last_block_num) {
|
||||
std::for_each(it, collection.end(), remove_files);
|
||||
collection.erase(it, collection.end());
|
||||
return 0;
|
||||
} else {
|
||||
auto truncate_it = --it;
|
||||
auto name = truncate_it->second.filename_base;
|
||||
bfs::rename(name.replace_extension("log"), new_name.replace_extension("log"));
|
||||
bfs::rename(name.replace_extension("index"), new_name.replace_extension("index"));
|
||||
std::for_each(truncate_it + 1, collection.end(), remove_files);
|
||||
auto result = truncate_it->first;
|
||||
collection.erase(truncate_it, collection.end());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace chain
|
||||
} // namespace eosio
|
||||
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/io/cfile.hpp>
|
||||
|
||||
namespace eosio {
|
||||
namespace chain {
|
||||
|
||||
template <typename T>
|
||||
T read_data_at(fc::datastream<fc::cfile>& file, std::size_t offset) {
|
||||
file.seek(offset);
|
||||
T value;
|
||||
fc::raw::unpack(file, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
class log_data_base {
|
||||
protected:
|
||||
fc::datastream<fc::cfile> file;
|
||||
|
||||
Derived* self() { return static_cast<Derived*>(this); }
|
||||
const Derived* self() const { return static_cast<const Derived*>(this); }
|
||||
|
||||
public:
|
||||
|
||||
log_data_base() = default;
|
||||
|
||||
void close() { file.close(); }
|
||||
bool is_open() const { return file.is_open(); }
|
||||
|
||||
uint64_t size() const { return self()->size(); }
|
||||
|
||||
uint32_t last_block_num() { return self()->block_num_at(last_block_position()); }
|
||||
uint64_t last_block_position() {
|
||||
uint32_t offset = sizeof(uint64_t);
|
||||
if (self()->is_currently_pruned())
|
||||
offset += sizeof(uint32_t);
|
||||
return read_data_at<uint64_t>(file, size() - offset);
|
||||
}
|
||||
|
||||
uint32_t num_blocks() {
|
||||
if (self()->first_block_position() == size())
|
||||
return 0;
|
||||
else if (self()->is_currently_pruned())
|
||||
return read_data_at<uint32_t>(file, size() - sizeof(uint32_t));
|
||||
return last_block_num() - self()->first_block_num() + 1;
|
||||
}
|
||||
};
|
||||
} // namespace chain
|
||||
} // namespace eosio
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <fc/io/cfile.hpp>
|
||||
|
||||
namespace eosio {
|
||||
namespace chain {
|
||||
/// copy up to n bytes from the current position of src to dest
|
||||
void copy_file_content(fc::cfile& src, fc::cfile& dest, uint64_t n = UINT64_MAX);
|
||||
|
||||
template <typename Exception>
|
||||
class log_index {
|
||||
fc::cfile file_;
|
||||
std::size_t num_blocks_ = 0;
|
||||
public:
|
||||
log_index() = default;
|
||||
log_index(const boost::filesystem::path& path) {
|
||||
open(path);
|
||||
}
|
||||
|
||||
void open(const boost::filesystem::path& path) {
|
||||
if (file_.is_open())
|
||||
file_.close();
|
||||
file_.set_file_path(path);
|
||||
file_.open("rb");
|
||||
file_.seek_end(0);
|
||||
num_blocks_ = file_.tellp()/ sizeof(uint64_t);
|
||||
EOS_ASSERT(file_.tellp() % sizeof(uint64_t) == 0, Exception,
|
||||
"The size of ${file} is not a multiple of sizeof(uint64_t)", ("file", path.generic_string()));
|
||||
}
|
||||
|
||||
bool is_open() const { return file_.is_open(); }
|
||||
|
||||
uint64_t back() { return nth_block_position(num_blocks()-1); }
|
||||
unsigned num_blocks() const { return num_blocks_; }
|
||||
uint64_t nth_block_position(uint32_t n) {
|
||||
file_.seek(n*sizeof(uint64_t));
|
||||
uint64_t r;
|
||||
file_.read((char*)&r, sizeof(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
void copy_to(fc::cfile& dest, uint64_t nbytes) {
|
||||
file_.seek(0);
|
||||
copy_file_content(file_, dest, nbytes);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace chain
|
||||
} // namespace eosio
|
||||
@@ -335,3 +335,4 @@ FC_REFLECT_DERIVED( eosio::chain::producer_schedule_change_extension, (eosio::ch
|
||||
FC_REFLECT( eosio::chain::shared_block_signing_authority_v0, (threshold)(keys))
|
||||
FC_REFLECT( eosio::chain::shared_producer_authority, (producer_name)(authority) )
|
||||
FC_REFLECT( eosio::chain::shared_producer_authority_schedule, (version)(producers) )
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ protected:
|
||||
class protocol_feature_manager {
|
||||
public:
|
||||
|
||||
protocol_feature_manager( protocol_feature_set&& pfs, std::function<deep_mind_handler*(bool is_trx_transient)> get_deep_mind_logger );
|
||||
protocol_feature_manager( protocol_feature_set&& pfs, std::function<deep_mind_handler*()> get_deep_mind_logger );
|
||||
|
||||
class const_iterator {
|
||||
public:
|
||||
@@ -393,12 +393,9 @@ protected:
|
||||
bool _initialized = false;
|
||||
|
||||
private:
|
||||
std::function<deep_mind_handler*(bool is_trx_transient)> _get_deep_mind_logger;
|
||||
std::function<deep_mind_handler*()> _get_deep_mind_logger;
|
||||
};
|
||||
|
||||
std::optional<builtin_protocol_feature> read_builtin_protocol_feature( const fc::path& p );
|
||||
protocol_feature_set initialize_protocol_features( const fc::path& p, bool populate_missing_builtins = true );
|
||||
|
||||
} } // namespace eosio::chain
|
||||
|
||||
FC_REFLECT(eosio::chain::protocol_feature_subjective_restrictions,
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace eosio { namespace chain {
|
||||
class resource_limits_manager {
|
||||
public:
|
||||
|
||||
explicit resource_limits_manager(chainbase::database& db, std::function<deep_mind_handler*(bool is_trx_transient)> get_deep_mind_logger)
|
||||
explicit resource_limits_manager(chainbase::database& db, std::function<deep_mind_handler*()> get_deep_mind_logger)
|
||||
:_db(db),_get_deep_mind_logger(get_deep_mind_logger)
|
||||
{
|
||||
}
|
||||
@@ -74,17 +74,17 @@ namespace eosio { namespace chain {
|
||||
void add_to_snapshot( const snapshot_writer_ptr& snapshot ) const;
|
||||
void read_from_snapshot( const snapshot_reader_ptr& snapshot );
|
||||
|
||||
void initialize_account( const account_name& account, bool is_trx_transient );
|
||||
void initialize_account( const account_name& account );
|
||||
void set_block_parameters( const elastic_limit_parameters& cpu_limit_parameters, const elastic_limit_parameters& net_limit_parameters );
|
||||
|
||||
void update_account_usage( const flat_set<account_name>& accounts, uint32_t ordinal );
|
||||
void add_transaction_usage( const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t ordinal, bool is_trx_transient = false );
|
||||
void add_transaction_usage( const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t ordinal );
|
||||
|
||||
void add_pending_ram_usage( const account_name account, int64_t ram_delta, bool is_trx_transient = false );
|
||||
void add_pending_ram_usage( const account_name account, int64_t ram_delta );
|
||||
void verify_account_ram_usage( const account_name accunt )const;
|
||||
|
||||
/// set_account_limits returns true if new ram_bytes limit is more restrictive than the previously set one
|
||||
bool set_account_limits( const account_name& account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight, bool is_trx_transient);
|
||||
bool set_account_limits( const account_name& account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight);
|
||||
void get_account_limits( const account_name& account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight) const;
|
||||
|
||||
bool is_unlimited_cpu( const account_name& account ) const;
|
||||
@@ -114,7 +114,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
private:
|
||||
chainbase::database& _db;
|
||||
std::function<deep_mind_handler*(bool is_trx_transient)> _get_deep_mind_logger;
|
||||
std::function<deep_mind_handler*()> _get_deep_mind_logger;
|
||||
};
|
||||
} } } /// eosio::chain
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <eosio/chain/name.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <fc/log/logger_config.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <future>
|
||||
@@ -13,108 +10,45 @@
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
/**
|
||||
* Wrapper class for thread pool of boost asio io_context run.
|
||||
* Wrapper class for boost asio thread pool and io_context run.
|
||||
* Also names threads so that tools like htop can see thread name.
|
||||
* Example: named_thread_pool<struct net> thread_pool;
|
||||
* or: struct net{}; named_thread_pool<net> thread_pool;
|
||||
* @param NamePrefixTag is a type name appended with -## of thread.
|
||||
* A short NamePrefixTag type name (6 chars or under) is recommended as console_appender uses
|
||||
* 9 chars for the thread name.
|
||||
*/
|
||||
template<typename NamePrefixTag>
|
||||
class named_thread_pool {
|
||||
public:
|
||||
using on_except_t = std::function<void(const fc::exception& e)>;
|
||||
using init_t = std::function<void()>;
|
||||
// name_prefix is name appended with -## of thread.
|
||||
// short name_prefix (6 chars or under) is recommended as console_appender uses 9 chars for thread name
|
||||
/// @param delay_start do not spawn threads in constructor, wait for start() call
|
||||
named_thread_pool( std::string name_prefix, size_t num_threads, bool delay_start = false );
|
||||
|
||||
named_thread_pool() = default;
|
||||
|
||||
~named_thread_pool(){
|
||||
stop();
|
||||
}
|
||||
// calls stop()
|
||||
~named_thread_pool();
|
||||
|
||||
boost::asio::io_context& get_executor() { return _ioc; }
|
||||
|
||||
/// Spawn threads, can be re-started after stop().
|
||||
/// Assumes start()/stop() called from the same thread or externally protected.
|
||||
/// @param num_threads is number of threads spawned
|
||||
/// @param on_except is the function to call if io_context throws an exception, is called from thread pool thread.
|
||||
/// if an empty function then logs and rethrows exception on thread which will terminate.
|
||||
/// @param init is an optional function to call at startup to initialize any data.
|
||||
/// @throw assert_exception if already started and not stopped.
|
||||
void start( size_t num_threads, on_except_t on_except, init_t init = {} ) {
|
||||
FC_ASSERT( !_ioc_work, "Thread pool already started" );
|
||||
_ioc_work.emplace( boost::asio::make_work_guard( _ioc ) );
|
||||
_ioc.restart();
|
||||
_thread_pool.reserve( num_threads );
|
||||
for( size_t i = 0; i < num_threads; ++i ) {
|
||||
_thread_pool.emplace_back( std::thread( &named_thread_pool::run_thread, this, i, on_except, init ) );
|
||||
}
|
||||
}
|
||||
void start();
|
||||
|
||||
/// destroy work guard, stop io_context, join thread_pool
|
||||
void stop() {
|
||||
_ioc_work.reset();
|
||||
_ioc.stop();
|
||||
for( auto& t : _thread_pool ) {
|
||||
t.join();
|
||||
}
|
||||
_thread_pool.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
void run_thread( size_t i, const on_except_t& on_except, const init_t& init ) {
|
||||
std::string tn = boost::core::demangle(typeid(this).name());
|
||||
auto offset = tn.rfind("::");
|
||||
if (offset != std::string::npos)
|
||||
tn.erase(0, offset+2);
|
||||
tn = tn.substr(0, tn.find('>')) + "-" + std::to_string( i );
|
||||
try {
|
||||
fc::set_os_thread_name( tn );
|
||||
if ( init )
|
||||
init();
|
||||
_ioc.run();
|
||||
} catch( const fc::exception& e ) {
|
||||
if( on_except ) {
|
||||
on_except( e );
|
||||
} else {
|
||||
elog( "Exiting thread ${t} on exception: ${e}", ("t", tn)("e", e.to_detail_string()) );
|
||||
throw;
|
||||
}
|
||||
} catch( const std::exception& e ) {
|
||||
fc::std_exception_wrapper se( FC_LOG_MESSAGE( warn, "${what}: ", ("what", e.what()) ),
|
||||
std::current_exception(), BOOST_CORE_TYPEID( e ).name(), e.what() );
|
||||
if( on_except ) {
|
||||
on_except( se );
|
||||
} else {
|
||||
elog( "Exiting thread ${t} on exception: ${e}", ("t", tn)("e", se.to_detail_string()) );
|
||||
throw;
|
||||
}
|
||||
} catch( ... ) {
|
||||
if( on_except ) {
|
||||
fc::unhandled_exception ue( FC_LOG_MESSAGE( warn, "unknown exception" ), std::current_exception() );
|
||||
on_except( ue );
|
||||
} else {
|
||||
elog( "Exiting thread ${t} on unknown exception", ("t", tn) );
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
void stop();
|
||||
|
||||
private:
|
||||
using ioc_work_t = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;
|
||||
|
||||
boost::asio::io_context _ioc;
|
||||
std::string _name_prefix;
|
||||
size_t _num_threads;
|
||||
std::vector<std::thread> _thread_pool;
|
||||
boost::asio::io_context _ioc;
|
||||
std::optional<ioc_work_t> _ioc_work;
|
||||
};
|
||||
|
||||
|
||||
// async on io_context and return future
|
||||
// async on thread_pool and return future
|
||||
template<typename F>
|
||||
auto post_async_task( boost::asio::io_context& ioc, F&& f ) {
|
||||
auto async_thread_pool( boost::asio::io_context& thread_pool, F&& f ) {
|
||||
auto task = std::make_shared<std::packaged_task<decltype( f() )()>>( std::forward<F>( f ) );
|
||||
boost::asio::post( ioc, [task]() { (*task)(); } );
|
||||
boost::asio::post( thread_pool, [task]() { (*task)(); } );
|
||||
return task->get_future();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,10 @@ namespace eosio { namespace chain {
|
||||
|
||||
transaction_context( controller& c,
|
||||
const packed_transaction& t,
|
||||
const transaction_id_type& trx_id, // trx_id diff than t.id() before replace_deferred
|
||||
transaction_checktime_timer&& timer,
|
||||
fc::time_point start = fc::time_point::now(),
|
||||
transaction_metadata::trx_type type = transaction_metadata::trx_type::input);
|
||||
bool read_only=false);
|
||||
~transaction_context();
|
||||
|
||||
void init_for_implicit_trx( uint64_t initial_net_usage = 0 );
|
||||
@@ -83,10 +84,6 @@ namespace eosio { namespace chain {
|
||||
|
||||
void validate_referenced_accounts( const transaction& trx, bool enforce_actor_whitelist_blacklist )const;
|
||||
|
||||
bool is_dry_run()const { return trx_type == transaction_metadata::trx_type::dry_run; };
|
||||
bool is_read_only()const { return trx_type == transaction_metadata::trx_type::read_only; };
|
||||
bool is_transient()const { return trx_type == transaction_metadata::trx_type::read_only || trx_type == transaction_metadata::trx_type::dry_run; };
|
||||
|
||||
private:
|
||||
|
||||
friend struct controller_impl;
|
||||
@@ -120,13 +117,12 @@ namespace eosio { namespace chain {
|
||||
|
||||
void disallow_transaction_extensions( const char* error_msg )const;
|
||||
|
||||
std::string get_tx_cpu_usage_exceeded_reason_msg(fc::microseconds& limit) const;
|
||||
|
||||
/// Fields:
|
||||
public:
|
||||
|
||||
controller& control;
|
||||
const packed_transaction& packed_trx;
|
||||
const transaction_id_type& id;
|
||||
std::optional<chainbase::database::session> undo_session;
|
||||
transaction_trace_ptr trace;
|
||||
fc::time_point start;
|
||||
@@ -154,9 +150,9 @@ namespace eosio { namespace chain {
|
||||
|
||||
transaction_checktime_timer transaction_timer;
|
||||
|
||||
const bool is_read_only;
|
||||
private:
|
||||
bool is_initialized = false;
|
||||
transaction_metadata::trx_type trx_type;
|
||||
|
||||
uint64_t net_limit = 0;
|
||||
bool net_limit_due_to_block = true;
|
||||
@@ -175,16 +171,6 @@ namespace eosio { namespace chain {
|
||||
int64_t billing_timer_exception_code = block_cpu_usage_exceeded::code_value;
|
||||
fc::time_point pseudo_start;
|
||||
fc::microseconds billed_time;
|
||||
|
||||
enum class tx_cpu_usage_exceeded_reason {
|
||||
account_cpu_limit, // includes subjective billing
|
||||
on_chain_consensus_max_transaction_cpu_usage,
|
||||
user_specified_trx_max_cpu_usage_ms,
|
||||
node_configured_max_transaction_time,
|
||||
speculative_executed_adjusted_max_transaction_time // prev_billed_cpu_time_us > 0
|
||||
};
|
||||
tx_cpu_usage_exceeded_reason tx_cpu_usage_reason = tx_cpu_usage_exceeded_reason::account_cpu_limit;
|
||||
fc::microseconds tx_cpu_usage_amount;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
@@ -24,7 +24,6 @@ class transaction_metadata {
|
||||
input,
|
||||
implicit,
|
||||
scheduled,
|
||||
dry_run,
|
||||
read_only
|
||||
};
|
||||
|
||||
@@ -32,9 +31,11 @@ class transaction_metadata {
|
||||
const packed_transaction_ptr _packed_trx;
|
||||
const fc::microseconds _sig_cpu_usage;
|
||||
const flat_set<public_key_type> _recovered_pub_keys;
|
||||
const trx_type _trx_type;
|
||||
|
||||
public:
|
||||
const bool implicit;
|
||||
const bool scheduled;
|
||||
const bool read_only;
|
||||
bool accepted = false; // not thread safe
|
||||
uint32_t billed_cpu_time_us = 0; // not thread safe
|
||||
|
||||
@@ -51,11 +52,13 @@ class transaction_metadata {
|
||||
// creation of tranaction_metadata restricted to start_recover_keys and create_no_recover_keys below, public for make_shared
|
||||
explicit transaction_metadata( const private_type& pt, packed_transaction_ptr ptrx,
|
||||
fc::microseconds sig_cpu_usage, flat_set<public_key_type> recovered_pub_keys,
|
||||
trx_type t = trx_type::input )
|
||||
bool _implicit = false, bool _scheduled = false, bool _read_only = false)
|
||||
: _packed_trx( std::move( ptrx ) )
|
||||
, _sig_cpu_usage( sig_cpu_usage )
|
||||
, _recovered_pub_keys( std::move( recovered_pub_keys ) )
|
||||
, _trx_type( t ) {
|
||||
, implicit( _implicit )
|
||||
, scheduled( _scheduled )
|
||||
, read_only( _read_only) {
|
||||
}
|
||||
|
||||
transaction_metadata() = delete;
|
||||
@@ -70,12 +73,6 @@ class transaction_metadata {
|
||||
fc::microseconds signature_cpu_usage()const { return _sig_cpu_usage; }
|
||||
const flat_set<public_key_type>& recovered_keys()const { return _recovered_pub_keys; }
|
||||
size_t get_estimated_size() const;
|
||||
trx_type get_trx_type() const { return _trx_type; };
|
||||
bool implicit() const { return _trx_type == trx_type::implicit; };
|
||||
bool scheduled() const { return _trx_type == trx_type::scheduled; };
|
||||
bool is_dry_run() const { return _trx_type == trx_type::dry_run; };
|
||||
bool is_read_only() const { return _trx_type == trx_type::read_only; };
|
||||
bool is_transient() const { return _trx_type == trx_type::read_only || _trx_type == trx_type::dry_run; };
|
||||
|
||||
/// Thread safe.
|
||||
/// @returns transaction_metadata_ptr or exception via future
|
||||
@@ -88,7 +85,7 @@ class transaction_metadata {
|
||||
static transaction_metadata_ptr
|
||||
create_no_recover_keys( packed_transaction_ptr trx, trx_type t ) {
|
||||
return std::make_shared<transaction_metadata>( private_type(), std::move(trx),
|
||||
fc::microseconds(), flat_set<public_key_type>(), t );
|
||||
fc::microseconds(), flat_set<public_key_type>(), t == trx_type::implicit, t == trx_type::scheduled, t==trx_type::read_only );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -21,10 +21,11 @@ using namespace boost::multi_index;
|
||||
|
||||
enum class trx_enum_type {
|
||||
unknown = 0,
|
||||
forked = 1,
|
||||
aborted = 2,
|
||||
incoming_api = 3,
|
||||
incoming_p2p = 4 // incoming_end() needs to be updated if this changes
|
||||
persisted = 1,
|
||||
forked = 2,
|
||||
aborted = 3,
|
||||
incoming_persisted = 4,
|
||||
incoming = 5 // incoming_end() needs to be updated if this changes
|
||||
};
|
||||
|
||||
using next_func_t = std::function<void(const std::variant<fc::exception_ptr, transaction_trace_ptr>&)>;
|
||||
@@ -45,7 +46,8 @@ struct unapplied_transaction {
|
||||
};
|
||||
|
||||
/**
|
||||
* Track unapplied transactions for incoming, forked blocks, and aborted blocks.
|
||||
* Track unapplied transactions for persisted, forked blocks, and aborted blocks.
|
||||
* Persisted are first so that they can be applied in each block until expired.
|
||||
*/
|
||||
class unapplied_transaction_queue {
|
||||
private:
|
||||
@@ -157,11 +159,26 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void add_incoming( const transaction_metadata_ptr& trx, bool api_trx, bool return_failure_trace, next_func_t next ) {
|
||||
void add_persisted( const transaction_metadata_ptr& trx ) {
|
||||
auto itr = queue.get<by_trx_id>().find( trx->id() );
|
||||
if( itr == queue.get<by_trx_id>().end() ) {
|
||||
auto insert_itr = queue.insert( { trx, trx_enum_type::persisted } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
} else if( itr->trx_type != trx_enum_type::persisted ) {
|
||||
if (itr->trx_type == trx_enum_type::incoming || itr->trx_type == trx_enum_type::incoming_persisted)
|
||||
--incoming_count;
|
||||
queue.get<by_trx_id>().modify( itr, [](auto& un){
|
||||
un.trx_type = trx_enum_type::persisted;
|
||||
un.next = nullptr; // persisted already have ack'ed initial trace
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
void add_incoming( const transaction_metadata_ptr& trx, bool persist_until_expired, bool return_failure_trace, next_func_t next ) {
|
||||
auto itr = queue.get<by_trx_id>().find( trx->id() );
|
||||
if( itr == queue.get<by_trx_id>().end() ) {
|
||||
auto insert_itr = queue.insert(
|
||||
{ trx, api_trx ? trx_enum_type::incoming_api : trx_enum_type::incoming_p2p, return_failure_trace, std::move( next ) } );
|
||||
{ trx, persist_until_expired ? trx_enum_type::incoming_persisted : trx_enum_type::incoming, return_failure_trace, std::move( next ) } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
} else {
|
||||
if( itr->trx_meta == trx ) return; // same trx meta pointer
|
||||
@@ -177,11 +194,14 @@ public:
|
||||
iterator begin() { return queue.get<by_type>().begin(); }
|
||||
iterator end() { return queue.get<by_type>().end(); }
|
||||
|
||||
// forked, aborted
|
||||
// persisted, forked, aborted
|
||||
iterator unapplied_begin() { return queue.get<by_type>().begin(); }
|
||||
iterator unapplied_end() { return queue.get<by_type>().upper_bound( trx_enum_type::aborted ); }
|
||||
|
||||
iterator incoming_begin() { return queue.get<by_type>().lower_bound( trx_enum_type::incoming_api ); }
|
||||
iterator persisted_begin() { return queue.get<by_type>().lower_bound( trx_enum_type::persisted ); }
|
||||
iterator persisted_end() { return queue.get<by_type>().upper_bound( trx_enum_type::persisted ); }
|
||||
|
||||
iterator incoming_begin() { return queue.get<by_type>().lower_bound( trx_enum_type::incoming_persisted ); }
|
||||
iterator incoming_end() { return queue.get<by_type>().end(); } // if changed to upper_bound, verify usage performance
|
||||
|
||||
iterator lower_bound( const transaction_id_type& id ) {
|
||||
@@ -200,7 +220,7 @@ private:
|
||||
template<typename Itr>
|
||||
void added( Itr itr ) {
|
||||
auto size = calc_size( itr->trx_meta );
|
||||
if( itr->trx_type == trx_enum_type::incoming_p2p || itr->trx_type == trx_enum_type::incoming_api ) {
|
||||
if( itr->trx_type == trx_enum_type::incoming || itr->trx_type == trx_enum_type::incoming_persisted ) {
|
||||
++incoming_count;
|
||||
EOS_ASSERT( size_in_bytes + size < max_transaction_queue_size, tx_resource_exhaustion,
|
||||
"Transaction ${id}, size ${s} bytes would exceed configured "
|
||||
@@ -213,7 +233,7 @@ private:
|
||||
|
||||
template<typename Itr>
|
||||
void removed( Itr itr ) {
|
||||
if( itr->trx_type == trx_enum_type::incoming_p2p || itr->trx_type == trx_enum_type::incoming_api ) {
|
||||
if( itr->trx_type == trx_enum_type::incoming || itr->trx_type == trx_enum_type::incoming_persisted ) {
|
||||
--incoming_count;
|
||||
}
|
||||
size_in_bytes -= calc_size( itr->trx_meta );
|
||||
|
||||
@@ -332,7 +332,7 @@ namespace eosio { namespace chain { namespace wasm_validations {
|
||||
public:
|
||||
wasm_binary_validation( const eosio::chain::controller& control, IR::Module& mod ) : _module( &mod ) {
|
||||
// initialize validators here
|
||||
nested_validator::init(!control.is_speculative_block());
|
||||
nested_validator::init(!control.is_producing_block());
|
||||
}
|
||||
|
||||
void validate() {
|
||||
|
||||
@@ -45,9 +45,6 @@ namespace eosio { namespace chain {
|
||||
wasm_interface(vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile);
|
||||
~wasm_interface();
|
||||
|
||||
// initialize exec per thread
|
||||
void init_thread_local_data();
|
||||
|
||||
//call before dtor to skip what can be minutes of dtor overhead with some runtimes; can cause leaks
|
||||
void indicate_shutting_down();
|
||||
|
||||
@@ -66,16 +63,12 @@ namespace eosio { namespace chain {
|
||||
//Immediately exits currently running wasm. UB is called when no wasm running
|
||||
void exit();
|
||||
|
||||
//Returns true if the code is cached
|
||||
bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) const;
|
||||
|
||||
// If substitute_apply is set, then apply calls it before doing anything else. If substitute_apply returns true,
|
||||
// then apply returns immediately.
|
||||
std::function<bool(
|
||||
const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, apply_context& context)> substitute_apply;
|
||||
private:
|
||||
unique_ptr<struct wasm_interface_impl> my;
|
||||
vm_type vm;
|
||||
};
|
||||
|
||||
} } // eosio::chain
|
||||
|
||||
@@ -50,21 +50,11 @@ namespace eosio { namespace chain {
|
||||
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|
||||
struct eosvmoc_tier {
|
||||
eosvmoc_tier(const boost::filesystem::path& d, const eosvmoc::config& c, const chainbase::database& db)
|
||||
: cc(d, c, db) {
|
||||
// construct exec for the main thread
|
||||
init_thread_local_data();
|
||||
}
|
||||
|
||||
// Support multi-threaded execution.
|
||||
void init_thread_local_data() {
|
||||
exec = std::make_unique<eosvmoc::executor>(cc);
|
||||
}
|
||||
|
||||
: cc(d, c, db), exec(cc),
|
||||
mem(wasm_constraints::maximum_linear_memory/wasm_constraints::wasm_page_size) {}
|
||||
eosvmoc::code_cache_async cc;
|
||||
|
||||
// Each thread requires its own exec and mem. Defined in wasm_interface.cpp
|
||||
thread_local static std::unique_ptr<eosvmoc::executor> exec;
|
||||
thread_local static eosvmoc::memory mem;
|
||||
eosvmoc::executor exec;
|
||||
eosvmoc::memory mem;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -104,11 +94,6 @@ namespace eosio { namespace chain {
|
||||
});
|
||||
}
|
||||
|
||||
bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) const {
|
||||
wasm_cache_index::iterator it = wasm_instantiation_cache.find( boost::make_tuple(code_hash, vm_type, vm_version) );
|
||||
return it != wasm_instantiation_cache.end();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> parse_initial_memory(const Module& module) {
|
||||
std::vector<uint8_t> mem_image;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
|
||||
@@ -34,16 +34,11 @@ class eosvmoc_runtime : public eosio::chain::wasm_runtime_interface {
|
||||
const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) override;
|
||||
|
||||
void immediately_exit_currently_running_module() override;
|
||||
void init_thread_local_data() override;
|
||||
|
||||
friend eosvmoc_instantiated_module;
|
||||
eosvmoc::code_cache_sync cc;
|
||||
eosvmoc::executor exec;
|
||||
eosvmoc::memory mem;
|
||||
|
||||
// Defined in eos-vm-oc.cpp. Used for non-main thread in multi-threaded execution
|
||||
thread_local static std::unique_ptr<eosvmoc::executor> exec_thread_local;
|
||||
thread_local static eosvmoc::memory mem_thread_local;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -354,13 +349,7 @@ auto fn(A... a) {
|
||||
: "cc");
|
||||
}
|
||||
using native_args = vm::flatten_parameters_t<AUTO_PARAM_WORKAROUND(F)>;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-value"
|
||||
// If a is unpopulated, this reports "statement has no effect [-Werror=unused-value]"
|
||||
eosio::vm::native_value stack[] = { a... };
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
constexpr int cb_ctx_ptr_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(ctx);
|
||||
apply_context* ctx;
|
||||
asm("mov %%gs:%c[applyContextOffset], %[cPtr]\n"
|
||||
@@ -396,7 +385,7 @@ void register_eosvm_oc(Name n) {
|
||||
if(n == BOOST_HANA_STRING("env.eosio_exit")) return;
|
||||
constexpr auto fn = create_function<F, Preconditions, injected>();
|
||||
constexpr auto index = find_intrinsic_index(n.c_str());
|
||||
[[maybe_unused]] intrinsic the_intrinsic(
|
||||
intrinsic the_intrinsic(
|
||||
n.c_str(),
|
||||
wasm_function_type_provider<std::remove_pointer_t<decltype(fn)>>::type(),
|
||||
reinterpret_cast<void*>(fn),
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
|
||||
#include <thread>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace std {
|
||||
template<> struct hash<eosio::chain::eosvmoc::code_tuple> {
|
||||
@@ -85,9 +84,6 @@ class code_cache_base {
|
||||
|
||||
template <typename T>
|
||||
void serialize_cache_index(fc::datastream<T>& ds);
|
||||
|
||||
std::thread::id _main_thread_id;
|
||||
bool is_main_thread() const;
|
||||
};
|
||||
|
||||
class code_cache_async : public code_cache_base {
|
||||
@@ -118,4 +114,4 @@ class code_cache_sync : public code_cache_base {
|
||||
const code_descriptor* const get_descriptor_for_code_sync(const digest_type& code_id, const uint8_t& vm_version);
|
||||
};
|
||||
|
||||
}}}
|
||||
}}}
|
||||
@@ -27,9 +27,6 @@ class wasm_runtime_interface {
|
||||
virtual void immediately_exit_currently_running_module() = 0;
|
||||
|
||||
virtual ~wasm_runtime_interface();
|
||||
|
||||
// eosvmoc_runtime needs this
|
||||
virtual void init_thread_local_data() {};
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
Regular → Executable
Regular → Executable
@@ -4,7 +4,6 @@
|
||||
#include <eosio/chain/deep_mind.hpp>
|
||||
|
||||
#include <fc/scoped_exit.hpp>
|
||||
#include <fc/io/json.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
@@ -569,7 +568,7 @@ Enables new `get_block_num` intrinsic which returns the current block number.
|
||||
|
||||
protocol_feature_manager::protocol_feature_manager(
|
||||
protocol_feature_set&& pfs,
|
||||
std::function<deep_mind_handler*(bool is_trx_transient)> get_deep_mind_logger
|
||||
std::function<deep_mind_handler*()> get_deep_mind_logger
|
||||
):_protocol_feature_set( std::move(pfs) ), _get_deep_mind_logger(get_deep_mind_logger)
|
||||
{
|
||||
_builtin_protocol_features.resize( _protocol_feature_set._recognized_builtin_protocol_features.size() );
|
||||
@@ -750,8 +749,7 @@ Enables new `get_block_num` intrinsic which returns the current block number.
|
||||
("digest", feature_digest)
|
||||
);
|
||||
|
||||
// activate_feature is called by init. no transaction specific logging is possible
|
||||
if (auto dm_logger = _get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_activate_feature(*itr);
|
||||
}
|
||||
|
||||
@@ -780,202 +778,4 @@ Enables new `get_block_num` intrinsic which returns the current block number.
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<builtin_protocol_feature> read_builtin_protocol_feature( const fc::path& p ) {
|
||||
try {
|
||||
return fc::json::from_file<builtin_protocol_feature>( p );
|
||||
} catch( const fc::exception& e ) {
|
||||
wlog( "problem encountered while reading '${path}':\n${details}",
|
||||
("path", p.generic_string())("details",e.to_detail_string()) );
|
||||
} catch( ... ) {
|
||||
dlog( "unknown problem encountered while reading '${path}'",
|
||||
("path", p.generic_string()) );
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
protocol_feature_set initialize_protocol_features( const fc::path& p, bool populate_missing_builtins ) {
|
||||
using boost::filesystem::directory_iterator;
|
||||
|
||||
protocol_feature_set pfs;
|
||||
|
||||
bool directory_exists = true;
|
||||
|
||||
if( fc::exists( p ) ) {
|
||||
EOS_ASSERT( fc::is_directory( p ), plugin_exception,
|
||||
"Path to protocol-features is not a directory: ${path}",
|
||||
("path", p.generic_string())
|
||||
);
|
||||
} else {
|
||||
if( populate_missing_builtins )
|
||||
boost::filesystem::create_directories( p );
|
||||
else
|
||||
directory_exists = false;
|
||||
}
|
||||
|
||||
auto log_recognized_protocol_feature = []( const builtin_protocol_feature& f, const digest_type& feature_digest ) {
|
||||
if( f.subjective_restrictions.enabled ) {
|
||||
if( f.subjective_restrictions.preactivation_required ) {
|
||||
if( f.subjective_restrictions.earliest_allowed_activation_time == time_point{} ) {
|
||||
ilog( "Support for builtin protocol feature '${codename}' (with digest of '${digest}') is enabled with preactivation required",
|
||||
("codename", builtin_protocol_feature_codename(f.get_codename()))
|
||||
("digest", feature_digest)
|
||||
);
|
||||
} else {
|
||||
ilog( "Support for builtin protocol feature '${codename}' (with digest of '${digest}') is enabled with preactivation required and with an earliest allowed activation time of ${earliest_time}",
|
||||
("codename", builtin_protocol_feature_codename(f.get_codename()))
|
||||
("digest", feature_digest)
|
||||
("earliest_time", f.subjective_restrictions.earliest_allowed_activation_time)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if( f.subjective_restrictions.earliest_allowed_activation_time == time_point{} ) {
|
||||
ilog( "Support for builtin protocol feature '${codename}' (with digest of '${digest}') is enabled without activation restrictions",
|
||||
("codename", builtin_protocol_feature_codename(f.get_codename()))
|
||||
("digest", feature_digest)
|
||||
);
|
||||
} else {
|
||||
ilog( "Support for builtin protocol feature '${codename}' (with digest of '${digest}') is enabled without preactivation required but with an earliest allowed activation time of ${earliest_time}",
|
||||
("codename", builtin_protocol_feature_codename(f.get_codename()))
|
||||
("digest", feature_digest)
|
||||
("earliest_time", f.subjective_restrictions.earliest_allowed_activation_time)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ilog( "Recognized builtin protocol feature '${codename}' (with digest of '${digest}') but support for it is not enabled",
|
||||
("codename", builtin_protocol_feature_codename(f.get_codename()))
|
||||
("digest", feature_digest)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
map<builtin_protocol_feature_t, fc::path> found_builtin_protocol_features;
|
||||
map<digest_type, std::pair<builtin_protocol_feature, bool> > builtin_protocol_features_to_add;
|
||||
// The bool in the pair is set to true if the builtin protocol feature has already been visited to add
|
||||
map< builtin_protocol_feature_t, std::optional<digest_type> > visited_builtins;
|
||||
|
||||
// Read all builtin protocol features
|
||||
if( directory_exists ) {
|
||||
for( directory_iterator enditr, itr{p}; itr != enditr; ++itr ) {
|
||||
auto file_path = itr->path();
|
||||
if( !fc::is_regular_file( file_path ) || file_path.extension().generic_string().compare( ".json" ) != 0 )
|
||||
continue;
|
||||
|
||||
auto f = read_builtin_protocol_feature( file_path );
|
||||
|
||||
if( !f ) continue;
|
||||
|
||||
auto res = found_builtin_protocol_features.emplace( f->get_codename(), file_path );
|
||||
|
||||
EOS_ASSERT( res.second, plugin_exception,
|
||||
"Builtin protocol feature '${codename}' was already included from a previous_file",
|
||||
("codename", builtin_protocol_feature_codename(f->get_codename()))
|
||||
("current_file", file_path.generic_string())
|
||||
("previous_file", res.first->second.generic_string())
|
||||
);
|
||||
|
||||
const auto feature_digest = f->digest();
|
||||
|
||||
builtin_protocol_features_to_add.emplace( std::piecewise_construct,
|
||||
std::forward_as_tuple( feature_digest ),
|
||||
std::forward_as_tuple( *f, false ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Add builtin protocol features to the protocol feature manager in the right order (to satisfy dependencies)
|
||||
using itr_type = map<digest_type, std::pair<builtin_protocol_feature, bool>>::iterator;
|
||||
std::function<void(const itr_type&)> add_protocol_feature =
|
||||
[&pfs, &builtin_protocol_features_to_add, &visited_builtins, &log_recognized_protocol_feature, &add_protocol_feature]( const itr_type& itr ) -> void {
|
||||
if( itr->second.second ) {
|
||||
return;
|
||||
} else {
|
||||
itr->second.second = true;
|
||||
visited_builtins.emplace( itr->second.first.get_codename(), itr->first );
|
||||
}
|
||||
|
||||
for( const auto& d : itr->second.first.dependencies ) {
|
||||
auto itr2 = builtin_protocol_features_to_add.find( d );
|
||||
if( itr2 != builtin_protocol_features_to_add.end() ) {
|
||||
add_protocol_feature( itr2 );
|
||||
}
|
||||
}
|
||||
|
||||
pfs.add_feature( itr->second.first );
|
||||
|
||||
log_recognized_protocol_feature( itr->second.first, itr->first );
|
||||
};
|
||||
|
||||
for( auto itr = builtin_protocol_features_to_add.begin(); itr != builtin_protocol_features_to_add.end(); ++itr ) {
|
||||
add_protocol_feature( itr );
|
||||
}
|
||||
|
||||
auto output_protocol_feature = [&p]( const builtin_protocol_feature& f, const digest_type& feature_digest ) {
|
||||
string filename( "BUILTIN-" );
|
||||
filename += builtin_protocol_feature_codename( f.get_codename() );
|
||||
filename += ".json";
|
||||
|
||||
auto file_path = p / filename;
|
||||
|
||||
EOS_ASSERT( !fc::exists( file_path ), plugin_exception,
|
||||
"Could not save builtin protocol feature with codename '${codename}' because a file at the following path already exists: ${path}",
|
||||
("codename", builtin_protocol_feature_codename( f.get_codename() ))
|
||||
("path", file_path.generic_string())
|
||||
);
|
||||
|
||||
if( fc::json::save_to_file( f, file_path ) ) {
|
||||
ilog( "Saved default specification for builtin protocol feature '${codename}' (with digest of '${digest}') to: ${path}",
|
||||
("codename", builtin_protocol_feature_codename(f.get_codename()))
|
||||
("digest", feature_digest)
|
||||
("path", file_path.generic_string())
|
||||
);
|
||||
} else {
|
||||
elog( "Error occurred while writing default specification for builtin protocol feature '${codename}' (with digest of '${digest}') to: ${path}",
|
||||
("codename", builtin_protocol_feature_codename(f.get_codename()))
|
||||
("digest", feature_digest)
|
||||
("path", file_path.generic_string())
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
std::function<digest_type(builtin_protocol_feature_t)> add_missing_builtins =
|
||||
[&pfs, &visited_builtins, &output_protocol_feature, &log_recognized_protocol_feature, &add_missing_builtins, populate_missing_builtins]
|
||||
( builtin_protocol_feature_t codename ) -> digest_type {
|
||||
auto res = visited_builtins.emplace( codename, std::optional<digest_type>() );
|
||||
if( !res.second ) {
|
||||
EOS_ASSERT( res.first->second, protocol_feature_exception,
|
||||
"invariant failure: cycle found in builtin protocol feature dependencies"
|
||||
);
|
||||
return *res.first->second;
|
||||
}
|
||||
|
||||
auto f = protocol_feature_set::make_default_builtin_protocol_feature( codename,
|
||||
[&add_missing_builtins]( builtin_protocol_feature_t d ) {
|
||||
return add_missing_builtins( d );
|
||||
} );
|
||||
|
||||
if( !populate_missing_builtins )
|
||||
f.subjective_restrictions.enabled = false;
|
||||
|
||||
const auto& pf = pfs.add_feature( f );
|
||||
res.first->second = pf.feature_digest;
|
||||
|
||||
log_recognized_protocol_feature( f, pf.feature_digest );
|
||||
|
||||
if( populate_missing_builtins )
|
||||
output_protocol_feature( f, pf.feature_digest );
|
||||
|
||||
return pf.feature_digest;
|
||||
};
|
||||
|
||||
for( const auto& p : builtin_protocol_feature_codenames ) {
|
||||
auto itr = found_builtin_protocol_features.find( p.first );
|
||||
if( itr != found_builtin_protocol_features.end() ) continue;
|
||||
|
||||
add_missing_builtins( p.first );
|
||||
}
|
||||
|
||||
return pfs;
|
||||
}
|
||||
|
||||
|
||||
} } // eosio::chain
|
||||
|
||||
@@ -65,8 +65,7 @@ void resource_limits_manager::initialize_database() {
|
||||
state.virtual_net_limit = config.net_limit_parameters.max;
|
||||
});
|
||||
|
||||
// At startup, no transaction specific logging is possible
|
||||
if (auto dm_logger = _get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_init_resource_limits(config, state);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +93,7 @@ void resource_limits_manager::read_from_snapshot( const snapshot_reader_ptr& sna
|
||||
});
|
||||
}
|
||||
|
||||
void resource_limits_manager::initialize_account(const account_name& account, bool is_trx_transient) {
|
||||
void resource_limits_manager::initialize_account(const account_name& account) {
|
||||
const auto& limits = _db.create<resource_limits_object>([&]( resource_limits_object& bl ) {
|
||||
bl.owner = account;
|
||||
});
|
||||
@@ -102,7 +101,7 @@ void resource_limits_manager::initialize_account(const account_name& account, bo
|
||||
const auto& usage = _db.create<resource_usage_object>([&]( resource_usage_object& bu ) {
|
||||
bu.owner = account;
|
||||
});
|
||||
if (auto dm_logger = _get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_newaccount_resource_limits(limits, usage);
|
||||
}
|
||||
}
|
||||
@@ -117,9 +116,7 @@ void resource_limits_manager::set_block_parameters(const elastic_limit_parameter
|
||||
c.cpu_limit_parameters = cpu_limit_parameters;
|
||||
c.net_limit_parameters = net_limit_parameters;
|
||||
|
||||
// set_block_parameters is called by controller::finalize_block,
|
||||
// where transaction specific logging is not possible
|
||||
if (auto dm_logger = _get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_update_resource_limits_config(c);
|
||||
}
|
||||
});
|
||||
@@ -136,7 +133,7 @@ void resource_limits_manager::update_account_usage(const flat_set<account_name>&
|
||||
}
|
||||
}
|
||||
|
||||
void resource_limits_manager::add_transaction_usage(const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t time_slot, bool is_trx_transient ) {
|
||||
void resource_limits_manager::add_transaction_usage(const flat_set<account_name>& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t time_slot ) {
|
||||
const auto& state = _db.get<resource_limits_state_object>();
|
||||
const auto& config = _db.get<resource_limits_config_object>();
|
||||
|
||||
@@ -152,7 +149,7 @@ void resource_limits_manager::add_transaction_usage(const flat_set<account_name>
|
||||
bu.net_usage.add( net_usage, time_slot, config.account_net_usage_average_window );
|
||||
bu.cpu_usage.add( cpu_usage, time_slot, config.account_cpu_usage_average_window );
|
||||
|
||||
if (auto dm_logger = _get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_update_account_usage(bu);
|
||||
}
|
||||
});
|
||||
@@ -169,9 +166,8 @@ void resource_limits_manager::add_transaction_usage(const flat_set<account_name>
|
||||
|
||||
EOS_ASSERT( cpu_used_in_window <= max_user_use_in_window,
|
||||
tx_cpu_usage_exceeded,
|
||||
"authorizing account '${n}' has insufficient objective cpu resources for this transaction,"
|
||||
" used in window ${cpu_used_in_window}us, allowed in window ${max_user_use_in_window}us",
|
||||
("n", a)
|
||||
"authorizing account '${n}' has insufficient cpu resources for this transaction",
|
||||
("n", name(a))
|
||||
("cpu_used_in_window",cpu_used_in_window)
|
||||
("max_user_use_in_window",max_user_use_in_window) );
|
||||
}
|
||||
@@ -189,9 +185,8 @@ void resource_limits_manager::add_transaction_usage(const flat_set<account_name>
|
||||
|
||||
EOS_ASSERT( net_used_in_window <= max_user_use_in_window,
|
||||
tx_net_usage_exceeded,
|
||||
"authorizing account '${n}' has insufficient net resources for this transaction,"
|
||||
" used in window ${net_used_in_window}, allowed in window ${max_user_use_in_window}",
|
||||
("n", a)
|
||||
"authorizing account '${n}' has insufficient net resources for this transaction",
|
||||
("n", name(a))
|
||||
("net_used_in_window",net_used_in_window)
|
||||
("max_user_use_in_window",max_user_use_in_window) );
|
||||
|
||||
@@ -208,7 +203,7 @@ void resource_limits_manager::add_transaction_usage(const flat_set<account_name>
|
||||
EOS_ASSERT( state.pending_net_usage <= config.net_limit_parameters.max, block_resource_exhausted, "Block has insufficient net resources" );
|
||||
}
|
||||
|
||||
void resource_limits_manager::add_pending_ram_usage( const account_name account, int64_t ram_delta, bool is_trx_transient ) {
|
||||
void resource_limits_manager::add_pending_ram_usage( const account_name account, int64_t ram_delta ) {
|
||||
if (ram_delta == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -223,7 +218,7 @@ void resource_limits_manager::add_pending_ram_usage( const account_name account,
|
||||
_db.modify( usage, [&]( auto& u ) {
|
||||
u.ram_usage += ram_delta;
|
||||
|
||||
if (auto dm_logger = _get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_ram_event(account, u.ram_usage, ram_delta);
|
||||
}
|
||||
});
|
||||
@@ -246,7 +241,7 @@ int64_t resource_limits_manager::get_account_ram_usage( const account_name& name
|
||||
}
|
||||
|
||||
|
||||
bool resource_limits_manager::set_account_limits( const account_name& account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight, bool is_trx_transient) {
|
||||
bool resource_limits_manager::set_account_limits( const account_name& account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight) {
|
||||
//const auto& usage = _db.get<resource_usage_object,by_owner>( account );
|
||||
/*
|
||||
* Since we need to delay these until the next resource limiting boundary, these are created in a "pending"
|
||||
@@ -292,7 +287,7 @@ bool resource_limits_manager::set_account_limits( const account_name& account, i
|
||||
pending_limits.net_weight = net_weight;
|
||||
pending_limits.cpu_weight = cpu_weight;
|
||||
|
||||
if (auto dm_logger = _get_deep_mind_logger(is_trx_transient)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_set_account_limits(pending_limits);
|
||||
}
|
||||
});
|
||||
@@ -359,9 +354,7 @@ void resource_limits_manager::process_account_limit_updates() {
|
||||
multi_index.remove(*itr);
|
||||
}
|
||||
|
||||
// process_account_limit_updates is called by controller::finalize_block,
|
||||
// where transaction specific logging is not possible
|
||||
if (auto dm_logger = _get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_update_resource_limits_state(state);
|
||||
}
|
||||
});
|
||||
@@ -381,9 +374,7 @@ void resource_limits_manager::process_block_usage(uint32_t block_num) {
|
||||
state.update_virtual_net_limit(config);
|
||||
state.pending_net_usage = 0;
|
||||
|
||||
// process_block_usage is called by controller::finalize_block,
|
||||
// where transaction specific logging is not possible
|
||||
if (auto dm_logger = _get_deep_mind_logger(false)) {
|
||||
if (auto dm_logger = _get_deep_mind_logger()) {
|
||||
dm_logger->on_update_resource_limits_state(state);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <eosio/chain/thread_utils.hpp>
|
||||
#include <fc/log/logger_config.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
named_thread_pool::named_thread_pool( std::string name_prefix, size_t num_threads, bool delay_start )
|
||||
: _name_prefix( std::move(name_prefix) )
|
||||
, _num_threads( num_threads )
|
||||
, _ioc( num_threads )
|
||||
{
|
||||
if( !delay_start ) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
named_thread_pool::~named_thread_pool() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void named_thread_pool::start() {
|
||||
FC_ASSERT( !_ioc_work, "Thread pool already started" );
|
||||
_ioc_work.emplace( boost::asio::make_work_guard( _ioc ) );
|
||||
_ioc.restart();
|
||||
for( size_t i = 0; i < _num_threads; ++i ) {
|
||||
_thread_pool.emplace_back( [&ioc = _ioc, &name_prefix = _name_prefix, i]() {
|
||||
std::string tn = name_prefix + "-" + std::to_string( i );
|
||||
fc::set_os_thread_name( tn );
|
||||
ioc.run();
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
void named_thread_pool::stop() {
|
||||
_ioc_work.reset();
|
||||
_ioc.stop();
|
||||
for( auto& t : _thread_pool ) {
|
||||
t.join();
|
||||
}
|
||||
_thread_pool.clear();
|
||||
}
|
||||
|
||||
|
||||
} } // eosio::chain
|
||||
@@ -62,19 +62,16 @@ fc::microseconds transaction::get_signature_keys( const vector<signature_type>&
|
||||
{ try {
|
||||
auto start = fc::time_point::now();
|
||||
recovered_pub_keys.clear();
|
||||
const digest_type digest = sig_digest(chain_id, cfd);
|
||||
|
||||
if ( !signatures.empty() ) {
|
||||
const digest_type digest = sig_digest(chain_id, cfd);
|
||||
|
||||
for(const signature_type& sig : signatures) {
|
||||
auto now = fc::time_point::now();
|
||||
EOS_ASSERT( now < deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long ${time}us",
|
||||
("time", now - start)("now", now)("deadline", deadline)("start", start) );
|
||||
auto[ itr, successful_insertion ] = recovered_pub_keys.emplace( sig, digest );
|
||||
EOS_ASSERT( allow_duplicate_keys || successful_insertion, tx_duplicate_sig,
|
||||
"transaction includes more than one signature signed using the same key associated with public key: ${key}",
|
||||
("key", *itr ) );
|
||||
}
|
||||
for(const signature_type& sig : signatures) {
|
||||
auto now = fc::time_point::now();
|
||||
EOS_ASSERT( now < deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long ${time}us",
|
||||
("time", now - start)("now", now)("deadline", deadline)("start", start) );
|
||||
auto[ itr, successful_insertion ] = recovered_pub_keys.emplace( sig, digest );
|
||||
EOS_ASSERT( allow_duplicate_keys || successful_insertion, tx_duplicate_sig,
|
||||
"transaction includes more than one signature signed using the same key associated with public key: ${key}",
|
||||
("key", *itr ) );
|
||||
}
|
||||
|
||||
return fc::time_point::now() - start;
|
||||
|
||||
@@ -46,28 +46,30 @@ namespace eosio { namespace chain {
|
||||
|
||||
transaction_context::transaction_context( controller& c,
|
||||
const packed_transaction& t,
|
||||
const transaction_id_type& trx_id,
|
||||
transaction_checktime_timer&& tmr,
|
||||
fc::time_point s,
|
||||
transaction_metadata::trx_type type)
|
||||
bool read_only)
|
||||
:control(c)
|
||||
,packed_trx(t)
|
||||
,id(trx_id)
|
||||
,undo_session()
|
||||
,trace(std::make_shared<transaction_trace>())
|
||||
,start(s)
|
||||
,transaction_timer(std::move(tmr))
|
||||
,trx_type(type)
|
||||
,is_read_only(read_only)
|
||||
,net_usage(trace->net_usage)
|
||||
,pseudo_start(s)
|
||||
{
|
||||
if (!c.skip_db_sessions() && !is_read_only()) {
|
||||
if (!c.skip_db_sessions()) {
|
||||
undo_session.emplace(c.mutable_db().start_undo_session(true));
|
||||
}
|
||||
trace->id = packed_trx.id();
|
||||
trace->id = id;
|
||||
trace->block_num = c.head_block_num() + 1;
|
||||
trace->block_time = c.pending_block_time();
|
||||
trace->producer_block_id = c.pending_producer_block_id();
|
||||
|
||||
if(auto dm_logger = c.get_deep_mind_logger(is_transient()))
|
||||
if(auto dm_logger = control.get_deep_mind_logger())
|
||||
{
|
||||
dm_logger->on_start_transaction();
|
||||
}
|
||||
@@ -75,14 +77,14 @@ namespace eosio { namespace chain {
|
||||
|
||||
transaction_context::~transaction_context()
|
||||
{
|
||||
if(auto dm_logger = control.get_deep_mind_logger(is_transient()))
|
||||
if(auto dm_logger = control.get_deep_mind_logger())
|
||||
{
|
||||
dm_logger->on_end_transaction();
|
||||
}
|
||||
}
|
||||
|
||||
void transaction_context::disallow_transaction_extensions( const char* error_msg )const {
|
||||
if( control.is_speculative_block() ) {
|
||||
if( control.is_producing_block() ) {
|
||||
EOS_THROW( subjective_block_production_exception, error_msg );
|
||||
} else {
|
||||
EOS_THROW( disallowed_transaction_extensions_bad_block_exception, error_msg );
|
||||
@@ -105,16 +107,15 @@ namespace eosio { namespace chain {
|
||||
_deadline = start + objective_duration_limit;
|
||||
|
||||
// Possibly lower net_limit to the maximum net usage a transaction is allowed to be billed
|
||||
if( cfg.max_transaction_net_usage <= net_limit && !is_read_only() ) {
|
||||
if( cfg.max_transaction_net_usage <= net_limit ) {
|
||||
net_limit = cfg.max_transaction_net_usage;
|
||||
net_limit_due_to_block = false;
|
||||
}
|
||||
|
||||
// Possibly lower objective_duration_limit to the maximum cpu usage a transaction is allowed to be billed
|
||||
if( cfg.max_transaction_cpu_usage <= objective_duration_limit.count() && !is_read_only() ) {
|
||||
if( cfg.max_transaction_cpu_usage <= objective_duration_limit.count() ) {
|
||||
objective_duration_limit = fc::microseconds(cfg.max_transaction_cpu_usage);
|
||||
billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
|
||||
tx_cpu_usage_reason = tx_cpu_usage_exceeded_reason::on_chain_consensus_max_transaction_cpu_usage;
|
||||
_deadline = start + objective_duration_limit;
|
||||
}
|
||||
|
||||
@@ -132,63 +133,56 @@ namespace eosio { namespace chain {
|
||||
if( trx_specified_cpu_usage_limit <= objective_duration_limit ) {
|
||||
objective_duration_limit = trx_specified_cpu_usage_limit;
|
||||
billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
|
||||
tx_cpu_usage_reason = tx_cpu_usage_exceeded_reason::user_specified_trx_max_cpu_usage_ms;
|
||||
_deadline = start + objective_duration_limit;
|
||||
}
|
||||
}
|
||||
|
||||
initial_objective_duration_limit = objective_duration_limit;
|
||||
int64_t account_net_limit = 0;
|
||||
int64_t account_cpu_limit = 0;
|
||||
|
||||
if ( !is_read_only() ) {
|
||||
if( explicit_billed_cpu_time )
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits<int64_t>::max(), false, subjective_cpu_bill_us); // Fail early if the amount to be billed is too high
|
||||
if( explicit_billed_cpu_time )
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits<int64_t>::max(), false, subjective_cpu_bill_us); // Fail early if the amount to be billed is too high
|
||||
|
||||
// Record accounts to be billed for network and CPU usage
|
||||
if( control.is_builtin_activated(builtin_protocol_feature_t::only_bill_first_authorizer) ) {
|
||||
bill_to_accounts.insert( trx.first_authorizer() );
|
||||
} else {
|
||||
for( const auto& act : trx.actions ) {
|
||||
for( const auto& auth : act.authorization ) {
|
||||
bill_to_accounts.insert( auth.actor );
|
||||
}
|
||||
// Record accounts to be billed for network and CPU usage
|
||||
if( control.is_builtin_activated(builtin_protocol_feature_t::only_bill_first_authorizer) ) {
|
||||
bill_to_accounts.insert( trx.first_authorizer() );
|
||||
} else {
|
||||
for( const auto& act : trx.actions ) {
|
||||
for( const auto& auth : act.authorization ) {
|
||||
bill_to_accounts.insert( auth.actor );
|
||||
}
|
||||
}
|
||||
validate_ram_usage.reserve( bill_to_accounts.size() );
|
||||
|
||||
// Update usage values of accounts to reflect new time
|
||||
rl.update_account_usage( bill_to_accounts, block_timestamp_type(control.pending_block_time()).slot );
|
||||
|
||||
// Calculate the highest network usage and CPU time that all of the billed accounts can afford to be billed
|
||||
bool greylisted_net = false, greylisted_cpu = false;
|
||||
std::tie( account_net_limit, account_cpu_limit, greylisted_net, greylisted_cpu) = max_bandwidth_billed_accounts_can_pay();
|
||||
net_limit_due_to_greylist |= greylisted_net;
|
||||
cpu_limit_due_to_greylist |= greylisted_cpu;
|
||||
}
|
||||
validate_ram_usage.reserve( bill_to_accounts.size() );
|
||||
|
||||
// Update usage values of accounts to reflect new time
|
||||
rl.update_account_usage( bill_to_accounts, block_timestamp_type(control.pending_block_time()).slot );
|
||||
|
||||
// Calculate the highest network usage and CPU time that all of the billed accounts can afford to be billed
|
||||
int64_t account_net_limit = 0;
|
||||
int64_t account_cpu_limit = 0;
|
||||
bool greylisted_net = false, greylisted_cpu = false;
|
||||
std::tie( account_net_limit, account_cpu_limit, greylisted_net, greylisted_cpu) = max_bandwidth_billed_accounts_can_pay();
|
||||
net_limit_due_to_greylist |= greylisted_net;
|
||||
cpu_limit_due_to_greylist |= greylisted_cpu;
|
||||
|
||||
eager_net_limit = net_limit;
|
||||
|
||||
if ( !is_read_only() ) {
|
||||
// Possibly lower eager_net_limit to what the billed accounts can pay plus some (objective) leeway
|
||||
auto new_eager_net_limit = std::min( eager_net_limit, static_cast<uint64_t>(account_net_limit + cfg.net_usage_leeway) );
|
||||
if( new_eager_net_limit < eager_net_limit ) {
|
||||
eager_net_limit = new_eager_net_limit;
|
||||
net_limit_due_to_block = false;
|
||||
}
|
||||
// Possibly lower eager_net_limit to what the billed accounts can pay plus some (objective) leeway
|
||||
auto new_eager_net_limit = std::min( eager_net_limit, static_cast<uint64_t>(account_net_limit + cfg.net_usage_leeway) );
|
||||
if( new_eager_net_limit < eager_net_limit ) {
|
||||
eager_net_limit = new_eager_net_limit;
|
||||
net_limit_due_to_block = false;
|
||||
}
|
||||
|
||||
// Possibly limit deadline if the duration accounts can be billed for (+ a subjective leeway) does not exceed current delta
|
||||
if( (fc::microseconds(account_cpu_limit) + leeway) <= (_deadline - start) ) {
|
||||
_deadline = start + fc::microseconds(account_cpu_limit) + leeway;
|
||||
billing_timer_exception_code = leeway_deadline_exception::code_value;
|
||||
}
|
||||
// Possibly limit deadline if the duration accounts can be billed for (+ a subjective leeway) does not exceed current delta
|
||||
if( (fc::microseconds(account_cpu_limit) + leeway) <= (_deadline - start) ) {
|
||||
_deadline = start + fc::microseconds(account_cpu_limit) + leeway;
|
||||
billing_timer_exception_code = leeway_deadline_exception::code_value;
|
||||
}
|
||||
|
||||
// Possibly limit deadline to subjective max_transaction_time
|
||||
if( max_transaction_time_subjective != fc::microseconds::maximum() && (start + max_transaction_time_subjective) <= _deadline ) {
|
||||
_deadline = start + max_transaction_time_subjective;
|
||||
tx_cpu_usage_reason = billed_cpu_time_us > 0 ?
|
||||
tx_cpu_usage_exceeded_reason::speculative_executed_adjusted_max_transaction_time : tx_cpu_usage_exceeded_reason::node_configured_max_transaction_time;
|
||||
billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
|
||||
}
|
||||
|
||||
@@ -198,24 +192,6 @@ namespace eosio { namespace chain {
|
||||
billing_timer_exception_code = deadline_exception::code_value;
|
||||
}
|
||||
|
||||
if ( !is_read_only() ) {
|
||||
if( !explicit_billed_cpu_time ) {
|
||||
int64_t validate_account_cpu_limit = account_cpu_limit - subjective_cpu_bill_us + leeway.count(); // Add leeway to allow powerup
|
||||
// Possibly limit deadline to account subjective cpu left
|
||||
if( subjective_cpu_bill_us > 0 && (start + fc::microseconds(validate_account_cpu_limit) < _deadline) ) {
|
||||
_deadline = start + fc::microseconds(validate_account_cpu_limit);
|
||||
billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
|
||||
tx_cpu_usage_reason = tx_cpu_usage_exceeded_reason::account_cpu_limit;
|
||||
}
|
||||
|
||||
// Fail early if amount of the previous speculative execution is within 10% of remaining account cpu available
|
||||
if( validate_account_cpu_limit > 0 )
|
||||
validate_account_cpu_limit -= EOS_PERCENT( validate_account_cpu_limit, 10 * config::percent_1 );
|
||||
if( validate_account_cpu_limit < 0 ) validate_account_cpu_limit = 0;
|
||||
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit, subjective_cpu_bill_us );
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit billed_cpu_time_us should be used, block_deadline will be maximum unless in test code
|
||||
if( explicit_billed_cpu_time ) {
|
||||
_deadline = block_deadline;
|
||||
@@ -224,6 +200,15 @@ namespace eosio { namespace chain {
|
||||
deadline_exception_code = billing_timer_exception_code;
|
||||
}
|
||||
|
||||
if( !explicit_billed_cpu_time ) {
|
||||
// Fail early if amount of the previous speculative execution is within 10% of remaining account cpu available
|
||||
int64_t validate_account_cpu_limit = account_cpu_limit - subjective_cpu_bill_us + leeway.count(); // Add leeway to allow powerup
|
||||
if( validate_account_cpu_limit > 0 )
|
||||
validate_account_cpu_limit -= EOS_PERCENT( validate_account_cpu_limit, 10 * config::percent_1 );
|
||||
if( validate_account_cpu_limit < 0 ) validate_account_cpu_limit = 0;
|
||||
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit, subjective_cpu_bill_us );
|
||||
}
|
||||
|
||||
eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes) so check_net_usage can be efficient
|
||||
|
||||
if( initial_net_usage > 0 )
|
||||
@@ -254,9 +239,6 @@ namespace eosio { namespace chain {
|
||||
uint64_t packed_trx_prunable_size )
|
||||
{
|
||||
const transaction& trx = packed_trx.get_transaction();
|
||||
if ( is_transient() ) {
|
||||
EOS_ASSERT( trx.delay_sec.value == 0, transaction_exception, "dry-run or read-only transaction cannot be delayed" );
|
||||
}
|
||||
if( trx.transaction_extensions.size() > 0 ) {
|
||||
disallow_transaction_extensions( "no transaction extensions supported yet for input transactions" );
|
||||
}
|
||||
@@ -286,17 +268,12 @@ namespace eosio { namespace chain {
|
||||
published = control.pending_block_time();
|
||||
is_input = true;
|
||||
if (!control.skip_trx_checks()) {
|
||||
if ( !is_read_only() ) {
|
||||
control.validate_expiration(trx);
|
||||
control.validate_tapos(trx);
|
||||
}
|
||||
validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_speculative_block() );
|
||||
}
|
||||
|
||||
init( initial_net_usage );
|
||||
if ( !is_read_only() ) {
|
||||
record_transaction( packed_trx.id(), trx.expiration );
|
||||
control.validate_expiration(trx);
|
||||
control.validate_tapos(trx);
|
||||
validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_producing_block() );
|
||||
}
|
||||
init( initial_net_usage);
|
||||
record_transaction( id, trx.expiration ); /// checks for dupes
|
||||
}
|
||||
|
||||
void transaction_context::init_for_deferred_trx( fc::time_point p )
|
||||
@@ -346,13 +323,6 @@ namespace eosio { namespace chain {
|
||||
void transaction_context::finalize() {
|
||||
EOS_ASSERT( is_initialized, transaction_exception, "must first initialize" );
|
||||
|
||||
// read-only transactions only need net_usage and elapsed in the trace
|
||||
if ( is_read_only() ) {
|
||||
net_usage = ((net_usage + 7)/8)*8; // Round up to nearest multiple of word size (8 bytes)
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
return;
|
||||
}
|
||||
|
||||
if( is_input ) {
|
||||
const transaction& trx = packed_trx.get_transaction();
|
||||
auto& am = control.get_mutable_authorization_manager();
|
||||
@@ -388,7 +358,6 @@ namespace eosio { namespace chain {
|
||||
// NOTE: objective_duration_limit may possibly not be objective anymore due to cpu greylisting, but it should still be no greater than the truly objective objective_duration_limit
|
||||
objective_duration_limit = fc::microseconds(account_cpu_limit);
|
||||
billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
|
||||
tx_cpu_usage_reason = tx_cpu_usage_exceeded_reason::account_cpu_limit;
|
||||
}
|
||||
|
||||
net_usage = ((net_usage + 7)/8)*8; // Round up to nearest multiple of word size (8 bytes)
|
||||
@@ -404,7 +373,7 @@ namespace eosio { namespace chain {
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true, subjective_cpu_bill_us );
|
||||
|
||||
rl.add_transaction_usage( bill_to_accounts, static_cast<uint64_t>(billed_cpu_time_us), net_usage,
|
||||
block_timestamp_type(control.pending_block_time()).slot, is_transient() ); // Should never fail
|
||||
block_timestamp_type(control.pending_block_time()).slot ); // Should never fail
|
||||
}
|
||||
|
||||
void transaction_context::squash() {
|
||||
@@ -435,27 +404,6 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
}
|
||||
|
||||
std::string transaction_context::get_tx_cpu_usage_exceeded_reason_msg(fc::microseconds& limit) const {
|
||||
switch( tx_cpu_usage_reason ) {
|
||||
case tx_cpu_usage_exceeded_reason::account_cpu_limit:
|
||||
limit = objective_duration_limit;
|
||||
return " reached account cpu limit ${limit}us";
|
||||
case tx_cpu_usage_exceeded_reason::on_chain_consensus_max_transaction_cpu_usage:
|
||||
limit = objective_duration_limit;
|
||||
return " reached on chain max_transaction_cpu_usage ${limit}us";
|
||||
case tx_cpu_usage_exceeded_reason::user_specified_trx_max_cpu_usage_ms:
|
||||
limit = objective_duration_limit;
|
||||
return " reached trx specified max_cpu_usage_ms ${limit}us";
|
||||
case tx_cpu_usage_exceeded_reason::node_configured_max_transaction_time:
|
||||
limit = max_transaction_time_subjective;
|
||||
return " reached node configured max-transaction-time ${limit}us";
|
||||
case tx_cpu_usage_exceeded_reason::speculative_executed_adjusted_max_transaction_time:
|
||||
limit = max_transaction_time_subjective;
|
||||
return " reached speculative executed adjusted trx max time ${limit}us";
|
||||
}
|
||||
return "unknown tx_cpu_usage_exceeded";
|
||||
}
|
||||
|
||||
void transaction_context::checktime()const {
|
||||
if(BOOST_LIKELY(transaction_timer.expired == false))
|
||||
return;
|
||||
@@ -473,15 +421,15 @@ namespace eosio { namespace chain {
|
||||
if (subjective_cpu_bill_us > 0) {
|
||||
assert_msg += " with a subjective cpu of (${subjective} us)";
|
||||
}
|
||||
fc::microseconds limit;
|
||||
assert_msg += get_tx_cpu_usage_exceeded_reason_msg(limit);
|
||||
if (cpu_limit_due_to_greylist) {
|
||||
assert_msg = "greylisted " + assert_msg;
|
||||
EOS_THROW( greylist_cpu_usage_exceeded, assert_msg,
|
||||
("billing_timer", now - pseudo_start)("subjective", subjective_cpu_bill_us)("limit", limit) );
|
||||
EOS_THROW( greylist_cpu_usage_exceeded,
|
||||
assert_msg,
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start)( "subjective", subjective_cpu_bill_us) );
|
||||
} else {
|
||||
EOS_THROW( tx_cpu_usage_exceeded, assert_msg,
|
||||
("billing_timer", now - pseudo_start)("subjective", subjective_cpu_bill_us)("limit", limit) );
|
||||
EOS_THROW( tx_cpu_usage_exceeded,
|
||||
assert_msg,
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start)("subjective", subjective_cpu_bill_us) );
|
||||
}
|
||||
} else if( deadline_exception_code == leeway_deadline_exception::code_value ) {
|
||||
EOS_THROW( leeway_deadline_exception,
|
||||
@@ -544,28 +492,28 @@ namespace eosio { namespace chain {
|
||||
("billed", billed_us)( "billable", objective_duration_limit.count() )
|
||||
);
|
||||
} else {
|
||||
auto graylisted = cpu_limit_due_to_greylist && cpu_limited_by_account;
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
auto account_limit = graylisted ? account_cpu_limit : (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
|
||||
if( billed_us > account_limit ) {
|
||||
fc::microseconds tx_limit;
|
||||
std::string assert_msg;
|
||||
assert_msg.reserve(1024);
|
||||
assert_msg += "billed CPU time (${billed} us) is greater than the maximum";
|
||||
auto assert_msg = [&](bool graylisted, bool subjective) {
|
||||
std::string assert_msg = "billed CPU time (${billed} us) is greater than the maximum";
|
||||
assert_msg += graylisted ? " greylisted" : "";
|
||||
assert_msg += " billable CPU time for the transaction (${billable} us)";
|
||||
assert_msg += subjective_billed_us > 0 ? " with a subjective cpu of (${subjective} us)" : "";
|
||||
assert_msg += get_tx_cpu_usage_exceeded_reason_msg( tx_limit );
|
||||
|
||||
if( graylisted ) {
|
||||
FC_THROW_EXCEPTION( greylist_cpu_usage_exceeded, std::move(assert_msg),
|
||||
("billed", billed_us)("billable", account_limit)("subjective", subjective_billed_us)("limit", tx_limit) );
|
||||
} else {
|
||||
FC_THROW_EXCEPTION( tx_cpu_usage_exceeded, std::move(assert_msg),
|
||||
("billed", billed_us)("billable", account_limit)("subjective", subjective_billed_us)("limit", tx_limit) );
|
||||
}
|
||||
}
|
||||
assert_msg += " billable CPU time for the transaction (${billable} us)";
|
||||
assert_msg += subjective ? " with a subjective cpu of (${subjective} us)" : "";
|
||||
return assert_msg;
|
||||
};
|
||||
auto graylisted = cpu_limit_due_to_greylist && cpu_limited_by_account;
|
||||
auto subjective = subjective_billed_us > 0;
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
auto limit = graylisted ? account_cpu_limit : (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
|
||||
if (graylisted)
|
||||
EOS_ASSERT( billed_us <= limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
else
|
||||
EOS_ASSERT( billed_us <= limit,
|
||||
tx_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -582,34 +530,35 @@ namespace eosio { namespace chain {
|
||||
("billed", prev_billed_us)( "billable", objective_duration_limit.count() )
|
||||
);
|
||||
} else {
|
||||
auto graylisted = cpu_limit_due_to_greylist && cpu_limited_by_account;
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
auto account_limit = graylisted ? account_cpu_limit : (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
|
||||
if( prev_billed_us >= account_limit ) {
|
||||
std::string assert_msg;
|
||||
assert_msg.reserve(1024);
|
||||
assert_msg += "estimated CPU time (${billed} us) is not less than the maximum";
|
||||
auto assert_msg = [&](bool graylisted, bool subjective) {
|
||||
std::string assert_msg = "estimated CPU time (${billed} us) is not less than the maximum";
|
||||
assert_msg += graylisted ? " greylisted" : "";
|
||||
assert_msg += " billable CPU time for the transaction (${billable} us)";
|
||||
assert_msg += subjective_billed_us > 0 ? " with a subjective cpu of (${subjective} us)" : "";
|
||||
assert_msg += " reached account cpu limit ${limit}us";
|
||||
|
||||
if( graylisted ) {
|
||||
FC_THROW_EXCEPTION( greylist_cpu_usage_exceeded, std::move(assert_msg),
|
||||
("billed", prev_billed_us)("billable", account_limit)("subjective", subjective_billed_us)("limit", account_limit) );
|
||||
} else {
|
||||
FC_THROW_EXCEPTION( tx_cpu_usage_exceeded, std::move(assert_msg),
|
||||
("billed", prev_billed_us)("billable", account_limit)("subjective", subjective_billed_us)("limit", account_limit) );
|
||||
}
|
||||
}
|
||||
assert_msg += " billable CPU time for the transaction (${billable} us)";
|
||||
assert_msg += subjective ? " with a subjective cpu of (${subjective} us)" : "";
|
||||
return assert_msg;
|
||||
};
|
||||
auto graylisted = cpu_limit_due_to_greylist && cpu_limited_by_account;
|
||||
auto subjective = subjective_billed_us > 0;
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
auto limit = graylisted ? account_cpu_limit : (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
|
||||
if (graylisted)
|
||||
EOS_ASSERT( prev_billed_us < limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", prev_billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
else
|
||||
EOS_ASSERT( prev_billed_us < limit,
|
||||
tx_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", prev_billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transaction_context::add_ram_usage( account_name account, int64_t ram_delta ) {
|
||||
auto& rl = control.get_mutable_resource_limits_manager();
|
||||
rl.add_pending_ram_usage( account, ram_delta, is_transient() );
|
||||
rl.add_pending_ram_usage( account, ram_delta );
|
||||
if( ram_delta > 0 ) {
|
||||
validate_ram_usage.insert( account );
|
||||
}
|
||||
@@ -638,7 +587,7 @@ namespace eosio { namespace chain {
|
||||
uint32_t specified_greylist_limit = control.get_greylist_limit();
|
||||
for( const auto& a : bill_to_accounts ) {
|
||||
uint32_t greylist_limit = config::maximum_elastic_resource_multiplier;
|
||||
if( !force_elastic_limits && control.is_speculative_block() ) {
|
||||
if( !force_elastic_limits && control.is_producing_block() ) {
|
||||
if( control.is_resource_greylisted(a) ) {
|
||||
greylist_limit = 1;
|
||||
} else {
|
||||
@@ -657,7 +606,7 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
}
|
||||
|
||||
EOS_ASSERT( (!force_elastic_limits && control.is_speculative_block()) || (!greylisted_cpu && !greylisted_net),
|
||||
EOS_ASSERT( (!force_elastic_limits && control.is_producing_block()) || (!greylisted_cpu && !greylisted_net),
|
||||
transaction_exception, "greylisted when not producing block" );
|
||||
|
||||
return std::make_tuple(account_net_limit, account_cpu_limit, greylisted_net, greylisted_cpu);
|
||||
@@ -730,7 +679,7 @@ namespace eosio { namespace chain {
|
||||
apply_context acontext( control, *this, action_ordinal, recurse_depth );
|
||||
|
||||
if (recurse_depth == 0) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger(is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
dm_logger->on_input_action();
|
||||
}
|
||||
}
|
||||
@@ -753,7 +702,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
uint32_t trx_size = 0;
|
||||
const auto& cgto = control.mutable_db().create<generated_transaction_object>( [&]( auto& gto ) {
|
||||
gto.trx_id = packed_trx.id();
|
||||
gto.trx_id = id;
|
||||
gto.payer = first_auth;
|
||||
gto.sender = account_name(); /// delayed transactions have no sender
|
||||
gto.sender_id = transaction_id_to_sender_id( gto.trx_id );
|
||||
@@ -762,7 +711,7 @@ namespace eosio { namespace chain {
|
||||
gto.expiration = gto.delay_until + fc::seconds(control.get_global_properties().configuration.deferred_trx_expiration_window);
|
||||
trx_size = gto.set( trx );
|
||||
|
||||
if (auto dm_logger = control.get_deep_mind_logger(is_transient())) {
|
||||
if (auto dm_logger = control.get_deep_mind_logger()) {
|
||||
std::string event_id = RAM_EVENT_ID("${id}", ("id", gto.id));
|
||||
|
||||
dm_logger->on_create_deferred(deep_mind_handler::operation_qualifier::push, gto, packed_trx);
|
||||
@@ -810,10 +759,6 @@ namespace eosio { namespace chain {
|
||||
auto* code = db.find<account_object, by_name>(a.account);
|
||||
EOS_ASSERT( code != nullptr, transaction_exception,
|
||||
"action's code account '${account}' does not exist", ("account", a.account) );
|
||||
if ( is_read_only() ) {
|
||||
EOS_ASSERT( a.authorization.size() == 0, transaction_exception,
|
||||
"read-only action '${name}' cannot have authorizations", ("name", a.name) );
|
||||
}
|
||||
for( const auto& auth : a.authorization ) {
|
||||
one_auth = true;
|
||||
auto* actor = db.find<account_object, by_name>(auth.actor);
|
||||
@@ -826,7 +771,7 @@ namespace eosio { namespace chain {
|
||||
actors.insert( auth.actor );
|
||||
}
|
||||
}
|
||||
EOS_ASSERT( one_auth || is_transient(), tx_no_auths, "transaction must have at least one authorization" );
|
||||
EOS_ASSERT( one_auth || is_read_only, tx_no_auths, "transaction must have at least one authorization" );
|
||||
|
||||
if( enforce_actor_whitelist_blacklist ) {
|
||||
control.check_actor_list( actors );
|
||||
|
||||
@@ -11,14 +11,15 @@ recover_keys_future transaction_metadata::start_recover_keys( packed_transaction
|
||||
trx_type t,
|
||||
uint32_t max_variable_sig_size )
|
||||
{
|
||||
return post_async_task( thread_pool, [trx{std::move(trx)}, chain_id, time_limit, t, max_variable_sig_size]() mutable {
|
||||
return async_thread_pool( thread_pool, [trx{std::move(trx)}, chain_id, time_limit, t, max_variable_sig_size]() mutable {
|
||||
fc::time_point deadline = time_limit == fc::microseconds::maximum() ?
|
||||
fc::time_point::maximum() : fc::time_point::now() + time_limit;
|
||||
check_variable_sig_size( trx, max_variable_sig_size );
|
||||
const signed_transaction& trn = trx->get_signed_transaction();
|
||||
flat_set<public_key_type> recovered_pub_keys;
|
||||
fc::microseconds cpu_usage = trn.get_signature_keys( chain_id, deadline, recovered_pub_keys );
|
||||
return std::make_shared<transaction_metadata>( private_type(), std::move( trx ), cpu_usage, std::move( recovered_pub_keys ), t );
|
||||
return std::make_shared<transaction_metadata>( private_type(), std::move( trx ), cpu_usage, std::move( recovered_pub_keys ),
|
||||
t==trx_type::implicit, t==trx_type::scheduled, t==trx_type::read_only);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <softfloat.hpp>
|
||||
#include <compiler_builtins.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
|
||||
@@ -33,19 +34,10 @@
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
wasm_interface::wasm_interface(vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile)
|
||||
: my( new wasm_interface_impl(vm, eosvmoc_tierup, d, data_dir, eosvmoc_config, profile) ), vm( vm ) {}
|
||||
: my( new wasm_interface_impl(vm, eosvmoc_tierup, d, data_dir, eosvmoc_config, profile) ) {}
|
||||
|
||||
wasm_interface::~wasm_interface() {}
|
||||
|
||||
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|
||||
void wasm_interface::init_thread_local_data() {
|
||||
if (my->eosvmoc)
|
||||
my->eosvmoc->init_thread_local_data();
|
||||
else if (vm == wasm_interface::vm_type::eos_vm_oc && my->runtime_interface)
|
||||
my->runtime_interface->init_thread_local_data();
|
||||
}
|
||||
#endif
|
||||
|
||||
void wasm_interface::validate(const controller& control, const bytes& code) {
|
||||
const auto& pso = control.db().get<protocol_state_object>();
|
||||
|
||||
@@ -104,7 +96,7 @@ namespace eosio { namespace chain {
|
||||
once_is_enough = true;
|
||||
}
|
||||
if(cd) {
|
||||
my->eosvmoc->exec->execute(*cd, my->eosvmoc->mem, context);
|
||||
my->eosvmoc->exec.execute(*cd, my->eosvmoc->mem, context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -116,18 +108,9 @@ namespace eosio { namespace chain {
|
||||
my->runtime_interface->immediately_exit_currently_running_module();
|
||||
}
|
||||
|
||||
bool wasm_interface::is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) const {
|
||||
return my->is_code_cached(code_hash, vm_type, vm_version);
|
||||
}
|
||||
|
||||
wasm_instantiated_module_interface::~wasm_instantiated_module_interface() {}
|
||||
wasm_runtime_interface::~wasm_runtime_interface() {}
|
||||
|
||||
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|
||||
thread_local std::unique_ptr<eosvmoc::executor> wasm_interface_impl::eosvmoc_tier::exec {};
|
||||
thread_local eosvmoc::memory wasm_interface_impl::eosvmoc_tier::mem{ wasm_constraints::maximum_linear_memory/wasm_constraints::wasm_page_size };
|
||||
#endif
|
||||
|
||||
std::istream& operator>>(std::istream& in, wasm_interface::vm_type& runtime) {
|
||||
std::string s;
|
||||
in >> s;
|
||||
|
||||
@@ -24,10 +24,9 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
void interface::set_action_return_value( span<const char> packed_blob ) {
|
||||
auto max_action_return_value_size =
|
||||
context.control.get_global_properties().configuration.max_action_return_value_size;
|
||||
if( !context.trx_context.is_read_only() )
|
||||
EOS_ASSERT(packed_blob.size() <= max_action_return_value_size,
|
||||
action_return_value_exception,
|
||||
"action return value size must be less or equal to ${s} bytes", ("s", max_action_return_value_size));
|
||||
EOS_ASSERT(packed_blob.size() <= max_action_return_value_size,
|
||||
action_return_value_exception,
|
||||
"action return value size must be less or equal to ${s} bytes", ("s", max_action_return_value_size));
|
||||
context.action_return_value.assign( packed_blob.data(), packed_blob.data() + packed_blob.size() );
|
||||
}
|
||||
}}} // ns eosio::chain::webassembly
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
#include <eosio/chain/protocol_state_object.hpp>
|
||||
#include <eosio/chain/transaction_context.hpp>
|
||||
#include <eosio/chain/apply_context.hpp>
|
||||
#include <fc/crypto/alt_bn128.hpp>
|
||||
#include <fc/crypto/modular_arithmetic.hpp>
|
||||
#include <fc/crypto/blake2.hpp>
|
||||
#include <fc/crypto/sha3.hpp>
|
||||
#include <fc/crypto/k1_recover.hpp>
|
||||
#include <bn256/bn256.h>
|
||||
|
||||
namespace {
|
||||
uint32_t ceil_log2(uint32_t n)
|
||||
@@ -36,7 +36,7 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
EOS_ASSERT(p.which() < context.db.get<protocol_state_object>().num_supported_key_types, unactivated_key_type,
|
||||
"Unactivated key type used when creating assert_recover_key");
|
||||
|
||||
if(context.control.is_speculative_block())
|
||||
if(context.control.is_producing_block())
|
||||
EOS_ASSERT(s.variable_size() <= context.control.configured_subjective_signature_length_limit(),
|
||||
sig_variable_size_limit_exception, "signature variable length component size greater than subjective maximum");
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
EOS_ASSERT(s.which() < context.db.get<protocol_state_object>().num_supported_key_types, unactivated_signature_type,
|
||||
"Unactivated signature type used during recover_key");
|
||||
|
||||
if(context.control.is_speculative_block())
|
||||
if(context.control.is_producing_block())
|
||||
EOS_ASSERT(s.variable_size() <= context.control.configured_subjective_signature_length_limit(),
|
||||
sig_variable_size_limit_exception, "signature variable length component size greater than subjective maximum");
|
||||
|
||||
@@ -117,37 +117,62 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
}
|
||||
|
||||
int32_t interface::alt_bn128_add(span<const char> op1, span<const char> op2, span<char> result ) const {
|
||||
if (op1.size() != 64 || op2.size() != 64 || result.size() < 64 ||
|
||||
bn256::g1_add({(const uint8_t*)op1.data(), 64}, {(const uint8_t*)op2.data(), 64}, { (uint8_t*)result.data(), 64}) == -1)
|
||||
bytes bop1(op1.data(), op1.data() + op1.size());
|
||||
bytes bop2(op2.data(), op2.data() + op2.size());
|
||||
|
||||
auto maybe_err = fc::alt_bn128_add(bop1, bop2);
|
||||
if(std::holds_alternative<fc::alt_bn128_error>(maybe_err)) {
|
||||
return return_code::failure;
|
||||
}
|
||||
|
||||
const auto& res = std::get<bytes>(maybe_err);
|
||||
|
||||
if( result.size() < res.size() )
|
||||
return return_code::failure;
|
||||
|
||||
std::memcpy( result.data(), res.data(), res.size() );
|
||||
return return_code::success;
|
||||
}
|
||||
|
||||
int32_t interface::alt_bn128_mul(span<const char> g1_point, span<const char> scalar, span<char> result) const {
|
||||
if (g1_point.size() != 64 || scalar.size() != 32 || result.size() < 64 ||
|
||||
bn256::g1_scalar_mul({(const uint8_t*)g1_point.data(), 64}, {(const uint8_t*)scalar.data(), 32}, { (uint8_t*)result.data(), 64}) == -1)
|
||||
bytes bg1_point(g1_point.data(), g1_point.data() + g1_point.size());
|
||||
bytes bscalar(scalar.data(), scalar.data() + scalar.size());
|
||||
|
||||
auto maybe_err = fc::alt_bn128_mul(bg1_point, bscalar);
|
||||
if(std::holds_alternative<fc::alt_bn128_error>(maybe_err)) {
|
||||
return return_code::failure;
|
||||
}
|
||||
|
||||
const auto& res = std::get<bytes>(maybe_err);
|
||||
|
||||
if( result.size() < res.size() )
|
||||
return return_code::failure;
|
||||
|
||||
std::memcpy( result.data(), res.data(), res.size() );
|
||||
return return_code::success;
|
||||
}
|
||||
|
||||
int32_t interface::alt_bn128_pair(span<const char> g1_g2_pairs) const {
|
||||
bytes bg1_g2_pairs(g1_g2_pairs.data(), g1_g2_pairs.data() + g1_g2_pairs.size());
|
||||
|
||||
auto checktime = [this]() { context.trx_context.checktime(); };
|
||||
auto res = bn256::pairing_check({(const uint8_t*)g1_g2_pairs.data(), g1_g2_pairs.size()} , checktime);
|
||||
if (res == -1)
|
||||
auto res = fc::alt_bn128_pair(bg1_g2_pairs, checktime);
|
||||
if(std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
return return_code::failure;
|
||||
else
|
||||
return res? 0 : 1;
|
||||
}
|
||||
|
||||
return !std::get<bool>(res);
|
||||
}
|
||||
|
||||
int32_t interface::mod_exp(span<const char> base,
|
||||
span<const char> exp,
|
||||
span<const char> modulus,
|
||||
span<char> out) const {
|
||||
if (context.control.is_speculative_block()) {
|
||||
if (context.control.is_producing_block()) {
|
||||
unsigned int base_modulus_size = std::max(base.size(), modulus.size());
|
||||
|
||||
if (base_modulus_size < exp.size()) {
|
||||
EOS_THROW(subjective_block_production_exception,
|
||||
EOS_THROW(subjective_block_production_exception,
|
||||
"mod_exp restriction: exponent bit size cannot exceed bit size of either base or modulus");
|
||||
}
|
||||
|
||||
@@ -156,7 +181,7 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
uint64_t bit_calc = 5 * ceil_log2(exp.size()) + 8 * ceil_log2(base_modulus_size);
|
||||
|
||||
if (bit_calc_limit < bit_calc) {
|
||||
EOS_THROW(subjective_block_production_exception,
|
||||
EOS_THROW(subjective_block_production_exception,
|
||||
"mod_exp restriction: bit size too large for input arguments");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,16 +17,14 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
}
|
||||
|
||||
void interface::preactivate_feature( legacy_ptr<const digest_type> feature_digest ) {
|
||||
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "preactivate_feature not allowed in a readonly transaction");
|
||||
context.control.preactivate_feature( *feature_digest, context.trx_context.is_transient() );
|
||||
context.control.preactivate_feature( *feature_digest );
|
||||
}
|
||||
|
||||
void interface::set_resource_limits( account_name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ) {
|
||||
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_resource_limits not allowed in a readonly transaction");
|
||||
EOS_ASSERT(ram_bytes >= -1, wasm_execution_error, "invalid value for ram resource limit expected [-1,INT64_MAX]");
|
||||
EOS_ASSERT(net_weight >= -1, wasm_execution_error, "invalid value for net resource weight expected [-1,INT64_MAX]");
|
||||
EOS_ASSERT(cpu_weight >= -1, wasm_execution_error, "invalid value for cpu resource weight expected [-1,INT64_MAX]");
|
||||
if( context.control.get_mutable_resource_limits_manager().set_account_limits(account, ram_bytes, net_weight, cpu_weight, context.trx_context.is_transient()) ) {
|
||||
if( context.control.get_mutable_resource_limits_manager().set_account_limits(account, ram_bytes, net_weight, cpu_weight) ) {
|
||||
context.trx_context.validate_ram_usage.insert( account );
|
||||
}
|
||||
}
|
||||
@@ -101,7 +99,6 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
return s;
|
||||
}
|
||||
void interface::set_wasm_parameters_packed( span<const char> packed_parameters ) {
|
||||
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_wasm_parameters_packed not allowed in a readonly transaction");
|
||||
datastream<const char*> ds( packed_parameters.data(), packed_parameters.size() );
|
||||
uint32_t version;
|
||||
chain::wasm_config cfg;
|
||||
@@ -116,7 +113,6 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
);
|
||||
}
|
||||
int64_t interface::set_proposed_producers( legacy_span<const char> packed_producer_schedule) {
|
||||
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_proposed_producers not allowed in a readonly transaction");
|
||||
datastream<const char*> ds( packed_producer_schedule.data(), packed_producer_schedule.size() );
|
||||
std::vector<producer_authority> producers;
|
||||
std::vector<legacy::producer_key> old_version;
|
||||
@@ -133,7 +129,6 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
}
|
||||
|
||||
int64_t interface::set_proposed_producers_ex( uint64_t packed_producer_format, legacy_span<const char> packed_producer_schedule) {
|
||||
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_proposed_producers_ex not allowed in a readonly transaction");
|
||||
if (packed_producer_format == 0) {
|
||||
return set_proposed_producers(std::move(packed_producer_schedule));
|
||||
} else if (packed_producer_format == 1) {
|
||||
@@ -162,7 +157,6 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
}
|
||||
|
||||
void interface::set_blockchain_parameters_packed( legacy_span<const char> packed_blockchain_parameters ) {
|
||||
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_blockchain_parameters_packed not allowed in a readonly transaction");
|
||||
datastream<const char*> ds( packed_blockchain_parameters.data(), packed_blockchain_parameters.size() );
|
||||
chain::chain_config_v0 cfg;
|
||||
fc::raw::unpack(ds, cfg);
|
||||
@@ -194,7 +188,6 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
}
|
||||
|
||||
void interface::set_parameters_packed( span<const char> packed_parameters ){
|
||||
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_parameters_packed not allowed in a readonly transaction");
|
||||
datastream<const char*> ds( packed_parameters.data(), packed_parameters.size() );
|
||||
|
||||
chain::chain_config cfg = context.control.get_global_properties().configuration;
|
||||
@@ -214,7 +207,6 @@ namespace eosio { namespace chain { namespace webassembly {
|
||||
}
|
||||
|
||||
void interface::set_privileged( account_name n, bool is_priv ) {
|
||||
EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_privileged not allowed in a readonly transaction");
|
||||
const auto& a = context.db.get<account_metadata_object, by_name>( n );
|
||||
context.db.modify( a, [&]( auto& ma ){
|
||||
ma.set_privileged( is_priv );
|
||||
|
||||
@@ -15,8 +15,7 @@ class eosvmoc_instantiated_module : public wasm_instantiated_module_interface {
|
||||
eosvmoc_instantiated_module(const digest_type& code_hash, const uint8_t& vm_version, eosvmoc_runtime& wr) :
|
||||
_code_hash(code_hash),
|
||||
_vm_version(vm_version),
|
||||
_eosvmoc_runtime(wr),
|
||||
_main_thread_id(std::this_thread::get_id())
|
||||
_eosvmoc_runtime(wr)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -25,22 +24,16 @@ class eosvmoc_instantiated_module : public wasm_instantiated_module_interface {
|
||||
_eosvmoc_runtime.cc.free_code(_code_hash, _vm_version);
|
||||
}
|
||||
|
||||
bool is_main_thread() { return _main_thread_id == std::this_thread::get_id(); };
|
||||
|
||||
void apply(apply_context& context) override {
|
||||
const code_descriptor* const cd = _eosvmoc_runtime.cc.get_descriptor_for_code_sync(_code_hash, _vm_version);
|
||||
EOS_ASSERT(cd, wasm_execution_error, "EOS VM OC instantiation failed");
|
||||
|
||||
if ( is_main_thread() )
|
||||
_eosvmoc_runtime.exec.execute(*cd, _eosvmoc_runtime.mem, context);
|
||||
else
|
||||
_eosvmoc_runtime.exec_thread_local->execute(*cd, _eosvmoc_runtime.mem_thread_local, context);
|
||||
_eosvmoc_runtime.exec.execute(*cd, _eosvmoc_runtime.mem, context);
|
||||
}
|
||||
|
||||
const digest_type _code_hash;
|
||||
const uint8_t _vm_version;
|
||||
eosvmoc_runtime& _eosvmoc_runtime;
|
||||
std::thread::id _main_thread_id;
|
||||
};
|
||||
|
||||
eosvmoc_runtime::eosvmoc_runtime(const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db)
|
||||
@@ -52,17 +45,11 @@ eosvmoc_runtime::~eosvmoc_runtime() {
|
||||
|
||||
std::unique_ptr<wasm_instantiated_module_interface> eosvmoc_runtime::instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t> initial_memory,
|
||||
const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) {
|
||||
|
||||
return std::make_unique<eosvmoc_instantiated_module>(code_hash, vm_type, *this);
|
||||
}
|
||||
|
||||
//never called. EOS VM OC overrides eosio_exit to its own implementation
|
||||
void eosvmoc_runtime::immediately_exit_currently_running_module() {}
|
||||
|
||||
void eosvmoc_runtime::init_thread_local_data() {
|
||||
exec_thread_local = std::make_unique<eosvmoc::executor>(cc);
|
||||
}
|
||||
|
||||
thread_local std::unique_ptr<eosvmoc::executor> eosvmoc_runtime::exec_thread_local {};
|
||||
thread_local eosvmoc::memory eosvmoc_runtime::mem_thread_local{ wasm_constraints::maximum_linear_memory/wasm_constraints::wasm_page_size };
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -106,11 +106,9 @@ std::tuple<size_t, size_t> code_cache_async::consume_compile_thread_queue() {
|
||||
return {gotsome, bytes_remaining};
|
||||
}
|
||||
|
||||
|
||||
const code_descriptor* const code_cache_async::get_descriptor_for_code(const digest_type& code_id, const uint8_t& vm_version) {
|
||||
//if there are any outstanding compiles, process the result queue now
|
||||
//do this only on main thread (which is in single threaded write window)
|
||||
if(is_main_thread() && _outstanding_compiles_and_poison.size()) {
|
||||
if(_outstanding_compiles_and_poison.size()) {
|
||||
auto [count_processed, bytes_remaining] = consume_compile_thread_queue();
|
||||
|
||||
if(count_processed)
|
||||
@@ -136,12 +134,9 @@ const code_descriptor* const code_cache_async::get_descriptor_for_code(const dig
|
||||
//check for entry in cache
|
||||
code_cache_index::index<by_hash>::type::iterator it = _cache_index.get<by_hash>().find(boost::make_tuple(code_id, vm_version));
|
||||
if(it != _cache_index.get<by_hash>().end()) {
|
||||
if (is_main_thread())
|
||||
_cache_index.relocate(_cache_index.begin(), _cache_index.project<0>(it));
|
||||
_cache_index.relocate(_cache_index.begin(), _cache_index.project<0>(it));
|
||||
return &*it;
|
||||
}
|
||||
if(!is_main_thread()) // on read-only thread
|
||||
return nullptr;
|
||||
|
||||
const code_tuple ct = code_tuple{code_id, vm_version};
|
||||
|
||||
@@ -183,12 +178,9 @@ const code_descriptor* const code_cache_sync::get_descriptor_for_code_sync(const
|
||||
//check for entry in cache
|
||||
code_cache_index::index<by_hash>::type::iterator it = _cache_index.get<by_hash>().find(boost::make_tuple(code_id, vm_version));
|
||||
if(it != _cache_index.get<by_hash>().end()) {
|
||||
if (is_main_thread())
|
||||
_cache_index.relocate(_cache_index.begin(), _cache_index.project<0>(it));
|
||||
_cache_index.relocate(_cache_index.begin(), _cache_index.project<0>(it));
|
||||
return &*it;
|
||||
}
|
||||
if(!is_main_thread())
|
||||
return nullptr;
|
||||
|
||||
const code_object* const codeobject = _db.find<code_object,by_code_hash>(boost::make_tuple(code_id, 0, vm_version));
|
||||
if(!codeobject) //should be impossible right?
|
||||
@@ -212,8 +204,7 @@ const code_descriptor* const code_cache_sync::get_descriptor_for_code_sync(const
|
||||
|
||||
code_cache_base::code_cache_base(const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db) :
|
||||
_db(db),
|
||||
_cache_file_path(data_dir/"code_cache.bin"),
|
||||
_main_thread_id(std::this_thread::get_id())
|
||||
_cache_file_path(data_dir/"code_cache.bin")
|
||||
{
|
||||
static_assert(sizeof(allocator_t) <= header_offset, "header offset intersects with allocator");
|
||||
|
||||
@@ -391,7 +382,4 @@ void code_cache_base::check_eviction_threshold(size_t free_bytes) {
|
||||
run_eviction_round();
|
||||
}
|
||||
|
||||
bool code_cache_base::is_main_thread() const {
|
||||
return _main_thread_id == std::this_thread::get_id();
|
||||
}
|
||||
}}}
|
||||
|
||||
@@ -247,7 +247,7 @@ void launch_compile_monitor(int nodeos_fd) {
|
||||
sigaddset(&set, SIGQUIT);
|
||||
sigprocmask(SIG_BLOCK, &set, nullptr);
|
||||
|
||||
struct sigaction sa{};
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sa.sa_flags = SA_NOCLDWAIT;
|
||||
sigaction(SIGCHLD, &sa, nullptr);
|
||||
|
||||
@@ -89,7 +89,7 @@ bool write_message_with_fds(int fd_to_send_to, const eosvmoc_message& message, c
|
||||
.iov_len = sz
|
||||
};
|
||||
union {
|
||||
char buf[CMSG_SPACE(max_num_fds * sizeof(int))] = {};
|
||||
char buf[CMSG_SPACE(max_num_fds * sizeof(int))];
|
||||
struct cmsghdr align;
|
||||
} u;
|
||||
|
||||
@@ -108,7 +108,6 @@ bool write_message_with_fds(int fd_to_send_to, const eosvmoc_message& message, c
|
||||
memcpy(p, &thisfd, sizeof(thisfd));
|
||||
p += sizeof(thisfd);
|
||||
}
|
||||
msg.msg_controllen = cmsg->cmsg_len;
|
||||
}
|
||||
|
||||
int wrote;
|
||||
|
||||
@@ -247,7 +247,7 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_runtime<Impl>::instan
|
||||
wasm_code_ptr code((uint8_t*)code_bytes, code_size);
|
||||
apply_options options = { .max_pages = 65536,
|
||||
.max_call_depth = 0 };
|
||||
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options);
|
||||
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options, false); // uses 2-passes parsing
|
||||
eos_vm_host_functions_t::resolve(bkend->get_module());
|
||||
return std::make_unique<eos_vm_instantiated_module<Impl>>(this, std::move(bkend));
|
||||
} catch(eosio::vm::exception& e) {
|
||||
@@ -273,7 +273,7 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_profile_runtime::inst
|
||||
wasm_code_ptr code((uint8_t*)code_bytes, code_size);
|
||||
apply_options options = { .max_pages = 65536,
|
||||
.max_call_depth = 0 };
|
||||
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options);
|
||||
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options, false); // uses 2-passes parsing
|
||||
eos_vm_host_functions_t::resolve(bkend->get_module());
|
||||
return std::make_unique<eos_vm_profiling_module>(std::move(bkend), code_bytes, code_size);
|
||||
} catch(eosio::vm::exception& e) {
|
||||
|
||||
+1
-1
Submodule libraries/chainbase updated: 50540fa7bc...62d3f99059
@@ -1,7 +1,2 @@
|
||||
add_library(leap-cli11 INTERFACE)
|
||||
|
||||
set(CLI11_TESTING OFF)
|
||||
add_subdirectory(cli11)
|
||||
mark_as_advanced(CLI_CXX_STD CLI_EXAMPLES CLI_SINGLE_FILE CLI_SINGLE_FILE_TESTS CLI_TESTING)
|
||||
target_link_libraries(leap-cli11 INTERFACE CLI11::CLI11)
|
||||
|
||||
target_include_directories(leap-cli11 INTERFACE include)
|
||||
Submodule libraries/cli11/cli11 deleted from 90b0d6720d
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
add_library(custom_appbase INTERFACE)
|
||||
target_include_directories(custom_appbase INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_link_libraries(custom_appbase INTERFACE appbase)
|
||||
|
||||
add_subdirectory(tests)
|
||||
@@ -1,111 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <appbase/application_base.hpp>
|
||||
#include <appbase/execution_priority_queue.hpp>
|
||||
|
||||
/*
|
||||
* Custmomize appbase to support two-queue exector.
|
||||
*/
|
||||
namespace appbase {
|
||||
|
||||
enum class exec_window {
|
||||
read, // the window during which operations from read_only_trx_safe queue
|
||||
// can be executed in app thread in parallel with read-only transactions
|
||||
// in read-only transaction excuting threads.
|
||||
write, // the window during which operations from both general and
|
||||
// read_only_trx_safe queues can be executed in app thread,
|
||||
// while read-only transactions are not executed in read-only
|
||||
// transaction excuting threads.
|
||||
};
|
||||
|
||||
enum class exec_queue {
|
||||
read_only_trx_safe, // the queue storing operations which are safe to execute
|
||||
// on app thread in parallel with read-only transactions
|
||||
// in read-only transaction excuting threads.
|
||||
general // the queue storing operations which can be only executed
|
||||
// on the app thread while read-only transactions are
|
||||
// not being executed in read-only threads
|
||||
};
|
||||
|
||||
class two_queue_executor {
|
||||
public:
|
||||
|
||||
template <typename Func>
|
||||
auto post( int priority, exec_queue q, Func&& func ) {
|
||||
if ( q == exec_queue::general )
|
||||
return boost::asio::post(io_serv_, general_queue_.wrap(priority, --order_, std::forward<Func>(func)));
|
||||
else
|
||||
return boost::asio::post(io_serv_, read_only_trx_safe_queue_.wrap(priority, --order_, std::forward<Func>(func)));
|
||||
}
|
||||
|
||||
// Legacy and deprecated. To be removed after cleaning up its uses in base appbase
|
||||
template <typename Func>
|
||||
auto post( int priority, Func&& func ) {
|
||||
// safer to use general queue for unknown type of operation since operations
|
||||
// from general queue are not executed in parallel with read-only transactions
|
||||
return boost::asio::post(io_serv_, general_queue_.wrap(priority, --order_, std::forward<Func>(func)));
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service() { return io_serv_; }
|
||||
|
||||
bool execute_highest() {
|
||||
if ( exec_window_ == exec_window::write ) {
|
||||
if( !general_queue_.empty() && ( read_only_trx_safe_queue_.empty() || *read_only_trx_safe_queue_.top() < *general_queue_.top()) ) {
|
||||
// general_queue_'s top function's priority greater than read_only_trx_safe_queue_'s top function's, or general_queue_ empty
|
||||
general_queue_.execute_highest();
|
||||
} else if( !read_only_trx_safe_queue_.empty() ) {
|
||||
read_only_trx_safe_queue_.execute_highest();
|
||||
}
|
||||
return !read_only_trx_safe_queue_.empty() || !general_queue_.empty();
|
||||
} else {
|
||||
return read_only_trx_safe_queue_.execute_highest();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
boost::asio::executor_binder<Function, appbase::execution_priority_queue::executor>
|
||||
wrap(int priority, exec_queue q, Function&& func ) {
|
||||
if ( q == exec_queue::general )
|
||||
return general_queue_.wrap(priority, --order_, std::forward<Function>(func));
|
||||
else
|
||||
return read_only_trx_safe_queue_.wrap(priority, --order_, std::forward<Function>(func));
|
||||
}
|
||||
|
||||
void clear() {
|
||||
read_only_trx_safe_queue_.clear();
|
||||
general_queue_.clear();
|
||||
}
|
||||
|
||||
void set_to_read_window() {
|
||||
exec_window_ = exec_window::read;
|
||||
}
|
||||
|
||||
void set_to_write_window() {
|
||||
exec_window_ = exec_window::write;
|
||||
}
|
||||
|
||||
bool is_read_window() const {
|
||||
return exec_window_ == exec_window::read;
|
||||
}
|
||||
|
||||
bool is_write_window() const {
|
||||
return exec_window_ == exec_window::write;
|
||||
}
|
||||
|
||||
auto& read_only_trx_safe_queue() { return read_only_trx_safe_queue_; }
|
||||
|
||||
auto& general_queue() { return general_queue_; }
|
||||
|
||||
// members are ordered taking into account that the last one is destructed first
|
||||
private:
|
||||
boost::asio::io_service io_serv_;
|
||||
appbase::execution_priority_queue read_only_trx_safe_queue_;
|
||||
appbase::execution_priority_queue general_queue_;
|
||||
std::atomic<std::size_t> order_ { std::numeric_limits<size_t>::max() }; // to maintain FIFO ordering in both queues within priority
|
||||
exec_window exec_window_ { exec_window::write };
|
||||
};
|
||||
|
||||
using application = application_t<two_queue_executor>;
|
||||
}
|
||||
|
||||
#include <appbase/application_instance.hpp>
|
||||
@@ -1,13 +0,0 @@
|
||||
if(CMAKE_CXX_STANDARD EQUAL 98 OR CMAKE_CXX_STANDARD LESS 17)
|
||||
message(FATAL_ERROR "appbase requires c++17 or newer")
|
||||
elseif(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
file(GLOB UNIT_TESTS "*.cpp")
|
||||
add_executable( custom_appbase_test ${UNIT_TESTS} )
|
||||
target_link_libraries( custom_appbase_test appbase ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )
|
||||
target_include_directories( custom_appbase_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include" "${CMAKE_CURRENT_SOURCE_DIR}/../../appbase/include" )
|
||||
|
||||
add_test( custom_appbase_test custom_appbase_test )
|
||||
@@ -1,215 +0,0 @@
|
||||
#define BOOST_TEST_MODULE custom_appbase_tests
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
|
||||
#include <eosio/chain/application.hpp>
|
||||
|
||||
using namespace appbase;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(custom_appbase_tests)
|
||||
|
||||
std::thread start_app_thread(appbase::scoped_app& app) {
|
||||
const char* argv[] = { boost::unit_test::framework::current_test_case().p_name->c_str() };
|
||||
BOOST_CHECK(app->initialize(sizeof(argv) / sizeof(char*), const_cast<char**>(argv)));
|
||||
app->startup();
|
||||
std::thread app_thread( [&]() {
|
||||
app->exec();
|
||||
} );
|
||||
return app_thread;
|
||||
}
|
||||
|
||||
// verify functions from both queues are executed when execution window is not explictly set
|
||||
BOOST_AUTO_TEST_CASE( default_exec_window ) {
|
||||
appbase::scoped_app app;
|
||||
auto app_thread = start_app_thread(app);
|
||||
|
||||
// post functions
|
||||
std::map<int, int> rslts {};
|
||||
int seq_num = 0;
|
||||
app->executor().post( priority::medium, exec_queue::read_only_trx_safe, [&]() { rslts[0]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::medium, exec_queue::general, [&]() { rslts[1]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[2]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::read_only_trx_safe, [&]() { rslts[3]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::read_only_trx_safe, [&]() { rslts[4]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::general, [&]() { rslts[5]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::highest,exec_queue::read_only_trx_safe, [&]() { rslts[6]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[7]=seq_num; ++seq_num; } );
|
||||
|
||||
// Stop app. Use the lowest priority to make sure this function to execute the last
|
||||
app->executor().post( priority::lowest, exec_queue::read_only_trx_safe, [&]() {
|
||||
// read_only_trx_safe_queue should only contain the current lambda function,
|
||||
// and general_queue should have execute all its functions
|
||||
BOOST_REQUIRE_EQUAL( app->executor().read_only_trx_safe_queue().size(), 1);
|
||||
BOOST_REQUIRE_EQUAL( app->executor().general_queue().size(), 0 );
|
||||
app->quit();
|
||||
} );
|
||||
app_thread.join();
|
||||
|
||||
// both queues are cleared after execution
|
||||
BOOST_REQUIRE_EQUAL( app->executor().read_only_trx_safe_queue().empty(), true);
|
||||
BOOST_REQUIRE_EQUAL( app->executor().general_queue().empty(), true);
|
||||
|
||||
// exactly number of both queues' functions processed
|
||||
BOOST_REQUIRE_EQUAL( rslts.size(), 8 );
|
||||
|
||||
// same priority of functions executed by the post order
|
||||
BOOST_CHECK_LT( rslts[0], rslts[1] ); // medium
|
||||
BOOST_CHECK_LT( rslts[2], rslts[3] ); // high
|
||||
BOOST_CHECK_LT( rslts[3], rslts[7] ); // high
|
||||
BOOST_CHECK_LT( rslts[4], rslts[5] ); // low
|
||||
|
||||
// higher priority posted earlier executed earlier
|
||||
BOOST_CHECK_LT( rslts[3], rslts[4] );
|
||||
BOOST_CHECK_LT( rslts[6], rslts[7] );
|
||||
}
|
||||
|
||||
// verify functions only from read_only_trx_safe queue are processed during read window
|
||||
BOOST_AUTO_TEST_CASE( execute_from_read_queue ) {
|
||||
appbase::scoped_app app;
|
||||
auto app_thread = start_app_thread(app);
|
||||
|
||||
// set to run functions from read_only_trx_safe queue only
|
||||
app->executor().set_to_read_window();
|
||||
|
||||
// post functions
|
||||
std::map<int, int> rslts {};
|
||||
int seq_num = 0;
|
||||
app->executor().post( priority::medium, exec_queue::general, [&]() { rslts[0]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::read_only_trx_safe, [&]() { rslts[1]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[2]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::read_only_trx_safe, [&]() { rslts[3]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::read_only_trx_safe, [&]() { rslts[4]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::general, [&]() { rslts[5]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::highest,exec_queue::read_only_trx_safe, [&]() { rslts[6]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::highest,exec_queue::read_only_trx_safe, [&]() { rslts[7]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::read_only_trx_safe, [&]() { rslts[8]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[9]=seq_num; ++seq_num; } );
|
||||
|
||||
// stop application. Use lowest at the end to make sure this executes the last
|
||||
app->executor().post( priority::lowest, exec_queue::read_only_trx_safe, [&]() {
|
||||
// read_queue should have current function and write_queue should have all its functions
|
||||
BOOST_REQUIRE_EQUAL( app->executor().read_only_trx_safe_queue().size(), 1);
|
||||
BOOST_REQUIRE_EQUAL( app->executor().general_queue().size(), 4 );
|
||||
app->quit();
|
||||
} );
|
||||
app_thread.join();
|
||||
|
||||
// both queues are cleared after execution
|
||||
BOOST_REQUIRE_EQUAL( app->executor().read_only_trx_safe_queue().empty(), true);
|
||||
BOOST_REQUIRE_EQUAL( app->executor().general_queue().empty(), true);
|
||||
|
||||
// exactly number of posts processed
|
||||
BOOST_REQUIRE_EQUAL( rslts.size(), 6 );
|
||||
|
||||
// same priority (high) of functions in read_queue executed by the post order
|
||||
BOOST_CHECK_LT( rslts[1], rslts[3] );
|
||||
|
||||
// higher priority posted earlier in read_queue executed earlier
|
||||
BOOST_CHECK_LT( rslts[3], rslts[4] );
|
||||
}
|
||||
|
||||
// verify no functions are executed during read window if read_only_trx_safe queue is empty
|
||||
BOOST_AUTO_TEST_CASE( execute_from_empty_read_queue ) {
|
||||
appbase::scoped_app app;
|
||||
auto app_thread = start_app_thread(app);
|
||||
|
||||
// set to run functions from read_only_trx_safe queue only
|
||||
app->executor().set_to_read_window();
|
||||
|
||||
// post functions
|
||||
std::map<int, int> rslts {};
|
||||
int seq_num = 0;
|
||||
app->executor().post( priority::medium, exec_queue::general, [&]() { rslts[0]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[1]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[2]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[3]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::general, [&]() { rslts[4]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::general, [&]() { rslts[5]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::highest,exec_queue::general, [&]() { rslts[6]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::highest,exec_queue::general, [&]() { rslts[7]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[8]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[9]=seq_num; ++seq_num; } );
|
||||
|
||||
// Stop application. Use lowest at the end to make sure this executes the last
|
||||
app->executor().post( priority::lowest, exec_queue::read_only_trx_safe, [&]() {
|
||||
// read_queue should have current function and write_queue should have all its functions
|
||||
BOOST_REQUIRE_EQUAL( app->executor().read_only_trx_safe_queue().size(), 1);
|
||||
BOOST_REQUIRE_EQUAL( app->executor().general_queue().size(), 10 );
|
||||
app->quit();
|
||||
} );
|
||||
app_thread.join();
|
||||
|
||||
// both queues are cleared after execution
|
||||
BOOST_REQUIRE_EQUAL( app->executor().read_only_trx_safe_queue().empty(), true);
|
||||
BOOST_REQUIRE_EQUAL( app->executor().general_queue().empty(), true);
|
||||
|
||||
// no results
|
||||
BOOST_REQUIRE_EQUAL( rslts.size(), 0 );
|
||||
}
|
||||
|
||||
// verify functions from both queues are processed in write window
|
||||
BOOST_AUTO_TEST_CASE( execute_from_both_queues ) {
|
||||
appbase::scoped_app app;
|
||||
auto app_thread = start_app_thread(app);
|
||||
|
||||
// set to run functions from both queues
|
||||
app->executor().is_write_window();
|
||||
|
||||
// post functions
|
||||
std::map<int, int> rslts {};
|
||||
int seq_num = 0;
|
||||
app->executor().post( priority::medium, exec_queue::read_only_trx_safe, [&]() { rslts[0]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::medium, exec_queue::general, [&]() { rslts[1]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::high, exec_queue::general, [&]() { rslts[2]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::lowest, exec_queue::read_only_trx_safe, [&]() { rslts[3]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::read_only_trx_safe, [&]() { rslts[4]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::general, [&]() { rslts[5]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::highest,exec_queue::read_only_trx_safe, [&]() { rslts[6]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::general, [&]() { rslts[7]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::lowest, exec_queue::read_only_trx_safe, [&]() { rslts[8]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::lowest, exec_queue::read_only_trx_safe, [&]() { rslts[9]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::low, exec_queue::general, [&]() { rslts[10]=seq_num; ++seq_num; } );
|
||||
app->executor().post( priority::medium, exec_queue::general, [&]() { rslts[11]=seq_num; ++seq_num; } );
|
||||
|
||||
// stop application. Use lowest at the end to make sure this executes the last
|
||||
app->executor().post( priority::lowest, exec_queue::read_only_trx_safe, [&]() {
|
||||
// read_queue should have current function and write_queue's functions are all executed
|
||||
BOOST_REQUIRE_EQUAL( app->executor().read_only_trx_safe_queue().size(), 1);
|
||||
BOOST_REQUIRE_EQUAL( app->executor().general_queue().size(), 0 );
|
||||
app->quit();
|
||||
} );
|
||||
|
||||
app_thread.join();
|
||||
|
||||
// queues are emptied after quit
|
||||
BOOST_REQUIRE_EQUAL( app->executor().read_only_trx_safe_queue().empty(), true);
|
||||
BOOST_REQUIRE_EQUAL( app->executor().general_queue().empty(), true);
|
||||
|
||||
// exactly number of posts processed
|
||||
BOOST_REQUIRE_EQUAL( rslts.size(), 12 );
|
||||
|
||||
// all low must be processed the in order of posting
|
||||
BOOST_CHECK_LT( rslts[4], rslts[5] );
|
||||
BOOST_CHECK_LT( rslts[5], rslts[7] );
|
||||
BOOST_CHECK_LT( rslts[7], rslts[10] );
|
||||
|
||||
// all medium must be processed the in order of posting
|
||||
BOOST_CHECK_LT( rslts[0], rslts[1] );
|
||||
BOOST_CHECK_LT( rslts[1], rslts[11] );
|
||||
|
||||
// all functions posted after high before highest must be processed after high
|
||||
BOOST_CHECK_LT( rslts[2], rslts[3] );
|
||||
BOOST_CHECK_LT( rslts[2], rslts[4] );
|
||||
BOOST_CHECK_LT( rslts[2], rslts[5] );
|
||||
|
||||
// all functions posted after highest must be processed after it
|
||||
BOOST_CHECK_LT( rslts[6], rslts[7] );
|
||||
BOOST_CHECK_LT( rslts[6], rslts[8] );
|
||||
BOOST_CHECK_LT( rslts[6], rslts[9] );
|
||||
BOOST_CHECK_LT( rslts[6], rslts[10] );
|
||||
BOOST_CHECK_LT( rslts[6], rslts[11] );
|
||||
BOOST_CHECK_LT( rslts[6], rslts[11] );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
+1
-1
Submodule libraries/eos-vm updated: 1592261e96...4da112c820
@@ -1,5 +1,11 @@
|
||||
add_subdirectory( secp256k1 )
|
||||
add_subdirectory( libraries/bn256/src )
|
||||
|
||||
set( WITH_PROCPS OFF CACHE BOOL "" FORCE)
|
||||
set( CURVE "ALT_BN128" CACHE STRING "" FORCE)
|
||||
set( USE_ASM OFF CACHE BOOL "" FORCE)
|
||||
set( IS_LIBFF_PARENT OFF CACHE BOOL "" FORCE)
|
||||
set( FF_INSTALL_COMPONENT "${FC_INSTALL_COMPONENT}")
|
||||
add_subdirectory( libraries/ff )
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
@@ -24,16 +30,19 @@ set( fc_sources
|
||||
src/io/console.cpp
|
||||
src/filesystem.cpp
|
||||
src/interprocess/file_mapping.cpp
|
||||
src/interprocess/mmap_struct.cpp
|
||||
src/log/log_message.cpp
|
||||
src/log/logger.cpp
|
||||
src/log/appender.cpp
|
||||
src/log/console_appender.cpp
|
||||
src/log/console_appender.cpp
|
||||
src/log/dmlog_appender.cpp
|
||||
src/log/logger_config.cpp
|
||||
src/crypto/_digest_common.cpp
|
||||
src/crypto/aes.cpp
|
||||
src/crypto/crc.cpp
|
||||
src/crypto/city.cpp
|
||||
# src/crypto/base32.cpp
|
||||
src/crypto/base36.cpp
|
||||
src/crypto/base58.cpp
|
||||
src/crypto/base64.cpp
|
||||
src/crypto/bigint.cpp
|
||||
@@ -44,6 +53,8 @@ set( fc_sources
|
||||
src/crypto/sha256.cpp
|
||||
src/crypto/sha224.cpp
|
||||
src/crypto/sha512.cpp
|
||||
src/crypto/dh.cpp
|
||||
src/crypto/blowfish.cpp
|
||||
src/crypto/elliptic_common.cpp
|
||||
src/crypto/elliptic_impl_priv.cpp
|
||||
src/crypto/elliptic_secp256k1.cpp
|
||||
@@ -53,16 +64,20 @@ set( fc_sources
|
||||
src/crypto/public_key.cpp
|
||||
src/crypto/private_key.cpp
|
||||
src/crypto/signature.cpp
|
||||
src/crypto/alt_bn128.cpp
|
||||
src/crypto/modular_arithmetic.cpp
|
||||
src/crypto/blake2.cpp
|
||||
src/crypto/k1_recover.cpp
|
||||
src/network/ip.cpp
|
||||
src/network/platform_root_ca.cpp
|
||||
src/network/resolve.cpp
|
||||
src/network/udp_socket.cpp
|
||||
src/network/url.cpp
|
||||
src/network/http/http_client.cpp
|
||||
src/compress/smaz.cpp
|
||||
src/compress/zlib.cpp
|
||||
src/log/gelf_appender.cpp
|
||||
src/log/zipkin.cpp
|
||||
)
|
||||
|
||||
file( GLOB_RECURSE fc_headers ${CMAKE_CURRENT_SOURCE_DIR} *.hpp *.h )
|
||||
@@ -102,22 +117,6 @@ find_package(Boost 1.66 REQUIRED COMPONENTS
|
||||
unit_test_framework
|
||||
iostreams)
|
||||
|
||||
find_path(GMP_INCLUDE_DIR NAMES gmp.h)
|
||||
find_library(GMP_LIBRARY gmp)
|
||||
if(NOT GMP_LIBRARY MATCHES ${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
message( FATAL_ERROR "GMP shared library not found" )
|
||||
endif()
|
||||
set(gmp_library_type SHARED)
|
||||
message(STATUS "GMP: ${GMP_LIBRARY}, ${GMP_INCLUDE_DIR}")
|
||||
add_library(GMP::gmp ${gmp_library_type} IMPORTED)
|
||||
set_target_properties(
|
||||
GMP::gmp PROPERTIES
|
||||
IMPORTED_LOCATION ${GMP_LIBRARY}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${GMP_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(fc PUBLIC GMP::gmp)
|
||||
|
||||
# fc picks up a dependency on zlib via Boost::iostreams, however in some versions of cmake/boost (depending on if CMake config
|
||||
# files are used) the Boost::iostreams target does not have a dependency on zlib itself so add it explicitly
|
||||
find_package(ZLIB REQUIRED)
|
||||
@@ -139,8 +138,9 @@ if(APPLE)
|
||||
find_library(security_framework Security)
|
||||
find_library(corefoundation_framework CoreFoundation)
|
||||
endif()
|
||||
target_link_libraries( fc PUBLIC Boost::date_time Boost::filesystem Boost::chrono Boost::iostreams Threads::Threads
|
||||
OpenSSL::Crypto ZLIB::ZLIB ${PLATFORM_SPECIFIC_LIBS} ${CMAKE_DL_LIBS} secp256k1 ${security_framework} ${corefoundation_framework})
|
||||
target_link_libraries( fc PUBLIC ff
|
||||
Boost::date_time Boost::filesystem Boost::chrono Boost::iostreams Threads::Threads
|
||||
OpenSSL::Crypto OpenSSL::SSL ZLIB::ZLIB ${PLATFORM_SPECIFIC_LIBS} ${CMAKE_DL_LIBS} secp256k1 ${security_framework} ${corefoundation_framework} )
|
||||
|
||||
# Critically, this ensures that OpenSSL 1.1 & 3.0 both have a variant of BN_zero() with void return value. But it also allows access
|
||||
# to some obsoleted AES functions in 3.0 too, since 3.0's API_COMPAT is effectively 3.0 by default
|
||||
@@ -152,3 +152,4 @@ install(TARGETS fc
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
install(DIRECTORY include/fc DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#include <fc/api.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace detail {
|
||||
struct actor_member {
|
||||
#if 1 // BOOST_NO_VARIADIC_TEMPLATES
|
||||
#define RPC_MEMBER_FUNCTOR(z,n,IS_CONST) \
|
||||
template<typename R, typename C, typename P BOOST_PP_ENUM_TRAILING_PARAMS( n, typename A)> \
|
||||
static std::function<fc::future<R>( BOOST_PP_ENUM_PARAMS(n,A) ) > \
|
||||
functor( P p, R (C::*mem_func)(BOOST_PP_ENUM_PARAMS(n,A)) IS_CONST, fc::thread* c = 0) { \
|
||||
return [=](BOOST_PP_ENUM_BINARY_PARAMS(n,A,a))->fc::future<R>{ \
|
||||
return c->async( [=](){ return (p->*mem_func)(BOOST_PP_ENUM_PARAMS(n,a)); } ); }; \
|
||||
}
|
||||
BOOST_PP_REPEAT( 8, RPC_MEMBER_FUNCTOR, const )
|
||||
BOOST_PP_REPEAT( 8, RPC_MEMBER_FUNCTOR, BOOST_PP_EMPTY() )
|
||||
#undef RPC_MEMBER_FUNCTOR
|
||||
|
||||
#else // g++ has a bug that prevents lambdas and varidic templates from working together (G++ Bug 41933)
|
||||
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<fc::future<R>(Args...)> functor( P&& p, R (C::*mem_func)(Args...), fc::thread* c ) {
|
||||
return [=](Args... args)->fc::future<R>{ c->async( [=]()->R { return p->*mem_func( fc::forward<Args>(args)... ); } ) };
|
||||
}
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<fc::future<R>(Args...)> functor( P&& p, R (C::*mem_func)(Args...)const, fc::thread* c ){
|
||||
return [=](Args... args)->fc::future<R>{ c->async( [=]()->R { return p->*mem_func( fc::forward<Args>(args)... ); } ) };
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename ThisPtr>
|
||||
struct actor_vtable_visitor {
|
||||
template<typename U>
|
||||
actor_vtable_visitor( fc::thread* t, U&& u ):_thread(t),_this( fc::forward<U>(u) ){}
|
||||
|
||||
template<typename Function, typename MemberPtr>
|
||||
void operator()( const char* name, Function& memb, MemberPtr m )const {
|
||||
memb = actor_member::functor( _this, m, _thread );
|
||||
}
|
||||
fc::thread* _thread;
|
||||
ThisPtr _this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts all method calls to another thread and
|
||||
* returns a future.
|
||||
*/
|
||||
template<typename Interface>
|
||||
class actor : public api<Interface, detail::actor_member> {
|
||||
public:
|
||||
actor(){}
|
||||
|
||||
template<typename InterfaceType>
|
||||
actor( InterfaceType* p, fc::thread* t = &fc::thread::current() )
|
||||
{
|
||||
this->_vtable.reset(new detail::vtable<Interface,detail::actor_member>() );
|
||||
this->_vtable->template visit<InterfaceType>( detail::actor_vtable_visitor<InterfaceType*>(t, p) );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,621 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* *
|
||||
* Open Bloom Filter *
|
||||
* *
|
||||
* Author: Arash Partow - 2000 *
|
||||
* URL: http://www.partow.net *
|
||||
* URL: http://www.partow.net/programming/hashfunctions/index.html *
|
||||
* *
|
||||
* Copyright notice: *
|
||||
* Free use of the Open Bloom Filter Library is permitted under the *
|
||||
* guidelines and in accordance with the most current version of the *
|
||||
* Common Public License. *
|
||||
* http://www.opensource.org/licenses/cpl1.0.php *
|
||||
* *
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
|
||||
static const std::size_t bits_per_char = 0x08; // 8 bits in 1 char(unsigned)
|
||||
static const unsigned char bit_mask[bits_per_char] = {
|
||||
0x01, //00000001
|
||||
0x02, //00000010
|
||||
0x04, //00000100
|
||||
0x08, //00001000
|
||||
0x10, //00010000
|
||||
0x20, //00100000
|
||||
0x40, //01000000
|
||||
0x80 //10000000
|
||||
};
|
||||
|
||||
class bloom_parameters
|
||||
{
|
||||
public:
|
||||
|
||||
bloom_parameters()
|
||||
: minimum_size(1),
|
||||
maximum_size(std::numeric_limits<unsigned long long int>::max()),
|
||||
minimum_number_of_hashes(1),
|
||||
maximum_number_of_hashes(std::numeric_limits<unsigned int>::max()),
|
||||
projected_element_count(10000),
|
||||
false_positive_probability(1.0 / projected_element_count),
|
||||
random_seed(0xA5A5A5A55A5A5A5AULL)
|
||||
{}
|
||||
|
||||
virtual ~bloom_parameters()
|
||||
{}
|
||||
|
||||
inline bool operator!()
|
||||
{
|
||||
return (minimum_size > maximum_size) ||
|
||||
(minimum_number_of_hashes > maximum_number_of_hashes) ||
|
||||
(minimum_number_of_hashes < 1) ||
|
||||
(0 == maximum_number_of_hashes) ||
|
||||
(0 == projected_element_count) ||
|
||||
(false_positive_probability < 0.0) ||
|
||||
(std::numeric_limits<double>::infinity() == std::abs(false_positive_probability)) ||
|
||||
(0 == random_seed) ||
|
||||
(0xFFFFFFFFFFFFFFFFULL == random_seed);
|
||||
}
|
||||
|
||||
//Allowed min/max size of the bloom filter in bits
|
||||
unsigned long long int minimum_size;
|
||||
unsigned long long int maximum_size;
|
||||
|
||||
//Allowed min/max number of hash functions
|
||||
unsigned int minimum_number_of_hashes;
|
||||
unsigned int maximum_number_of_hashes;
|
||||
|
||||
//The approximate number of elements to be inserted
|
||||
//into the bloom filter, should be within one order
|
||||
//of magnitude. The default is 10000.
|
||||
unsigned long long int projected_element_count;
|
||||
|
||||
//The approximate false positive probability expected
|
||||
//from the bloom filter. The default is the reciprocal
|
||||
//of the projected_element_count.
|
||||
double false_positive_probability;
|
||||
|
||||
unsigned long long int random_seed;
|
||||
|
||||
struct optimal_parameters_t
|
||||
{
|
||||
optimal_parameters_t()
|
||||
: number_of_hashes(0),
|
||||
table_size(0)
|
||||
{}
|
||||
|
||||
unsigned int number_of_hashes;
|
||||
unsigned long long int table_size;
|
||||
};
|
||||
|
||||
optimal_parameters_t optimal_parameters;
|
||||
|
||||
virtual bool compute_optimal_parameters()
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
The following will attempt to find the number of hash functions
|
||||
and minimum amount of storage bits required to construct a bloom
|
||||
filter consistent with the user defined false positive probability
|
||||
and estimated element insertion count.
|
||||
*/
|
||||
|
||||
if (!(*this))
|
||||
return false;
|
||||
|
||||
double min_m = std::numeric_limits<double>::infinity();
|
||||
double min_k = 0.0;
|
||||
double curr_m = 0.0;
|
||||
double k = 1.0;
|
||||
|
||||
while (k < 1000.0)
|
||||
{
|
||||
double numerator = (- k * projected_element_count);
|
||||
double denominator = std::log(1.0 - std::pow(false_positive_probability, 1.0 / k));
|
||||
curr_m = numerator / denominator;
|
||||
if (curr_m < min_m)
|
||||
{
|
||||
min_m = curr_m;
|
||||
min_k = k;
|
||||
}
|
||||
k += 1.0;
|
||||
}
|
||||
|
||||
optimal_parameters_t& optp = optimal_parameters;
|
||||
|
||||
optp.number_of_hashes = static_cast<unsigned int>(min_k);
|
||||
optp.table_size = static_cast<unsigned long long int>(min_m);
|
||||
optp.table_size += (((optp.table_size % bits_per_char) != 0) ? (bits_per_char - (optp.table_size % bits_per_char)) : 0);
|
||||
|
||||
if (optp.number_of_hashes < minimum_number_of_hashes)
|
||||
optp.number_of_hashes = minimum_number_of_hashes;
|
||||
else if (optp.number_of_hashes > maximum_number_of_hashes)
|
||||
optp.number_of_hashes = maximum_number_of_hashes;
|
||||
|
||||
if (optp.table_size < minimum_size)
|
||||
optp.table_size = minimum_size;
|
||||
else if (optp.table_size > maximum_size)
|
||||
optp.table_size = maximum_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class bloom_filter
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef unsigned int bloom_type;
|
||||
typedef unsigned char cell_type;
|
||||
|
||||
public:
|
||||
|
||||
bloom_filter()
|
||||
: salt_count_(0),
|
||||
table_size_(0),
|
||||
raw_table_size_(0),
|
||||
projected_element_count_(0),
|
||||
inserted_element_count_(0),
|
||||
random_seed_(0),
|
||||
desired_false_positive_probability_(0.0)
|
||||
{}
|
||||
|
||||
bloom_filter(const bloom_parameters& p)
|
||||
: projected_element_count_(p.projected_element_count),
|
||||
inserted_element_count_(0),
|
||||
random_seed_((p.random_seed * 0xA5A5A5A5) + 1),
|
||||
desired_false_positive_probability_(p.false_positive_probability)
|
||||
{
|
||||
salt_count_ = p.optimal_parameters.number_of_hashes;
|
||||
table_size_ = p.optimal_parameters.table_size;
|
||||
generate_unique_salt();
|
||||
raw_table_size_ = table_size_ / bits_per_char;
|
||||
|
||||
bit_table_.resize( static_cast<std::size_t>(raw_table_size_) );
|
||||
//bit_table_ = new cell_type[static_cast<std::size_t>(raw_table_size_)];
|
||||
std::fill_n(bit_table_.data(),raw_table_size_,0x00);
|
||||
}
|
||||
|
||||
bloom_filter(const bloom_filter& filter)
|
||||
{
|
||||
this->operator=(filter);
|
||||
}
|
||||
|
||||
inline bool operator == (const bloom_filter& f) const
|
||||
{
|
||||
if (this != &f)
|
||||
{
|
||||
return
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(raw_table_size_ == f.raw_table_size_) &&
|
||||
(projected_element_count_ == f.projected_element_count_) &&
|
||||
(inserted_element_count_ == f.inserted_element_count_) &&
|
||||
(random_seed_ == f.random_seed_) &&
|
||||
(desired_false_positive_probability_ == f.desired_false_positive_probability_) &&
|
||||
(salt_ == f.salt_) &&
|
||||
std::equal(f.bit_table_.data(),f.bit_table_.data() + raw_table_size_,bit_table_.data());
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool operator != (const bloom_filter& f) const
|
||||
{
|
||||
return !operator==(f);
|
||||
}
|
||||
|
||||
inline bloom_filter& operator = (const bloom_filter& f)
|
||||
{
|
||||
if (this != &f)
|
||||
{
|
||||
salt_count_ = f.salt_count_;
|
||||
table_size_ = f.table_size_;
|
||||
raw_table_size_ = f.raw_table_size_;
|
||||
projected_element_count_ = f.projected_element_count_;
|
||||
inserted_element_count_ = f.inserted_element_count_;
|
||||
random_seed_ = f.random_seed_;
|
||||
desired_false_positive_probability_ = f.desired_false_positive_probability_;
|
||||
bit_table_.resize( raw_table_size_ );
|
||||
std::copy(f.bit_table_.data(),f.bit_table_.data() + raw_table_size_,bit_table_.data());
|
||||
salt_ = f.salt_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~bloom_filter()
|
||||
{
|
||||
}
|
||||
|
||||
inline bool operator!() const
|
||||
{
|
||||
return (0 == table_size_);
|
||||
}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
std::fill_n(bit_table_.data(),raw_table_size_,0x00);
|
||||
inserted_element_count_ = 0;
|
||||
}
|
||||
|
||||
inline void insert(const unsigned char* key_begin, const std::size_t& length)
|
||||
{
|
||||
std::size_t bit_index = 0;
|
||||
std::size_t bit = 0;
|
||||
for (std::size_t i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit);
|
||||
bit_table_[bit_index / bits_per_char] |= bit_mask[bit];
|
||||
}
|
||||
++inserted_element_count_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void insert(const T& t)
|
||||
{
|
||||
// Note: T must be a C++ POD type.
|
||||
insert(reinterpret_cast<const unsigned char*>(&t),sizeof(T));
|
||||
}
|
||||
|
||||
inline void insert(const std::string& key)
|
||||
{
|
||||
insert(reinterpret_cast<const unsigned char*>(key.c_str()),key.size());
|
||||
}
|
||||
|
||||
inline void insert(const char* data, const std::size_t& length)
|
||||
{
|
||||
insert(reinterpret_cast<const unsigned char*>(data),length);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline void insert(const InputIterator begin, const InputIterator end)
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
insert(*(itr++));
|
||||
}
|
||||
}
|
||||
|
||||
inline virtual bool contains(const unsigned char* key_begin, const std::size_t length) const
|
||||
{
|
||||
std::size_t bit_index = 0;
|
||||
std::size_t bit = 0;
|
||||
for (std::size_t i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit);
|
||||
if ((bit_table_[bit_index / bits_per_char] & bit_mask[bit]) != bit_mask[bit])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool contains(const T& t) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(&t),static_cast<std::size_t>(sizeof(T)));
|
||||
}
|
||||
|
||||
inline bool contains(const std::string& key) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(key.c_str()),key.size());
|
||||
}
|
||||
|
||||
inline bool contains(const char* data, const std::size_t& length) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(data),length);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline InputIterator contains_all(const InputIterator begin, const InputIterator end) const
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
if (!contains(*itr))
|
||||
{
|
||||
return itr;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline InputIterator contains_none(const InputIterator begin, const InputIterator end) const
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
if (contains(*itr))
|
||||
{
|
||||
return itr;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
inline virtual unsigned long long int size() const
|
||||
{
|
||||
return table_size_;
|
||||
}
|
||||
|
||||
inline std::size_t element_count() const
|
||||
{
|
||||
return inserted_element_count_;
|
||||
}
|
||||
|
||||
inline double effective_fpp() const
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
The effective false positive probability is calculated using the
|
||||
designated table size and hash function count in conjunction with
|
||||
the current number of inserted elements - not the user defined
|
||||
predicated/expected number of inserted elements.
|
||||
*/
|
||||
return std::pow(1.0 - std::exp(-1.0 * salt_.size() * inserted_element_count_ / size()), 1.0 * salt_.size());
|
||||
}
|
||||
|
||||
inline bloom_filter& operator &= (const bloom_filter& f)
|
||||
{
|
||||
/* intersection */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] &= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bloom_filter& operator |= (const bloom_filter& f)
|
||||
{
|
||||
/* union */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] |= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bloom_filter& operator ^= (const bloom_filter& f)
|
||||
{
|
||||
/* difference */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] ^= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const cell_type* table() const
|
||||
{
|
||||
return bit_table_.data();
|
||||
}
|
||||
|
||||
inline std::size_t hash_count()
|
||||
{
|
||||
return salt_.size();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
inline virtual void compute_indices(const bloom_type& hash, std::size_t& bit_index, std::size_t& bit) const
|
||||
{
|
||||
bit_index = hash % table_size_;
|
||||
bit = bit_index % bits_per_char;
|
||||
}
|
||||
|
||||
void generate_unique_salt()
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
A distinct hash function need not be implementation-wise
|
||||
distinct. In the current implementation "seeding" a common
|
||||
hash function with different values seems to be adequate.
|
||||
*/
|
||||
const unsigned int predef_salt_count = 128;
|
||||
static const bloom_type predef_salt[predef_salt_count] =
|
||||
{
|
||||
0xAAAAAAAA, 0x55555555, 0x33333333, 0xCCCCCCCC,
|
||||
0x66666666, 0x99999999, 0xB5B5B5B5, 0x4B4B4B4B,
|
||||
0xAA55AA55, 0x55335533, 0x33CC33CC, 0xCC66CC66,
|
||||
0x66996699, 0x99B599B5, 0xB54BB54B, 0x4BAA4BAA,
|
||||
0xAA33AA33, 0x55CC55CC, 0x33663366, 0xCC99CC99,
|
||||
0x66B566B5, 0x994B994B, 0xB5AAB5AA, 0xAAAAAA33,
|
||||
0x555555CC, 0x33333366, 0xCCCCCC99, 0x666666B5,
|
||||
0x9999994B, 0xB5B5B5AA, 0xFFFFFFFF, 0xFFFF0000,
|
||||
0xB823D5EB, 0xC1191CDF, 0xF623AEB3, 0xDB58499F,
|
||||
0xC8D42E70, 0xB173F616, 0xA91A5967, 0xDA427D63,
|
||||
0xB1E8A2EA, 0xF6C0D155, 0x4909FEA3, 0xA68CC6A7,
|
||||
0xC395E782, 0xA26057EB, 0x0CD5DA28, 0x467C5492,
|
||||
0xF15E6982, 0x61C6FAD3, 0x9615E352, 0x6E9E355A,
|
||||
0x689B563E, 0x0C9831A8, 0x6753C18B, 0xA622689B,
|
||||
0x8CA63C47, 0x42CC2884, 0x8E89919B, 0x6EDBD7D3,
|
||||
0x15B6796C, 0x1D6FDFE4, 0x63FF9092, 0xE7401432,
|
||||
0xEFFE9412, 0xAEAEDF79, 0x9F245A31, 0x83C136FC,
|
||||
0xC3DA4A8C, 0xA5112C8C, 0x5271F491, 0x9A948DAB,
|
||||
0xCEE59A8D, 0xB5F525AB, 0x59D13217, 0x24E7C331,
|
||||
0x697C2103, 0x84B0A460, 0x86156DA9, 0xAEF2AC68,
|
||||
0x23243DA5, 0x3F649643, 0x5FA495A8, 0x67710DF8,
|
||||
0x9A6C499E, 0xDCFB0227, 0x46A43433, 0x1832B07A,
|
||||
0xC46AFF3C, 0xB9C8FFF0, 0xC9500467, 0x34431BDF,
|
||||
0xB652432B, 0xE367F12B, 0x427F4C1B, 0x224C006E,
|
||||
0x2E7E5A89, 0x96F99AA5, 0x0BEB452A, 0x2FD87C39,
|
||||
0x74B2E1FB, 0x222EFD24, 0xF357F60C, 0x440FCB1E,
|
||||
0x8BBE030F, 0x6704DC29, 0x1144D12F, 0x948B1355,
|
||||
0x6D8FD7E9, 0x1C11A014, 0xADD1592F, 0xFB3C712E,
|
||||
0xFC77642F, 0xF9C4CE8C, 0x31312FB9, 0x08B0DD79,
|
||||
0x318FA6E7, 0xC040D23D, 0xC0589AA7, 0x0CA5C075,
|
||||
0xF874B172, 0x0CF914D5, 0x784D3280, 0x4E8CFEBC,
|
||||
0xC569F575, 0xCDB2A091, 0x2CC016B4, 0x5C5F4421
|
||||
};
|
||||
|
||||
if (salt_count_ <= predef_salt_count)
|
||||
{
|
||||
std::copy(predef_salt,
|
||||
predef_salt + salt_count_,
|
||||
std::back_inserter(salt_));
|
||||
for (unsigned int i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
This is done to integrate the user defined random seed,
|
||||
so as to allow for the generation of unique bloom filter
|
||||
instances.
|
||||
*/
|
||||
salt_[i] = salt_[i] * salt_[(i + 3) % salt_.size()] + static_cast<bloom_type>(random_seed_);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(predef_salt,predef_salt + predef_salt_count,std::back_inserter(salt_));
|
||||
srand(static_cast<unsigned int>(random_seed_));
|
||||
while (salt_.size() < salt_count_)
|
||||
{
|
||||
bloom_type current_salt = static_cast<bloom_type>(rand()) * static_cast<bloom_type>(rand());
|
||||
if (0 == current_salt) continue;
|
||||
if (salt_.end() == std::find(salt_.begin(), salt_.end(), current_salt))
|
||||
{
|
||||
salt_.push_back(current_salt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bloom_type hash_ap(const unsigned char* begin, std::size_t remaining_length, bloom_type hash) const
|
||||
{
|
||||
const unsigned char* itr = begin;
|
||||
unsigned int loop = 0;
|
||||
while (remaining_length >= 8)
|
||||
{
|
||||
const unsigned int& i1 = *(reinterpret_cast<const unsigned int*>(itr)); itr += sizeof(unsigned int);
|
||||
const unsigned int& i2 = *(reinterpret_cast<const unsigned int*>(itr)); itr += sizeof(unsigned int);
|
||||
hash ^= (hash << 7) ^ i1 * (hash >> 3) ^
|
||||
(~((hash << 11) + (i2 ^ (hash >> 5))));
|
||||
remaining_length -= 8;
|
||||
}
|
||||
if (remaining_length)
|
||||
{
|
||||
if (remaining_length >= 4)
|
||||
{
|
||||
const unsigned int& i = *(reinterpret_cast<const unsigned int*>(itr));
|
||||
if (loop & 0x01)
|
||||
hash ^= (hash << 7) ^ i * (hash >> 3);
|
||||
else
|
||||
hash ^= (~((hash << 11) + (i ^ (hash >> 5))));
|
||||
++loop;
|
||||
remaining_length -= 4;
|
||||
itr += sizeof(unsigned int);
|
||||
}
|
||||
if (remaining_length >= 2)
|
||||
{
|
||||
const unsigned short& i = *(reinterpret_cast<const unsigned short*>(itr));
|
||||
if (loop & 0x01)
|
||||
hash ^= (hash << 7) ^ i * (hash >> 3);
|
||||
else
|
||||
hash ^= (~((hash << 11) + (i ^ (hash >> 5))));
|
||||
++loop;
|
||||
remaining_length -= 2;
|
||||
itr += sizeof(unsigned short);
|
||||
}
|
||||
if (remaining_length)
|
||||
{
|
||||
hash += ((*itr) ^ (hash * 0xA5A5A5A5)) + loop;
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<bloom_type> salt_;
|
||||
std::vector<unsigned char> bit_table_;
|
||||
unsigned int salt_count_;
|
||||
unsigned long long int table_size_;
|
||||
unsigned long long int raw_table_size_;
|
||||
unsigned long long int projected_element_count_;
|
||||
unsigned int inserted_element_count_;
|
||||
unsigned long long int random_seed_;
|
||||
double desired_false_positive_probability_;
|
||||
};
|
||||
|
||||
inline bloom_filter operator & (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result &= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bloom_filter operator | (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result |= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bloom_filter operator ^ (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result ^= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
FC_REFLECT( fc::bloom_filter, (salt_)(bit_table_)(salt_count_)(table_size_)(raw_table_size_)(projected_element_count_)(inserted_element_count_)(random_seed_)(desired_false_positive_probability_) )
|
||||
FC_REFLECT( fc::bloom_parameters::optimal_parameters_t, (number_of_hashes)(table_size) )
|
||||
FC_REFLECT( fc::bloom_parameters, (minimum_size)(maximum_size)(minimum_number_of_hashes)(maximum_number_of_hashes)(projected_element_count)(false_positive_probability)(random_seed)(optimal_parameters) )
|
||||
|
||||
/*
|
||||
Note 1:
|
||||
If it can be guaranteed that bits_per_char will be of the form 2^n then
|
||||
the following optimization can be used:
|
||||
|
||||
hash_table[bit_index >> n] |= bit_mask[bit_index & (bits_per_char - 1)];
|
||||
|
||||
Note 2:
|
||||
For performance reasons where possible when allocating memory it should
|
||||
be aligned (aligned_alloc) according to the architecture being used.
|
||||
*/
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace fc {
|
||||
|
||||
std::string smaz_compress( const std::string& in );
|
||||
std::string smaz_decompress( const std::string& compressed );
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
namespace fc {
|
||||
using bytes = std::vector<char>;
|
||||
|
||||
enum class alt_bn128_error : int32_t {
|
||||
operand_component_invalid,
|
||||
operand_not_in_curve,
|
||||
pairing_list_size_error,
|
||||
operand_outside_g2,
|
||||
input_len_error,
|
||||
invalid_scalar_size
|
||||
};
|
||||
|
||||
std::variant<alt_bn128_error, bytes> alt_bn128_add(const bytes& op1, const bytes& op2);
|
||||
std::variant<alt_bn128_error, bytes> alt_bn128_mul(const bytes& g1_point, const bytes& scalar);
|
||||
std::variant<alt_bn128_error, bool> alt_bn128_pair(const bytes& g1_g2_pairs, const yield_function_t& yield);
|
||||
|
||||
} // fc
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
std::vector<char> from_base32( const fc::string& b32 );
|
||||
fc::string to_base32( const std::vector<char>& vec );
|
||||
fc::string to_base32( const char* data, size_t len );
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
std::vector<char> from_base36( const fc::string& b36 );
|
||||
fc::string to_base36( const std::vector<char>& vec );
|
||||
fc::string to_base36( const char* data, size_t len );
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user