diff --git a/Builds/CMake/XBridgeWitnessNIH.cmake b/Builds/CMake/XBridgeWitnessNIH.cmake deleted file mode 100644 index 5e9e244..0000000 --- a/Builds/CMake/XBridgeWitnessNIH.cmake +++ /dev/null @@ -1,36 +0,0 @@ -#[===================================================================[ - NIH prefix path..this is where we will download - and build any ExternalProjects, and they will hopefully - survive across build directory deletion (manual cleans) - - Copied from rippled https://github.com/ripple/rippled/blob/develop/Builds/CMake/RippledNIH.cmake - Only called if building directly and a Rippled installation was not found. -#]===================================================================] - -string (REGEX REPLACE "[ \\/%]+" "_" gen_for_path ${CMAKE_GENERATOR}) -string (TOLOWER ${gen_for_path} gen_for_path) -# HACK: trying to shorten paths for windows CI (which hits 260 MAXPATH easily) -# @see: https://issues.jenkins-ci.org/browse/JENKINS-38706?focusedCommentId=339847 -string (REPLACE "visual_studio" "vs" gen_for_path ${gen_for_path}) -if (NOT DEFINED NIH_CACHE_ROOT) - if (DEFINED ENV{NIH_CACHE_ROOT}) - set (NIH_CACHE_ROOT $ENV{NIH_CACHE_ROOT}) - else () - set (NIH_CACHE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/.nih_c") - endif () -endif () -set (nih_cache_path - "${NIH_CACHE_ROOT}/${gen_for_path}/${CMAKE_CXX_COMPILER_ID}_${CMAKE_CXX_COMPILER_VERSION}") -if (NOT is_multiconfig) - set (nih_cache_path "${nih_cache_path}/${CMAKE_BUILD_TYPE}") -endif () -file(TO_CMAKE_PATH "${nih_cache_path}" nih_cache_path) -message (STATUS "NIH-EP cache path: ${nih_cache_path}") -## two convenience variables: -set (ep_lib_prefix ${CMAKE_STATIC_LIBRARY_PREFIX}) -set (ep_lib_suffix ${CMAKE_STATIC_LIBRARY_SUFFIX}) - -# this is a setting for FetchContent and needs to be -# a cache variable -# https://cmake.org/cmake/help/latest/module/FetchContent.html#populating-the-content -set (FETCHCONTENT_BASE_DIR ${nih_cache_path} CACHE STRING "" FORCE) diff --git a/Builds/CMake/deps/Boost.cmake b/Builds/CMake/deps/Boost.cmake deleted file mode 100644 index 23ea5e5..0000000 --- a/Builds/CMake/deps/Boost.cmake +++ /dev/null @@ -1,51 +0,0 @@ -find_package(Boost 1.70 REQUIRED - COMPONENTS - chrono - container - context - coroutine - date_time - filesystem - program_options - regex - system - thread -) - -add_library(ripple_boost INTERFACE) -add_library(Ripple::boost ALIAS ripple_boost) -if(XCODE) - target_include_directories(ripple_boost BEFORE INTERFACE ${Boost_INCLUDE_DIRS}) - target_compile_options(ripple_boost INTERFACE --system-header-prefix="boost/") -else() - target_include_directories(ripple_boost SYSTEM BEFORE INTERFACE ${Boost_INCLUDE_DIRS}) -endif() - -target_link_libraries(ripple_boost - INTERFACE - Boost::boost - Boost::chrono - Boost::container - Boost::coroutine - Boost::date_time - Boost::filesystem - Boost::program_options - Boost::regex - Boost::system - Boost::thread) -if(Boost_COMPILER) - target_link_libraries(ripple_boost INTERFACE Boost::disable_autolinking) -endif() -if(san AND is_clang) - # TODO: gcc does not support -fsanitize-blacklist...can we do something else - # for gcc ? - if(NOT Boost_INCLUDE_DIRS AND TARGET Boost::headers) - get_target_property(Boost_INCLUDE_DIRS Boost::headers INTERFACE_INCLUDE_DIRECTORIES) - endif() - message(STATUS "Adding [${Boost_INCLUDE_DIRS}] to sanitizer blacklist") - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt "src:${Boost_INCLUDE_DIRS}/*") - target_compile_options(opts - INTERFACE - # ignore boost headers for sanitizing - -fsanitize-blacklist=${CMAKE_CURRENT_BINARY_DIR}/san_bl.txt) -endif() diff --git a/Builds/CMake/deps/FindRipple.cmake b/Builds/CMake/deps/FindRipple.cmake deleted file mode 100644 index eff5b21..0000000 --- a/Builds/CMake/deps/FindRipple.cmake +++ /dev/null @@ -1,36 +0,0 @@ -find_path(Ripple_SRC - NAMES src/ripple/protocol/STXChainBridge.h - PATHS ${RIPPLE_SRC_DIR} - NO_CMAKE_SYSTEM_PATH - NO_SYSTEM_ENVIRONMENT_PATH) -if(Ripple_SRC) - set(Ripple_INCLUDE_DIR ${Ripple_SRC}/src) -endif() - -find_library(Ripple_LIBRARY - NAMES xrpl_core - PATHS ${RIPPLE_BIN_DIR} - NO_CMAKE_SYSTEM_PATH - NO_SYSTEM_ENVIRONMENT_PATH) - -if(Ripple_SRC AND Ripple_LIBRARY) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Ripple DEFAULT_MSG - Ripple_INCLUDE_DIR Ripple_LIBRARY) - if(Ripple_FOUND) - add_library(Ripple::xrpl_core STATIC IMPORTED) - set_target_properties(Ripple::xrpl_core PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${Ripple_INCLUDE_DIR}" - IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" - IMPORTED_LOCATION "${Ripple_LIBRARY}") - target_link_libraries (Ripple::xrpl_core INTERFACE - ${RIPPLE_BIN_DIR}/src/ed25519-donna/libed25519.a - ${RIPPLE_BIN_DIR}/src/secp256k1/src/libsecp256k1.a) - endif() -endif() - -if(Ripple_FOUND) - message("Looking for RIPPLED ... found") -else() - message("Looking for RIPPLED ... NOT found") -endif() diff --git a/Builds/CMake/packaging/build_packages.sh b/Builds/CMake/packaging/build_packages.sh index f7a5a77..81c956f 100755 --- a/Builds/CMake/packaging/build_packages.sh +++ b/Builds/CMake/packaging/build_packages.sh @@ -7,7 +7,6 @@ bin_dir="${src_dir}/build" pkg_dir="${src_dir}/packages" build_config=Release conan_packages_to_build="missing" -#conan_profile="default" nproc=$(($(nproc) - 2)) if [ $nproc -lt 3 ]; then @@ -21,10 +20,14 @@ if [ $ID = centos ]; then source /opt/rh/rh-python38/enable conan_packages_to_build="" # blank bc all dependencies need to be built for CentOS 7 currently #conan_profile="centos" # TODO: Make a "centos" profile and upload the bin pkgs - #conan remote add --insert 0 conan-non-prod http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod || true fi -conan profile new default --detect +if ! (conan remote list | grep conan-non-prod); then + conan remote add --insert 0 conan-non-prod http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod +fi +if ! (conan profile list | grep default); then + conan profile new default --detect; +fi conan profile update settings.compiler.cppstd=20 default conan profile update settings.compiler.libcxx=libstdc++11 default @@ -39,7 +42,7 @@ cmake \ -B "${bin_dir}" \ -DCMAKE_BUILD_TYPE=${build_config} \ -DPKG=deb \ - -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake + -DCMAKE_TOOLCHAIN_FILE:FILEPATH=conan_toolchain.cmake \ cmake \ --build "${bin_dir}" \ @@ -51,8 +54,8 @@ cmake \ -S "${src_dir}" \ -B "${bin_dir}" \ -DCMAKE_BUILD_TYPE=${build_config} \ - -DPKG=rpm \ - -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake + -DCMAKE_TOOLCHAIN_FILE:FILEPATH=conan_toolchain.cmake \ + -DPKG=rpm cmake \ --build "${bin_dir}" \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 55bf058..a9a7dae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required (VERSION 3.20) -project (xbridge_witnessd) +cmake_minimum_required(VERSION 3.20) +project(xbridge_witnessd) -if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11)) +if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11)) message(FATAL_ERROR "Use gcc >= 11.0") -elseif((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13)) +elseif((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13)) message(FATAL_ERROR "Use clang >= 13.0") endif() @@ -19,148 +19,57 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_VERBOSE_MAKEFILE 1) - - -#[===========================================[ - The tool depends on the xrpl_core - library which is defined by the rippled - project. This looks for installed rippled - libs and, if not found, pulls them in with - FetchContent. -#]===========================================] list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Builds/CMake") -#include(deps/Boost) -find_package(SOCI REQUIRED) -find_package(fmt REQUIRED) find_package(date REQUIRED) +find_package(fmt REQUIRED) find_package(OpenSSL REQUIRED) +find_package(SOCI REQUIRED) find_package(Threads) - -include(XBridgeWitnessNIH) +find_package(xrpl REQUIRED) get_directory_property(has_parent PARENT_DIRECTORY) -if(coverage) - # Rippled also responds to the "coverage" flag, so clear it if it's set until - # the dependency is set up. - set(xbridge_witness_coverage ${coverage}) - set(coverage OFF CACHE BOOL "gcc/clang only" FORCE) -endif() - add_compile_definitions( BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT BOOST_CONTAINER_FWD_BAD_DEQUE HAS_UNCAUGHT_EXCEPTIONS=1 ) -if (CMAKE_BUILD_TYPE STREQUAL "Debug") +if(CMAKE_BUILD_TYPE STREQUAL "Debug") add_compile_definitions(_DEBUG) endif() -if (NOT has_parent) - find_package(Ripple QUIET) - if (NOT TARGET Ripple::xrpl_core) - include(deps/FindRipple) - if (NOT TARGET Ripple::xrpl_core) - find_package(Git) - - if (NOT GIT_FOUND) - message (FATAL_ERROR "git is required to determine branch name") - endif () - - execute_process (COMMAND ${GIT_EXECUTABLE} "rev-parse" "--abbrev-ref" "HEAD" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - RESULT_VARIABLE _git_exit_code - OUTPUT_VARIABLE _branch - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET) - if (NOT _git_exit_code EQUAL 0) - message (WARNING "git command failed - deduced branch might be incorrect") - endif () - - # rippled_tag is cache string and can be overriden when configuring - # with -Drippled_tag=commit_or_tag in order to pick a specific - # rippled version to download. Default tag is develop/master/release as - # determined by the branch of this project - if (NOT (_branch STREQUAL "master" OR _branch STREQUAL "release")) - set (rippled_tag "develop" CACHE STRING - "tag/commit of rippled to fetch from if a local install is not found") - else () - set (rippled_tag "${_branch}" CACHE STRING - "tag/commit of rippled to fetch from if a local install is not found") - endif () - message(STATUS "Installed rippled not found... \ - using local copy from tag/commit [${rippled_tag}]") - include (FetchContent) - FetchContent_Declare( - rippled_src - GIT_REPOSITORY https://github.com/XRPLF/rippled.git - GIT_TAG ${rippled_tag} - ) - FetchContent_GetProperties(rippled_src) - if(NOT rippled_src_POPULATED) - message (STATUS "Pausing to download rippled source...") - FetchContent_Populate(rippled_src) - - set (conan_build_type "Release") - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set (conan_build_type "Debug") - endif() - - set (conan_profile "default") - if(NOT "${CONAN_PROFILE} " STREQUAL " ") - set (conan_profile ${CONAN_PROFILE}) - endif() - - execute_process (COMMAND conan install ${rippled_src_SOURCE_DIR} --build missing --output-folder . -s build_type=${conan_build_type} -pr=${conan_profile} - WORKING_DIRECTORY ${rippled_src_BINARY_DIR} - RESULT_VARIABLE _git_exit_code - OUTPUT_STRIP_TRAILING_WHITESPACE - ECHO_OUTPUT_VARIABLE - ECHO_ERROR_VARIABLE - ) - if (NOT _git_exit_code EQUAL 0) - message (WARNING "conan exit_code: ${_git_exit_code}\n conan command failed - build might be incorrect") - endif () - - option (tests "Build tests" OFF) - add_subdirectory(${rippled_src_SOURCE_DIR} ${rippled_src_BINARY_DIR}) - endif() - endif() - endif () -endif () - if(xbridge_witness_coverage) set(coverage ${xbridge_witness_coverage} CACHE BOOL "gcc/clang only" FORCE) endif() # this one is a string and therefore can't be an option -set (san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation") -set_property (CACHE san PROPERTY STRINGS ";undefined;memory;address;thread") -if (san) - string (TOLOWER ${san} san) - set (SAN_FLAG "-fsanitize=${san}") - set (SAN_LIB "") - if (is_gcc) - if (san STREQUAL "address") - set (SAN_LIB "asan") - elseif (san STREQUAL "thread") - set (SAN_LIB "tsan") - elseif (san STREQUAL "memory") - set (SAN_LIB "msan") - elseif (san STREQUAL "undefined") - set (SAN_LIB "ubsan") - endif () - endif () - set (_saved_CRL ${CMAKE_REQUIRED_LIBRARIES}) - set (CMAKE_REQUIRED_LIBRARIES "${SAN_FLAG};${SAN_LIB}") - check_cxx_compiler_flag (${SAN_FLAG} COMPILER_SUPPORTS_SAN) - set (CMAKE_REQUIRED_LIBRARIES ${_saved_CRL}) - if (NOT COMPILER_SUPPORTS_SAN) - message (FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler") - endif () -endif () +set(san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation") +set_property(CACHE san PROPERTY STRINGS ";undefined;memory;address;thread") +if(san) + string(TOLOWER ${san} san) + set(SAN_FLAG "-fsanitize=${san}") + set(SAN_LIB "") + if(is_gcc) + if(san STREQUAL "address") + set(SAN_LIB "asan") + elseif(san STREQUAL "thread") + set(SAN_LIB "tsan") + elseif(san STREQUAL "memory") + set(SAN_LIB "msan") + elseif(san STREQUAL "undefined") + set(SAN_LIB "ubsan") + endif() + endif() + set(_saved_CRL ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_LIBRARIES "${SAN_FLAG};${SAN_LIB}") + check_cxx_compiler_flag(${SAN_FLAG} COMPILER_SUPPORTS_SAN) + set(CMAKE_REQUIRED_LIBRARIES ${_saved_CRL}) + if(NOT COMPILER_SUPPORTS_SAN) + message(FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler") + endif() +endif() include(XBridgeWitnessSanity) include(XBridgeWitnessCov) @@ -209,7 +118,7 @@ set(SOURCES option(tests "Enable unit tests" ON) -if (tests) +if(tests) set(UNIT_TESTS src/test/Config_test.cpp src/test/DB_test.cpp @@ -218,48 +127,57 @@ if (tests) src/test/RPCParse_test.cpp src/test/WS_test.cpp ) -endif () #tests +endif () -add_executable (${PROJECT_NAME} +add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${UNIT_TESTS} ) -install (TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) +install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) target_compile_options(${PROJECT_NAME} PUBLIC "-fstack-protector-strong") -if (is_linux) +if(is_linux) target_link_options(${PROJECT_NAME} PUBLIC "LINKER:-z,relro,-z,now") endif() + target_include_directories (${PROJECT_NAME} PRIVATE src ${date_INCLUDE_DIR}) -target_link_libraries (${PROJECT_NAME} PUBLIC Ripple::xrpl_core XBridgeWitness::opts - SOCI::soci_core_static SOCI::soci_sqlite3_static fmt::fmt OpenSSL::Crypto OpenSSL::SSL) +target_link_libraries(${PROJECT_NAME} + PUBLIC + xrpl::libxrpl + XBridgeWitness::opts + SOCI::soci_core_static + SOCI::soci_sqlite3_static + fmt::fmt + OpenSSL::Crypto + OpenSSL::SSL + ) -if (san) - target_compile_options (${PROJECT_NAME} +if(san) + target_compile_options(${PROJECT_NAME} INTERFACE # sanitizers recommend minimum of -O1 for reasonable performance $<$:-O1> ${SAN_FLAG} -fno-omit-frame-pointer) - target_compile_definitions (${PROJECT_NAME} + target_compile_definitions(${PROJECT_NAME} INTERFACE $<$:SANITIZER=ASAN> $<$:SANITIZER=TSAN> $<$:SANITIZER=MSAN> $<$:SANITIZER=UBSAN>) - target_link_libraries (${PROJECT_NAME} INTERFACE ${SAN_FLAG} ${SAN_LIB}) -endif () + target_link_libraries(${PROJECT_NAME} INTERFACE ${SAN_FLAG} ${SAN_LIB}) +endif() -if (has_parent) - set_target_properties (${PROJECT_NAME} PROPERTIES EXCLUDE_FROM_ALL ON) - set_target_properties (${PROJECT_NAME} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON) -endif () +if(has_parent) + set_target_properties(${PROJECT_NAME} PROPERTIES EXCLUDE_FROM_ALL ON) + set_target_properties(${PROJECT_NAME} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON) +endif() #fix for MAC get_target_property(FMT_INC_DIRS fmt::fmt INTERFACE_INCLUDE_DIRECTORIES) -list (GET FMT_INC_DIRS 0 FMT_INC_DIR) +list(GET FMT_INC_DIRS 0 FMT_INC_DIR) target_include_directories(${PROJECT_NAME} BEFORE PRIVATE ${FMT_INC_DIR}) include(packaging/package) diff --git a/README.md b/README.md index f797356..6108ece 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,155 @@ + + + + # Witness Server for XRPL Sidechains -## Table of contents +This is the Witness Server for [XLS-38d Cross-Chain bridge project](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0038d-cross-chain-bridge). "Witness Servers" validate transfers between "door accounts" that connect a locking chain to each issuing chain by listening for transactions on one or both of the chains and signing attestations to prove certain events happened on a chain. + +## Branches +- `develop`: The latest set of unreleased features, and the most common starting point for contributions. +- `release`: The latest beta release or release candidate. +- `main`: The latest stable release. -* [Documentation](#documentation) -* [Build guide](#build-guide) - * [Dependencies](#dependencies) - * [Conan inclusion](#conan-inclusion) - * [Other dependencies](#other-dependencies) - * [Build steps](#build-and-run) +## Release process: +- Bump version in `BuildInfo.cpp` and add -rcX suffix. (for example "1.0.0-rc1"). Name this commit "Version x.x.x-rcX". +- Merge `develop` branch into `release`. +- Create a git tag for release candidate. (for example "1.0.0-rc1") +- From now only fixes can be commited/merged into the `release` branch +- After a week of usage and tests, update the version by removing `-rcX` suffix. +- Merge `release` into `main`. +- Create tag for released version. (for example "1.0.0") +- Draft a new release. (See https://github.com/ripple/xbridge_witness/releases) -## Documentation +## Additional documentation - [XRPL Sidechains concept](https://xrpl.org/xrpl-sidechains.html) -- [Cross bridge transactions](https://opensource.ripple.com/docs/xls-38d-cross-chain-bridge/cross-chain-bridges/) +- [Cross bridge transactions](https://xrpl.org/cross-chain-bridges.html#how-do-bridges-work/) - [XRPL-Standards documentation](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0038d-cross-chain-bridge) -## Build guide -### Dependencies +## Minimum Requirements + +- [Python 3.7](https://www.python.org/downloads/) +- [Conan 1.55](https://conan.io/downloads.html) Conan 2.0 is **_not_** supported yet +- [CMake 3.20](https://cmake.org/download/) -#### Conan inclusion +| Compiler | Version | +|-------------|---------| +| GCC | 11 | +| Clang | 13 | +| Apple clang | 15 | -This project depends on conan (v1.5 and higher, v2.0 not supported) to build it's dependencies. See [conan doc](https://docs.conan.io/1/installation.html) to install conan. +## Build and run -#### Other dependencies +1. Create a build directory and `cd` into it. -* C++20 compiler (gcc >=11, clang >=13) -* [cmake](https://cmake.org) - at least 3.20 +```bash +mkdir .build && cd .build +``` +2. Configure Conan. -### Build and run +Add Ripple's Artifactory as a Conan remote to source the `libxrpl` Conan package. -1) Create a build directory. For example: build -2) Change to that directory. -3) Configure conan (once before very 1st build) +```bash +conan remote add --insert 0 conan-non-prod http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod -``` bash +``` +
+ Optional local development of xrpl library + +The Conan `xrpl` recipe is also available by checking out the [`rippled` source](https://github.com/XRPLF/rippled.git) and exporting the recipe locally. + +```bash +git clone https://github.com/XRPLF/rippled.git +cd rippled +conan export . +``` +
+ +```bash conan profile update settings.cppstd=20 default conan profile update settings.compiler.libcxx=libstdc++11 default -conan profile update settings.arch=x86_64 default ``` +
+
+ Example Conan profiles + +### Linux +```ini + [settings] + arch=x86_64 + arch_build=x86_64 + os=Linux + os_build=Linux + build_type=Release + compiler=gcc + compiler.cppstd=20 + compiler.libcxx=libstdc++11 + compiler.version=11 +``` +### macOS -4) Run conan. The command is: +On macOS [you may get an error from Boost](https://github.com/XRPLF/rippled/blob/develop/BUILD.md#call-to-async_teardown-is-ambiguous) +which requires adding some CMake flags to your Conan profile. +``` +conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default +conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default +``` -``` bash -conan install -b missing -s build_type=Release --output-folder . .. +```ini +[settings] +os=Macos +os_build=Macos +arch=armv8 +arch_build=armv8 +compiler=apple-clang +compiler.version=15 +build_type=Release +compiler.cppstd=20 +compiler.libcxx=libc++ +[options] +[conf] +tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS'] +[build_requires] +[env] +CXXFLAGS=-DBOOST_ASIO_DISABLE_CONCEPTS ``` +
+ +3. Run Conan to install and/or build dependencies. -5) Create a build file (replace .. with the appropriate directory). 2 pckage system supported - deb and rpm: -* 5.1 Default. If you have [rippled](https://github.com/XRPLF/rippled/tree/develop) installed by your packet manager - cmake will try to find it. If nothing found - this setup will download rippled and build it. ``` bash -cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=build/generators/conan_toolchain.cmake -DPKG=deb .. +conan install .. \ + --output-folder . \ + --build missing \ + --settings build_type=Release ``` -* 5.2 If you have [rippled](https://github.com/XRPLF/rippled/tree/develop) build from source you can use it +4. Configure CMake. + ``` bash -cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=build/generators/conan_toolchain.cmake -DRIPPLE_SRC_DIR=/home/user/repo/rippled -DRIPPLE_BIN_DIR=/home/user/repo/rippled/build-release -DPKG=deb .. +cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake ``` -6) Build the project: +5. Build with CMake. ``` bash -make -j $(nproc) +cmake --build --parallel $(nproc) ``` -7) Run +6. Run the unit tests. ``` bash -./xbridge_witnessd --conf /home/user/repo/config.json +./xbridge_witnessd --unittest ``` -Check for config examples in documenation + +[Check the documentation for configuration examples.](https://xrpl.org/witness-servers.html#witness-server-configuration) + +## Additional help + +Additional help for Conan/CMake issues may be found in [`rippled`'s build instructions.](https://github.com/XRPLF/rippled/blob/develop/BUILD.md) + +Feel free to open an [issue](https://github.com/ripple/xbridge_witness/issues) if you have a feature request or something doesn't work as expected. diff --git a/conanfile.py b/conanfile.py deleted file mode 100644 index 7f46b13..0000000 --- a/conanfile.py +++ /dev/null @@ -1,151 +0,0 @@ -from conan import ConanFile -from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout -import re -from sys import platform - -class Xrpl(ConanFile): - name = 'xrpl' - - license = 'ISC' - author = 'John Freeman ' - url = 'https://github.com/xrplf/rippled' - description = 'The XRP Ledger' - settings = 'os', 'compiler', 'build_type', 'arch' - options = { - 'assertions': [True, False], - 'coverage': [True, False], - 'fPIC': [True, False], - 'jemalloc': [True, False], - 'reporting': [True, False], - 'rocksdb': [True, False], - 'shared': [True, False], - 'static': [True, False], - 'tests': [True, False], - 'unity': [True, False], - } - - requires = [ - 'boost/1.82.0', - 'date/3.0.1', - 'grpc/1.50.1', - 'libarchive/3.6.2', - 'lz4/1.9.3', - 'nudb/2.0.8', - 'openssl/1.1.1u', - 'protobuf/3.21.9', - 'snappy/1.1.10', - 'soci/4.0.3', - 'sqlite3/3.42.0', - 'zlib/1.2.13', - 'fmt/8.1.1' - ] - - default_options = { - 'assertions': False, - 'coverage': False, - 'fPIC': True, - 'jemalloc': False, - 'reporting': False, - 'rocksdb': False, - 'shared': False, - 'static': True, - 'tests': True, - 'unity': False, - - 'cassandra-cpp-driver:shared': False, - 'cassandra-cpp-driver:use_atomic': None, - 'date:header_only': True, - 'grpc:shared': False, - 'grpc:secure': True, - 'libarchive:shared': False, - 'libarchive:with_acl': False, - 'libarchive:with_bzip2': False, - 'libarchive:with_cng': False, - 'libarchive:with_expat': False, - 'libarchive:with_iconv': False, - 'libarchive:with_libxml2': False, - 'libarchive:with_lz4': True, - 'libarchive:with_lzma': False, - 'libarchive:with_lzo': False, - 'libarchive:with_nettle': False, - 'libarchive:with_openssl': False, - 'libarchive:with_pcreposix': False, - 'libarchive:with_xattr': False, - 'libarchive:with_zlib': False, - 'libpq:shared': False, - 'lz4:shared': False, - 'openssl:shared': False, - 'protobuf:shared': False, - 'protobuf:with_zlib': True, - 'rocksdb:enable_sse': False, - 'rocksdb:lite': False, - 'rocksdb:shared': False, - 'rocksdb:use_rtti': True, - 'rocksdb:with_jemalloc': False, - 'rocksdb:with_lz4': True, - 'rocksdb:with_snappy': True, - 'snappy:shared': False, - 'soci:shared': False, - 'soci:with_sqlite3': True, - 'soci:with_boost': True, - } - - def set_version(self): - self.version = "1.0.0" - - def configure(self): - if self.settings.compiler == 'apple-clang': - self.options['boost'].visibility = 'global' - - def requirements(self): - if self.options.jemalloc: - self.requires('jemalloc/5.3.0') - if self.options.reporting: - self.requires('cassandra-cpp-driver/2.15.3') - self.requires('libpq/14.7') - if self.options.rocksdb: - self.requires('rocksdb/6.29.5') - if platform.startswith('linux'): - self.requires('liburing/2.2') - - exports_sources = ( - 'CMakeLists.txt', 'Builds/*', 'bin/getRippledInfo', 'src/*', 'cfg/*' - ) - - def layout(self): - cmake_layout(self) - # Fix this setting to follow the default introduced in Conan 1.48 - # to align with our build instructions. - self.folders.generators = 'build/generators' - - generators = 'CMakeDeps' - def generate(self): - tc = CMakeToolchain(self) - tc.variables['tests'] = self.options.tests - tc.variables['assert'] = self.options.assertions - tc.variables['coverage'] = self.options.coverage - tc.variables['jemalloc'] = self.options.jemalloc - tc.variables['reporting'] = self.options.reporting - tc.variables['rocksdb'] = self.options.rocksdb - tc.variables['BUILD_SHARED_LIBS'] = self.options.shared - tc.variables['static'] = self.options.static - tc.variables['unity'] = self.options.unity - tc.generate() - - def build(self): - cmake = CMake(self) - cmake.verbose = True - cmake.configure() - cmake.build() - - def package(self): - cmake = CMake(self) - cmake.verbose = True - cmake.install() - - def package_info(self): - self.cpp_info.libs = [ - 'libxrpl_core.a', - 'libed25519.a', - 'libsecp256k1.a', - ] diff --git a/conanfile.txt b/conanfile.txt new file mode 100644 index 0000000..e127d2f --- /dev/null +++ b/conanfile.txt @@ -0,0 +1,13 @@ +[requires] +fmt/10.1.1 +openssl/1.1.1u +xrpl/2.2.0-b2 +soci/4.0.3 + +[generators] +CMakeDeps +CMakeToolchain + +[options] +xrpl:tests=False +xrpl:rocksdb=False diff --git a/src/test/DB_test.cpp b/src/test/DB_test.cpp index 6285a1b..554f795 100644 --- a/src/test/DB_test.cpp +++ b/src/test/DB_test.cpp @@ -226,22 +226,15 @@ class DB_test : public beast::unit_test::suite auto session = db->checkoutDb(); - soci::blob amtBlob{*session}; - convert(amt, amtBlob); - soci::blob bridgeBlob(*session); - convert(bridge, bridgeBlob); - soci::blob sendingAccountBlob(*session); - convert(src, sendingAccountBlob); - soci::blob rewardAccountBlob(*session); - convert(rewAcc, rewardAccountBlob); - soci::blob signingAccountBlob(*session); - convert(claim.attestationSignerAccount, signingAccountBlob); - soci::blob publicKeyBlob(*session); - convert(signPub, publicKeyBlob); - soci::blob signatureBlob(*session); - convert(claim.signature, signatureBlob); - soci::blob otherChainDstBlob(*session); - convert(dst, otherChainDstBlob); + soci::blob amtBlob = convert(amt, *session); + soci::blob bridgeBlob = convert(bridge, *session); + soci::blob sendingAccountBlob = convert(src, *session); + soci::blob rewardAccountBlob = convert(rewAcc, *session); + soci::blob signingAccountBlob = + convert(claim.attestationSignerAccount, *session); + soci::blob publicKeyBlob = convert(signPub, *session); + soci::blob signatureBlob = convert(claim.signature, *session); + soci::blob otherChainDstBlob = convert(dst, *session); auto const sql = fmt::format( "INSERT INTO {} (TransID, LedgerSeq, ClaimID, Success, " @@ -306,23 +299,19 @@ class DB_test : public beast::unit_test::suite while (st.fetch()) { - ripple::AccountID locSignAcc; - convert(signingAccountBlob, locSignAcc); - ripple::PublicKey locSignPub; - convert(publicKeyBlob, locSignPub); - ripple::Buffer sigBuf; - convert(signatureBlob, sigBuf); - ripple::STAmount locAmt; - convert(amtBlob, locAmt, ripple::sfAmount); - ripple::AccountID locSrc; - convert(sendingAccountBlob, locSrc); - ripple::AccountID locRewAcc; - convert(rewardAccountBlob, locRewAcc); - ripple::AccountID locDst; + auto locSignAcc = + convert(signingAccountBlob); + auto locSignPub = convert(publicKeyBlob); + auto sigBuf = convert(signatureBlob); + auto locAmt = convert(amtBlob); + auto locSrc = + convert(sendingAccountBlob); + auto locRewAcc = + convert(rewardAccountBlob); + auto locDst = convert(otherChainDstBlob); BEAST_EXPECT(otherChainDstInd == soci::i_ok); - convert(otherChainDstBlob, locDst); - ripple::STXChainBridge locBridge; - convert(bridgeBlob, locBridge, ripple::sfXChainBridge); + auto locBridge = + convert(bridgeBlob); if (!BEAST_EXPECT(signAcc == locSignAcc)) return; @@ -395,24 +384,16 @@ class DB_test : public beast::unit_test::suite auto session = db->checkoutDb(); - soci::blob amtBlob{*session}; - convert(amt, amtBlob); - soci::blob rewardAmtBlob{*session}; - convert(rewAmt, rewardAmtBlob); - soci::blob bridgeBlob(*session); - convert(bridge, bridgeBlob); - soci::blob sendingAccountBlob(*session); - convert(src, sendingAccountBlob); - soci::blob rewardAccountBlob(*session); - convert(rewAcc, rewardAccountBlob); - soci::blob signingAccountBlob(*session); - convert(create.attestationSignerAccount, signingAccountBlob); - soci::blob publicKeyBlob(*session); - convert(signPub, publicKeyBlob); - soci::blob signatureBlob(*session); - convert(create.signature, signatureBlob); - soci::blob otherChainDstBlob(*session); - convert(dst, otherChainDstBlob); + soci::blob amtBlob = convert(amt, *session); + soci::blob rewardAmtBlob = convert(rewAmt, *session); + soci::blob bridgeBlob = convert(bridge, *session); + soci::blob sendingAccountBlob = convert(src, *session); + soci::blob rewardAccountBlob = convert(rewAcc, *session); + soci::blob signingAccountBlob = + convert(create.attestationSignerAccount, *session); + soci::blob publicKeyBlob = convert(signPub, *session); + soci::blob signatureBlob = convert(create.signature, *session); + soci::blob otherChainDstBlob = convert(dst, *session); auto const sql = fmt::format( "INSERT INTO {} " @@ -485,25 +466,20 @@ class DB_test : public beast::unit_test::suite while (st.fetch()) { - ripple::AccountID locSignAcc; - convert(signingAccountBlob, locSignAcc); - ripple::PublicKey locSignPub; - convert(publicKeyBlob, locSignPub); - ripple::Buffer sigBuf; - convert(signatureBlob, sigBuf); - ripple::STAmount locAmt; - convert(amtBlob, locAmt, ripple::sfAmount); - ripple::STAmount locRewAmt; - convert(rewardAmtBlob, locRewAmt, ripple::sfAmount); - ripple::AccountID locSrc; - convert(sendingAccountBlob, locSrc); - ripple::AccountID locRewAcc; - convert(rewardAccountBlob, locRewAcc); - ripple::AccountID locDst; + auto locSignAcc = + convert(signingAccountBlob); + auto locSignPub = convert(publicKeyBlob); + auto sigBuf = convert(signatureBlob); + auto locAmt = convert(amtBlob); + auto locRewAmt = convert(rewardAmtBlob); + auto locSrc = + convert(sendingAccountBlob); + auto locRewAcc = + convert(rewardAccountBlob); + auto locDst = convert(otherChainDstBlob); BEAST_EXPECT(otherChainDstInd == soci::i_ok); - convert(otherChainDstBlob, locDst); - ripple::STXChainBridge locBridge; - convert(bridgeBlob, locBridge, ripple::sfXChainBridge); + auto locBridge = + convert(bridgeBlob); if (!BEAST_EXPECT(signAcc == locSignAcc)) return; diff --git a/src/test/main_test.cpp b/src/test/main_test.cpp index 1977b1f..215818b 100644 --- a/src/test/main_test.cpp +++ b/src/test/main_test.cpp @@ -82,8 +82,7 @@ extern const char ledgerEntryIss[]; extern const char accTxLoc[]; extern const char accTxIss[]; -extern const char ledgerLoc1[]; -extern const char ledgerIss1[]; +extern const char ledgerAdvance[]; extern const char accTxLoc1[]; extern const char accTxLoc2[]; extern const char accInfoIss1[]; @@ -142,6 +141,7 @@ class engineLoc { std::atomic_bool clientInit_ = false; unsigned accTxCtr = 0; + unsigned closed_ledger = 5; public: Json::Value @@ -181,6 +181,7 @@ class engineLoc if (!clientInit_) { + DBG(std::cout << side() << " clientInit" << std::endl;) std::unique_lock l(gMcv); clientInit_ = true; gCv.notify_all(); @@ -192,19 +193,24 @@ class engineLoc Json::Value jv; Json::Reader().parse(s, jv); return jv; - }; + } bool clientInit() const { return clientInit_; - }; + } Json::Value - getNewLedger() const + getNewLedger() { + ++closed_ledger; Json::Value jv; - Json::Reader().parse(ledgerLoc1, jv); + Json::Reader().parse( + fmt::format( + fmt::runtime(prepForFmt(ledgerAdvance)), + "closed_ledger"_a = closed_ledger), + jv); return jv; } @@ -212,13 +218,19 @@ class engineLoc attSubmitted() const { return false; - }; + } bool blobOk() const { return false; - }; + } + + std::string + side() const + { + return "locking"; + } }; class engineIss @@ -228,6 +240,7 @@ class engineIss std::atomic_bool blobOk_ = false; unsigned accInfoCtr = 0; unsigned accTxCtr = 0; + unsigned closed_ledger = 4; public: Json::Value @@ -274,6 +287,7 @@ class engineIss if (!clientInit_) { + DBG(std::cout << side() << " clientInit" << std::endl;) std::unique_lock l(gMcv); clientInit_ = true; gCv.notify_all(); @@ -292,19 +306,24 @@ class engineIss Json::Value jv; Json::Reader().parse(s, jv); return jv; - }; + } bool clientInit() const { return clientInit_; - }; + } Json::Value - getNewLedger() const + getNewLedger() { + ++closed_ledger; Json::Value jv; - Json::Reader().parse(ledgerIss1, jv); + Json::Reader().parse( + fmt::format( + fmt::runtime(prepForFmt(ledgerAdvance)), + "closed_ledger"_a = closed_ledger), + jv); return jv; } @@ -312,13 +331,19 @@ class engineIss attSubmitted() const { return attSubmitted_; - }; + } bool blobOk() const { return blobOk_; - }; + } + + std::string + side() const + { + return "issuing"; + } }; //------------------------------------------------------------------------------ @@ -398,13 +423,24 @@ class session : public std::enable_shared_from_this> Json::Value jv; Json::Reader().parse( - static_cast(buffer_.data().data()), jv); + static_cast(buffer_.data().data()), jv); auto const jr = e_.process(jv); + + auto const method = jv[ripple::jss::method].asString(); + if (method == "ledger_entry") + { + t_.expires_after(1s); + t_.async_wait([this](const boost::system::error_code&) { + return this->sendNewLedger(); + }); + } + if (!clientInit_) { if (e_.clientInit()) { clientInit_ = true; + t_.expires_after(1s); t_.async_wait([this](const boost::system::error_code&) { return this->sendNewLedger(); }); @@ -465,7 +501,7 @@ class session : public std::enable_shared_from_this> void sendNewLedger() { - DBG(std::cout << "session::sendNewLedger()" << std::endl;) + DBG(std::cout << e_.side() << " session::sendNewLedger()" << std::endl;) auto const jv = e_.getNewLedger(); auto const s = to_string(jv); @@ -481,7 +517,7 @@ class session : public std::enable_shared_from_this> void onWriteNewLedger(boost::beast::error_code ec, std::size_t bytes_transferred) { - DBG(std::cout << "session::onWriteNewLedger(), ec:" << ec + DBG(std::cout << e_.side() << " session::onWriteNewLedger(), ec:" << ec << " bytes: " << bytes_transferred << std::endl;) boost::ignore_unused(bytes_transferred); if (ec == websocket::error::closed) @@ -494,13 +530,13 @@ class session : public std::enable_shared_from_this> attSubmitted() const { return e_.attSubmitted(); - }; + } bool blobOk() const { return e_.blobOk(); - }; + } }; //------------------------------------------------------------------------------ @@ -567,13 +603,13 @@ class listener : public std::enable_shared_from_this> bool attSubmitted() const { - return session_ ? session_->attSubmitted(): false; + return session_ ? session_->attSubmitted() : false; }; bool blobOk() const { - return session_ ? session_->blobOk(): false; + return session_ ? session_->blobOk() : false; }; private: @@ -677,7 +713,8 @@ struct Connection (serverIss_ ? serverIss_->clientInit() : false); } - bool checkAtt() const + bool + checkAtt() const { return (serverIss_ ? serverIss_->attSubmitted() : false) && (serverIss_ ? serverIss_->blobOk() : false); @@ -720,7 +757,7 @@ class Main_test : public beast::unit_test::suite gApp->start(); // wait till server send all the messages - wait_for(5s, [&c]() { + wait_for(7s, [&c]() { return c.clientInit(); } DBG_ARGS("Wait for App init")); BEAST_EXPECT(c.clientInit()); @@ -1357,7 +1394,7 @@ const char accTxLoc[] = R"str( "jsonrpc": "2.0", "result": { "account": "rL9vUaa9eBas32C5bgv4fEmHDfJr3oNd4D", - "ledger_index_max": 5, + "ledger_index_max": 6, "ledger_index_min": 2, "limit": 10, "transactions": [ @@ -1698,7 +1735,7 @@ const char accTxIss[] = R"str( "jsonrpc": "2.0", "result": { "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "ledger_index_max": 4, + "ledger_index_max": 5, "ledger_index_min": 2, "limit": 10, "transactions": [ @@ -1969,33 +2006,18 @@ const char accTxIss[] = R"str( } )str"; -const char ledgerLoc1[] = R"str( +const char ledgerAdvance[] = R"str( { "fee_base" : 10, "fee_ref" : 10, - "ledger_hash" : "614D49AAB66C02D6D190D101BA0BFBEB157A60D52ABF6547FBF4DA4B3324034D", - "ledger_index" : 7, - "ledger_time" : 752637130, + "ledger_hash" : "B66BEC6A8C3A3585880B37B600A88B0B280104DCC2F4CCB2DED9C605113FE13E", + "ledger_index" : `closed_ledger`, + "ledger_time" : 766541670, "reserve_base" : 10000000, "reserve_inc" : 2000000, "txn_count" : 1, "type" : "ledgerClosed", - "validated_ledgers" : "2-7" -} -)str"; - -const char ledgerIss1[] = R"str( -{ - "fee_base" : 10, - "fee_ref" : 10, - "ledger_hash" : "1BDC7FEDA9F41E30939D76D6BBD12ACE20CE36025CE879A303F0C434B17536DB", - "ledger_index" : 5, - "ledger_time" : 752637130, - "reserve_base" : 10000000, - "reserve_inc" : 2000000, - "txn_count" : 0, - "type" : "ledgerClosed", - "validated_ledgers" : "2-5" + "validated_ledgers" : "2-`closed_ledger`" } )str"; @@ -2184,8 +2206,8 @@ const char accTxIss1[] = R"str( "jsonrpc" : "2.0", "result" : { "account" : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", - "ledger_index_max" : 5, - "ledger_index_min" : 5, + "ledger_index_max" : 6, + "ledger_index_min" : 6, "limit" : 10, "transactions" : [], "validated" : true @@ -2202,8 +2224,8 @@ const char accTxIss2[] = R"str( "jsonrpc" : "2.0", "result" : { "account" : "rnscFKLtPLn9MnUZh8EHi2KEnJR6qcZXWg", - "ledger_index_max" : 5, - "ledger_index_min" : 5, + "ledger_index_max" : 6, + "ledger_index_min" : 6, "limit" : 10, "transactions" : [], "validated" : true diff --git a/src/xbwd/app/App.cpp b/src/xbwd/app/App.cpp index deb46b0..2a67d07 100644 --- a/src/xbwd/app/App.cpp +++ b/src/xbwd/app/App.cpp @@ -70,6 +70,9 @@ App::App( { // TODO initialize the public and secret keys + JLOG(j_.info()) << "Application starting. Version is " + << build_info::getVersionString(); + config_->rpcEndpoint = xbwd::rpc_call::addrToEndpoint( get_io_service(), config_->addrRpcEndpoint); config_->issuingChainConfig.chainIp = xbwd::rpc_call::addrToEndpoint( @@ -144,8 +147,6 @@ App::setup() void App::start() { - JLOG(j_.info()) << "Application starting. Version is " - << build_info::getVersionString(); if (federator_) federator_->start(); // TODO: unlockMainLoop should go away diff --git a/src/xbwd/app/BuildInfo.cpp b/src/xbwd/app/BuildInfo.cpp index 23a9a1b..0121988 100644 --- a/src/xbwd/app/BuildInfo.cpp +++ b/src/xbwd/app/BuildInfo.cpp @@ -36,7 +36,7 @@ namespace build_info { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "0.1.0" +char const* const versionString = "1.0.0" // clang-format on #if defined(DEBUG) || defined(SANITIZER) diff --git a/src/xbwd/app/Config.cpp b/src/xbwd/app/Config.cpp index 2923cbb..cdc8b2a 100644 --- a/src/xbwd/app/Config.cpp +++ b/src/xbwd/app/Config.cpp @@ -138,6 +138,7 @@ Config::Config(Json::Value const& jv) , adminConfig{jv.isMember("Admin") ? AdminConfig::make(jv["Admin"]) : std::nullopt} , maxAttToSend( jv.isMember("MaxAttToSend") ? jv["MaxAttToSend"].asUInt() : 200) + , txLimit(jv.isMember("TxLimit") ? jv["TxLimit"].asUInt() : 500) , logFile(jv.isMember("LogFile") ? jv["LogFile"].asString() : std::string()) , logLevel( jv.isMember("LogLevel") ? jv["LogLevel"].asString() : std::string()) diff --git a/src/xbwd/app/Config.h b/src/xbwd/app/Config.h index c59c1d5..2c60ab8 100644 --- a/src/xbwd/app/Config.h +++ b/src/xbwd/app/Config.h @@ -80,6 +80,8 @@ struct Config // 0 - no "window" std::uint32_t maxAttToSend = 0; + std::uint32_t txLimit = 500; + std::string logFile; std::string logLevel; bool logSilent; diff --git a/src/xbwd/app/main.cpp b/src/xbwd/app/main.cpp index 08a8eec..a68dbf0 100644 --- a/src/xbwd/app/main.cpp +++ b/src/xbwd/app/main.cpp @@ -127,8 +127,7 @@ main(int argc, char** argv) try { - std::unique_ptr config = [&]() -> auto - { + std::unique_ptr config = [&]() -> auto { auto const configFile = [&]() -> std::string { if (vm.count("conf")) return vm["conf"].as(); @@ -144,8 +143,7 @@ main(int argc, char** argv) if (!Json::Reader().parse(f, jv)) throw std::runtime_error("config file contains invalid json"); return std::make_unique(jv); - } - (); + }(); if (vm.count("silent")) { diff --git a/src/xbwd/client/ChainListener.cpp b/src/xbwd/client/ChainListener.cpp index 35703ff..2e24f23 100644 --- a/src/xbwd/client/ChainListener.cpp +++ b/src/xbwd/client/ChainListener.cpp @@ -54,6 +54,8 @@ ChainListener::ChainListener( std::optional submitAccount, std::weak_ptr&& federator, std::optional signAccount, + std::uint32_t txLimit, + std::uint32_t lastLedgerProcessed, beast::Journal j) : chainType_{chainType} , bridge_{sidechain} @@ -62,7 +64,9 @@ ChainListener::ChainListener( , federator_{std::move(federator)} , signAccount_(signAccount) , j_{j} + , txLimit_(txLimit) { + hp_.lastLedgerProcessed_ = lastLedgerProcessed; } void @@ -96,7 +100,7 @@ ChainListener::onConnect() // processed with transaction parsing. // account_tx present in the // Cycle, so there is no reconnect for it - self->wsClient_->reconnect(); + self->wsClient_->reconnect("Can't process Account Info"); return; } Json::Value params; @@ -123,13 +127,21 @@ ChainListener::onConnect() mainFlow](Json::Value const& msg) { if (!self->processSigningAccountInfo(msg)) { - self->wsClient_->reconnect(); + self->wsClient_->reconnect("Can't process Signing Account Info"); return; } mainFlow(); }; + // Clear on re-connect inRequest_ = false; + ledgerReqMax_ = 0; + ledgerProcessedDoor_ = 0; + ledgerProcessedSubmit_ = 0; + prevLedgerIndex_ = 0; + txnHistoryIndex_ = 0; + hp_.clear(); + if (signAccount_) { Json::Value params; @@ -350,6 +362,8 @@ ChainListener::processMessage(Json::Value const& msg) auto newLedgerEv = checkLedger(chainType_, msg); if (newLedgerEv) { + ledgerIndex_ = newLedgerEv->ledgerIndex_; + ledgerFee_ = newLedgerEv->fee_; pushEvent(std::move(*newLedgerEv)); processNewLedger(newLedgerEv->ledgerIndex_); return; @@ -671,7 +685,7 @@ processSignerListSetGeneral( if (msg.isMember("SignerQuorum")) { - unsigned const signerQuorum = msg["SignerQuorum"].asUInt(); + std::uint32_t const signerQuorum = msg["SignerQuorum"].asUInt(); if (!signerQuorum) return warn_ret("'SignerQuorum' is null"); } @@ -788,7 +802,11 @@ ChainListener::processAccountInfo(Json::Value const& msg) const } auto const& jslArray = jaccData[ripple::jss::signer_lists]; if (!jslArray.isArray() || jslArray.size() != 1) - return warn_ret("'signer_lists' isn't array of size 1"); + { + warn_ret("'signer_lists' isn't array of size 1"); + // empty array mean no signer_list, that's ok. + return jslArray.isArray() && !jslArray; + } auto opEntries = processSignerListSetGeneral( jslArray[0u], chainName, errTopic, j_); @@ -851,7 +869,7 @@ ChainListener::processServerInfo(Json::Value const& msg) std::uint32_t networkID = 0; auto checkNetworkID = [&jinfo, &networkID, this, warn_ret]() { if (!jinfo.isMember(ripple::jss::network_id)) - return warn_ret("'network_id' missed"); + return; auto const& jnetID = jinfo[ripple::jss::network_id]; if (!jnetID.isIntegral()) @@ -1113,8 +1131,9 @@ ChainListener::processAccountSet(Json::Value const& msg) const return warn_ret("'XXXFlag' missed"); bool const setFlag = msg.isMember(ripple::jss::SetFlag); - unsigned const flag = setFlag ? msg[ripple::jss::SetFlag].asUInt() - : msg[ripple::jss::ClearFlag].asUInt(); + std::uint32_t const flag = setFlag + ? msg[ripple::jss::SetFlag].asUInt() + : msg[ripple::jss::ClearFlag].asUInt(); if (flag != ripple::asfDisableMaster) return warn_ret("not 'asfDisableMaster' flag"); @@ -1393,6 +1412,18 @@ ChainListener::getSubmitProcessedLedger() const return ledgerProcessedSubmit_; } +std::uint32_t +ChainListener::getCurrentLedger() const +{ + return ledgerIndex_; +} + +std::uint32_t +ChainListener::getCurrentFee() const +{ + return ledgerFee_; +} + std::uint32_t ChainListener::getHistoryProcessedLedger() const { @@ -1404,6 +1435,9 @@ ChainListener::processAccountTx(Json::Value const& msg) { bool const requestContinue = processAccountTxHlp(msg); + if (hp_.state_ == HistoryProcessor::WAIT_CB) + hp_.state_ = HistoryProcessor::RETR_HISTORY; + if (hp_.state_ != HistoryProcessor::FINISHED) { if (hp_.stopHistory_) @@ -1475,8 +1509,10 @@ ChainListener::processAccountTxHlp(Json::Value const& msg) } // these should left the same during full account_tx + marker serie - unsigned const ledgerMax = result[ripple::jss::ledger_index_max].asUInt(); - unsigned const ledgerMin = result[ripple::jss::ledger_index_min].asUInt(); + std::uint32_t const ledgerMax = + result[ripple::jss::ledger_index_max].asUInt(); + std::uint32_t const ledgerMin = + result[ripple::jss::ledger_index_min].asUInt(); if ((hp_.state_ != HistoryProcessor::FINISHED) && ledgerMin && (ledgerMin <= hp_.toRequestLedger_)) @@ -1508,7 +1544,7 @@ ChainListener::processAccountTxHlp(Json::Value const& msg) auto const& transactions = result[ripple::jss::transactions]; bool const isMarker = result.isMember("marker"); - unsigned cnt = 0; + std::uint32_t cnt = 0; for (auto it = transactions.begin(); it != transactions.end(); ++it, ++cnt) { if ((hp_.state_ != HistoryProcessor::FINISHED) && hp_.stopHistory_) @@ -1618,6 +1654,24 @@ ChainListener::processAccountTxHlp(Json::Value const& msg) ledgerProcessedSubmit_ = ledgerMax; } + // if history finished, check if we reach lastProcessedLedger + if (!isMarker && (hp_.state_ != HistoryProcessor::FINISHED) && + !hp_.stopHistory_) + { + if (ledgerMin && (ledgerMin <= hp_.lastLedgerProcessed_)) + { + JLOGV( + j_.info(), + "Reach last processed ledger", + jv("chainType", chainName), + jv("finish_ledger", hp_.toRequestLedger_ + 1), + jv("ledgerMin", ledgerMin), + jv("lastLedgerProcessed", hp_.lastLedgerProcessed_)); + hp_.stopHistory_ = true; + pushEvent(event::EndOfHistory{chainType_}); + } + } + if (isMarker && ((hp_.state_ == HistoryProcessor::FINISHED) || !hp_.stopHistory_)) { @@ -1632,8 +1686,8 @@ ChainListener::processAccountTxHlp(Json::Value const& msg) void ChainListener::accountTx( std::string const& account, - unsigned ledger_min, - unsigned ledger_max, + std::uint32_t ledger_min, + std::uint32_t ledger_max, Json::Value const& marker) { inRequest_ = true; @@ -1678,7 +1732,7 @@ ChainListener::requestLedgers() } void -ChainListener::sendLedgerReq(unsigned cnt) +ChainListener::sendLedgerReq(std::uint32_t cnt) { auto const chainName = to_string(chainType_); @@ -1711,30 +1765,48 @@ ChainListener::sendLedgerReq(unsigned cnt) } void -ChainListener::processNewLedger(unsigned ledgerIdx) +ChainListener::initStartupLedger(std::uint32_t ledger) { - auto const doorAccStr = ripple::toBase58(bridge_.door(chainType_)); - - if (!hp_.startupLedger_) + if (hp_.startupLedger_ < ledger) { - hp_.startupLedger_ = ledgerIdx; - hp_.toRequestLedger_ = ledgerIdx - 1; + if (hp_.lastLedgerProcessed_ > ledger) + { + JLOGV( + j_.error(), + "New ledger less then processed ledger", + jv("chainType", to_string(chainType_)), + jv("newLedger", ledger), + jv("lastLedgerProcessed", hp_.lastLedgerProcessed_)); + throw std::runtime_error("New ledger less then processed ledger"); + } + + hp_.startupLedger_ = ledger; + hp_.toRequestLedger_ = ledger - 1; JLOGV( j_.info(), "Init startup ledger", jv("chainType", to_string(chainType_)), jv("startup_ledger", hp_.startupLedger_)); - if (!ledgerIdx) + if (!ledger) { JLOGV( j_.error(), "New ledger invalid idx", jv("chainType", to_string(chainType_)), - jv("ledgerIdx", ledgerIdx)); + jv("ledgerIdx", ledger)); throw std::runtime_error("New ledger invalid idx"); } } +} + +void +ChainListener::processNewLedger(std::uint32_t ledgerIdx) +{ + auto const doorAccStr = ripple::toBase58(bridge_.door(chainType_)); + + if (!hp_.startupLedger_) + initStartupLedger(ledgerIdx); if (hp_.state_ == HistoryProcessor::FINISHED) { @@ -1743,16 +1815,18 @@ ChainListener::processNewLedger(unsigned ledgerIdx) if (ledgerIdx > ledgerReqMax_) { - auto const ledgerReqMinDoor = ledgerProcessedDoor_ + auto ledgerReqMinDoor = ledgerProcessedDoor_ ? ledgerProcessedDoor_ + 1 : hp_.startupLedger_ + 1; + ledgerReqMinDoor = std::min(ledgerReqMinDoor, ledgerIdx); ledgerReqMax_ = ledgerIdx; accountTx(doorAccStr, ledgerReqMinDoor, ledgerReqMax_); if (!submitAccountStr_.empty()) { - auto const ledgerReqMinSub = ledgerProcessedSubmit_ + auto ledgerReqMinSub = ledgerProcessedSubmit_ ? ledgerProcessedSubmit_ + 1 : hp_.startupLedger_ + 1; + ledgerReqMinSub = std::min(ledgerReqMinSub, ledgerIdx); accountTx(submitAccountStr_, ledgerReqMinSub, ledgerReqMax_); } } @@ -1773,11 +1847,13 @@ ChainListener::processNewLedger(unsigned ledgerIdx) "History mode off, no bridge", jv("chainType", to_string(self->chainType_))); self->hp_.state_ = HistoryProcessor::FINISHED; + self->hp_.stopHistory_ = true; self->pushEvent(event::EndOfHistory{self->chainType_}); return; } + // request for accountTx on next "new ledger" event (in case + // bridge just created in the latest ledger) self->hp_.state_ = HistoryProcessor::RETR_HISTORY; - self->accountTx(doorAccStr, 0, self->hp_.startupLedger_); }; hp_.state_ = HistoryProcessor::WAIT_CB; @@ -1806,7 +1882,7 @@ ChainListener::processNewLedger(unsigned ledgerIdx) { self->accountTx( doorAccStr, - 0, + self->hp_.lastLedgerProcessed_, self->hp_.startupLedger_, self->hp_.marker_); } @@ -1816,10 +1892,16 @@ ChainListener::processNewLedger(unsigned ledgerIdx) break; } + case HistoryProcessor::RETR_HISTORY: { + // runs only once per initialization + hp_.state_ = HistoryProcessor::WAIT_CB; + // starts history from the latest ledger + initStartupLedger(ledgerIdx); + accountTx(doorAccStr, hp_.lastLedgerProcessed_, hp_.startupLedger_); + break; + } case HistoryProcessor::RETR_LEDGERS: [[fallthrough]]; - case HistoryProcessor::RETR_HISTORY: - [[fallthrough]]; case HistoryProcessor::WAIT_CB: [[fallthrough]]; default: diff --git a/src/xbwd/client/ChainListener.h b/src/xbwd/client/ChainListener.h index 4675ea7..282fd54 100644 --- a/src/xbwd/client/ChainListener.h +++ b/src/xbwd/client/ChainListener.h @@ -57,22 +57,26 @@ struct HistoryProcessor // Save last history request before requesting for ledgers Json::Value marker_; - unsigned accoutTxProcessed_ = 0; + std::uint32_t accoutTxProcessed_ = 0; // Ledger that divide transactions on historical and new - unsigned startupLedger_ = 0; + std::uint32_t startupLedger_ = 0; // Requesting ledgers in batch and check transactions after every batch - // request - unsigned const requestLedgerBatch_ = 100; - unsigned toRequestLedger_ = 0; + // request. Used only when history is not finished in 'normal' way. This + // means there are some gaps in the history. + std::uint32_t const requestLedgerBatch_ = 100; + std::uint32_t toRequestLedger_ = 0; // Minimal ledger validated by rippled. Retrieved from server_info - unsigned minValidatedLedger_ = 0; + std::uint32_t minValidatedLedger_ = 0; // History processed ledger std::atomic_uint ledgerProcessed_ = 0; + // last processed ledger from previous session + std::uint32_t lastLedgerProcessed_ = 0; + void clear(); }; @@ -95,21 +99,21 @@ class ChainListener : public std::enable_shared_from_this std::unordered_map GUARDED_BY(callbacksMtx_) callbacks_; - unsigned const minUserLedger_ = 3; + std::uint32_t const minUserLedger_ = 3; // Maximum transactions per one request for given account. - unsigned const txLimit_ = 10; + std::uint32_t const txLimit_ = 10; // accout_tx request can be divided into chunks (txLimit_ size) with // severeal requests. This flag do not allow other transactions request to // be started in the middle of current request. bool inRequest_ = false; // last ledger requested for new tx - unsigned ledgerReqMax_ = 0; + std::uint32_t ledgerReqMax_ = 0; // last ledger that was processed for Door account (in case of errors / // disconnects). Will be requested from the other thread. - std::atomic_uint ledgerProcessedDoor_ = 0; + std::atomic_uint32_t ledgerProcessedDoor_ = 0; // last ledger that was processed for Signing account (in case of errors / // disconnects) - std::atomic_uint ledgerProcessedSubmit_ = 0; + std::atomic_uint32_t ledgerProcessedSubmit_ = 0; // To determine ledger boundary acros consecutive requests for given // account. std::int32_t prevLedgerIndex_ = 0; @@ -117,6 +121,10 @@ class ChainListener : public std::enable_shared_from_this // account_history_tx_stream subscription. std::int32_t txnHistoryIndex_ = 0; + // current ledger info + std::atomic_uint32_t ledgerIndex_ = 0; + std::atomic_uint32_t ledgerFee_ = 0; + HistoryProcessor hp_; public: @@ -126,6 +134,8 @@ class ChainListener : public std::enable_shared_from_this std::optional submitAccount, std::weak_ptr&& federator, std::optional signAccount, + std::uint32_t txLimit, + std::uint32_t lastLedgerProcessed, beast::Journal j); ~ChainListener() = default; @@ -175,6 +185,12 @@ class ChainListener : public std::enable_shared_from_this std::uint32_t getHistoryProcessedLedger() const; + std::uint32_t + getCurrentLedger() const; + + std::uint32_t + getCurrentFee() const; + private: void onMessage(Json::Value const& msg) EXCLUDES(callbacksMtx_); @@ -217,7 +233,10 @@ class ChainListener : public std::enable_shared_from_this processBridgeReq(Json::Value const& msg) const; void - processNewLedger(unsigned ledger); + processNewLedger(std::uint32_t ledger); + + void + initStartupLedger(std::uint32_t ledger); template void @@ -226,8 +245,8 @@ class ChainListener : public std::enable_shared_from_this void accountTx( std::string const& account, - unsigned ledger_min = 0, - unsigned ledger_max = 0, + std::uint32_t ledger_min = 0, + std::uint32_t ledger_max = 0, Json::Value const& marker = Json::Value()); void @@ -237,7 +256,7 @@ class ChainListener : public std::enable_shared_from_this requestLedgers(); void - sendLedgerReq(unsigned cnt); + sendLedgerReq(std::uint32_t cnt); }; } // namespace xbwd diff --git a/src/xbwd/client/WebsocketClient.cpp b/src/xbwd/client/WebsocketClient.cpp index 0f893bb..53ec4fd 100644 --- a/src/xbwd/client/WebsocketClient.cpp +++ b/src/xbwd/client/WebsocketClient.cpp @@ -159,7 +159,7 @@ WebsocketClient::connect() jv("what", e.what()), jv("ip", ep_.address()), jv("port", ep_.port())); - reconnect(); + reconnect("exception in connection"); } } @@ -189,7 +189,7 @@ WebsocketClient::send( catch (...) { std::lock_guard l(shutdownM_); - reconnect(); + reconnect("exception at sending data"); } return id; } @@ -211,7 +211,7 @@ WebsocketClient::onReadMsg(error_code const& ec) peerClosed_ = true; std::lock_guard l(shutdownM_); - reconnect(); + reconnect("error reading data"); return; } @@ -228,10 +228,13 @@ WebsocketClient::onReadMsg(error_code const& ec) } void -WebsocketClient::reconnect() +WebsocketClient::reconnect(std::string_view reason) { if (isShutdown_) return; + + JLOGV(j_.info(), "WebsocketClient::reconnect()", jv("reason", reason)); + boost::system::error_code ecc; stream_.close(ecc); std::weak_ptr wptr = this->shared_from_this(); diff --git a/src/xbwd/client/WebsocketClient.h b/src/xbwd/client/WebsocketClient.h index b07d392..09f4a45 100644 --- a/src/xbwd/client/WebsocketClient.h +++ b/src/xbwd/client/WebsocketClient.h @@ -112,7 +112,7 @@ class WebsocketClient : public std::enable_shared_from_this shutdown() EXCLUDES(shutdownM_); void - reconnect() REQUIRES(shutdownM_); + reconnect(std::string_view reason) REQUIRES(shutdownM_); private: void diff --git a/src/xbwd/core/SociDB.cpp b/src/xbwd/core/SociDB.cpp index 7cf927a..ff31787 100644 --- a/src/xbwd/core/SociDB.cpp +++ b/src/xbwd/core/SociDB.cpp @@ -114,105 +114,73 @@ getKBUsedDB(soci::session& s) return 0; // Silence compiler warning. } -void -convert(soci::blob& from, std::vector& to) -{ - to.resize(from.get_len()); - if (to.empty()) - return; - from.read(0, reinterpret_cast(&to[0]), from.get_len()); -} - -void -convert(std::vector const& from, soci::blob& to) +soci::blob +convert(std::vector const& from, soci::session& s) { + soci::blob to(s); if (!from.empty()) to.write(0, reinterpret_cast(&from[0]), from.size()); else to.trim(0); + return to; } -void -convert(soci::blob& from, ripple::Buffer& to) -{ - to.alloc(from.get_len()); - if (to.empty()) - return; - from.read(0, reinterpret_cast(to.data()), from.get_len()); -} - -void -convert(ripple::Buffer const& from, soci::blob& to) +soci::blob +convert(ripple::Buffer const& from, soci::session& s) { + soci::blob to(s); if (!from.empty()) to.write(0, reinterpret_cast(from.data()), from.size()); else to.trim(0); + return to; } -void -convert(soci::blob& from, std::string& to) -{ - std::vector tmp; - convert(from, tmp); - to.assign(tmp.begin(), tmp.end()); -} - -void -convert(std::string const& from, soci::blob& to) +soci::blob +convert(std::string const& from, soci::session& s) { + soci::blob to(s); if (!from.empty()) to.write(0, from.data(), from.size()); else to.trim(0); + return to; } -void -convert(ripple::PublicKey const& from, soci::blob& to) +soci::blob +convert(ripple::PublicKey const& from, soci::session& s) { + soci::blob to(s); to.write(0, reinterpret_cast(from.data()), from.size()); + return to; } -void -convert(soci::blob& from, ripple::PublicKey& to) -{ - std::vector tmp; - convert(from, tmp); - to = ripple::PublicKey{ripple::makeSlice(tmp)}; -} - -void -convert(ripple::STAmount const& from, soci::blob& to) -{ - ripple::Serializer s; - from.add(s); - to.write(0, reinterpret_cast(s.data()), s.size()); -} - -void -convert(soci::blob& from, ripple::STAmount& to, ripple::SField const& f) +soci::blob +convert(ripple::STAmount const& from, soci::session& s) { - std::vector tmp; - convert(from, tmp); - ripple::SerialIter s(tmp.data(), tmp.size()); - to = ripple::STAmount{s, f}; + soci::blob to(s); + ripple::Serializer r; + from.add(r); + to.write(0, reinterpret_cast(r.data()), r.size()); + return to; } -void -convert(ripple::STXChainBridge const& from, soci::blob& to) +soci::blob +convert(ripple::STXChainBridge const& from, soci::session& s) { - ripple::Serializer s; - from.add(s); - to.write(0, reinterpret_cast(s.data()), s.size()); + soci::blob to(s); + ripple::Serializer r; + from.add(r); + to.write(0, reinterpret_cast(r.data()), r.size()); + return to; } -void -convert(soci::blob& from, ripple::STXChainBridge& to, ripple::SField const& f) +soci::blob +convert(ripple::AccountID const& from, soci::session& s) { - std::vector tmp; - convert(from, tmp); - ripple::SerialIter s(tmp.data(), tmp.size()); - to = ripple::STXChainBridge{s, f}; + soci::blob to(s); + to.write(0, reinterpret_cast(from.data()), from.size()); + return to; } } // namespace xbwd diff --git a/src/xbwd/core/SociDB.h b/src/xbwd/core/SociDB.h index 2bc0d0d..978352b 100644 --- a/src/xbwd/core/SociDB.h +++ b/src/xbwd/core/SociDB.h @@ -72,58 +72,94 @@ getKBUsedAll(soci::session& s); std::uint32_t getKBUsedDB(soci::session& s); -void -convert(soci::blob& from, std::vector& to); - -void -convert(std::vector const& from, soci::blob& to); - -void -convert(soci::blob& from, ripple::Buffer& to); - -void -convert(ripple::Buffer const& from, soci::blob& to); - -void -convert(soci::blob& from, std::string& to); +template +T +convert(soci::blob&); -void -convert(std::string const& from, soci::blob& to); - -void -convert(ripple::PublicKey const& from, soci::blob& to); - -void -convert(soci::blob& from, ripple::PublicKey& to); +template <> +inline std::vector +convert(soci::blob& from) +{ + std::vector to; + to.resize(from.get_len()); + if (to.empty()) + return to; + from.read(0, reinterpret_cast(&to[0]), from.get_len()); + return to; +} -void -convert(ripple::STAmount const& from, soci::blob& to); +template <> +inline ripple::Buffer +convert(soci::blob& from) +{ + ripple::Buffer to; + to.alloc(from.get_len()); + if (to.empty()) + return to; + from.read(0, reinterpret_cast(to.data()), from.get_len()); + return to; +} -void -convert(soci::blob& from, ripple::STAmount& to, ripple::SField const& f); +template <> +inline std::string +convert(soci::blob& from) +{ + auto tmp(convert>(from)); + return std::string(tmp.begin(), tmp.end()); +} -void -convert(ripple::STXChainBridge const& from, soci::blob& to); +template <> +inline ripple::PublicKey +convert(soci::blob& from) +{ + auto tmp(convert>(from)); + return ripple::PublicKey{ripple::makeSlice(tmp)}; +} -void -convert(soci::blob& from, ripple::STXChainBridge& to, ripple::SField const& f); +template <> +inline ripple::STAmount +convert(soci::blob& from) +{ + auto tmp(convert>(from)); + ripple::SerialIter s(tmp.data(), tmp.size()); + return ripple::STAmount{s, ripple::sfAmount}; +} -template -void -convert(soci::blob& from, ripple::base_uint& to) +template <> +inline ripple::STXChainBridge +convert(soci::blob& from) { - if (to.size() != from.get_len()) - throw std::runtime_error("Soci blob size mismatch"); - from.read(0, reinterpret_cast(to.data()), from.get_len()); + auto tmp(convert>(from)); + ripple::SerialIter s(tmp.data(), tmp.size()); + return ripple::STXChainBridge{s, ripple::sfXChainBridge}; } -template -void -convert(ripple::base_uint const& from, soci::blob& to) +template <> +inline ripple::AccountID +convert(soci::blob& from) { - to.write(0, reinterpret_cast(from.data()), from.size()); + ripple::AccountID a; + if (a.size() != from.get_len()) + throw std::runtime_error("Soci blob size mismatch"); + from.read(0, reinterpret_cast(a.data()), from.get_len()); + return a; } +soci::blob +convert(std::vector const& from, soci::session& s); +soci::blob +convert(ripple::Buffer const& from, soci::session& s); +soci::blob +convert(std::string const& from, soci::session& s); +soci::blob +convert(ripple::PublicKey const& from, soci::session& s); +soci::blob +convert(ripple::STAmount const& from, soci::session& s); +soci::blob +convert(ripple::STXChainBridge const& from, soci::session& s); +soci::blob +convert(ripple::AccountID const& from, soci::session& s); + } // namespace xbwd #if defined(__clang__) diff --git a/src/xbwd/federator/Federator.cpp b/src/xbwd/federator/Federator.cpp index c6deed7..b2a69d4 100644 --- a/src/xbwd/federator/Federator.cpp +++ b/src/xbwd/federator/Federator.cpp @@ -59,41 +59,7 @@ make_Federator( { auto r = std::make_shared( Federator::PrivateTag{}, app, config, l.journal("Federator")); - - auto getSubmitAccount = - [&](ChainType chainType) -> std::optional { - auto const& chainConfig = chainType == ChainType::locking - ? config.lockingChainConfig - : config.issuingChainConfig; - if (chainConfig.txnSubmit && chainConfig.txnSubmit->shouldSubmit) - { - return chainConfig.txnSubmit->submittingAccount; - } - return {}; - }; - - std::shared_ptr mainchainListener = - std::make_shared( - ChainType::locking, - config.bridge, - getSubmitAccount(ChainType::locking), - r, - config.signingAccount, - l.journal("LListener")); - std::shared_ptr sidechainListener = - std::make_shared( - ChainType::issuing, - config.bridge, - getSubmitAccount(ChainType::issuing), - r, - config.signingAccount, - l.journal("IListener")); - r->init( - ios, - config.lockingChainConfig.chainIp, - std::move(mainchainListener), - config.issuingChainConfig.chainIp, - std::move(sidechainListener)); + r->init(ios, config, l); return r; } @@ -117,9 +83,9 @@ Federator::Federator( chains_[ChainType::locking].txnSubmit_->shouldSubmit, chains_[ChainType::issuing].txnSubmit_ && chains_[ChainType::issuing].txnSubmit_->shouldSubmit} - , maxAttToSend_(config.maxAttToSend) - , keyType_{config.keyType} + , maxAttToSend_(config.maxAttToSend) , signingAccount_(config.signingAccount) + , keyType_{config.keyType} , signingPK_{derivePublicKey(config.keyType, config.signingKey)} , signingSK_{config.signingKey} , j_(j) @@ -137,10 +103,8 @@ Federator::Federator( void Federator::init( boost::asio::io_service& ios, - beast::IP::Endpoint const& mainchainIp, - std::shared_ptr&& mainchainListener, - beast::IP::Endpoint const& sidechainIp, - std::shared_ptr&& sidechainListener) + config::Config const& config, + ripple::Logs& l) { auto fillLastTxHash = [&]() -> bool { try @@ -251,6 +215,7 @@ Federator::init( j_.info(), "Prepare init sync", jv("chainType", to_string(ct)), + jv("autoSubmit", autoSubmit_[ct]), jv("DB ledgerSqn", initSync_[ct].dbLedgerSqn_), jv("DB txHash", initSync_[ct].dbTxnHash_), jv("config txHash", @@ -259,10 +224,46 @@ Federator::init( : std::string("not set"))); } + auto getSubmitAccount = + [&](ChainType chainType) -> std::optional { + auto const& chainConfig = chainType == ChainType::locking + ? config.lockingChainConfig + : config.issuingChainConfig; + if (autoSubmit_[chainType]) + { + return chainConfig.txnSubmit->submittingAccount; + } + return {}; + }; + + std::shared_ptr mainchainListener = + std::make_shared( + ChainType::locking, + config.bridge, + getSubmitAccount(ChainType::locking), + shared_from_this(), + config.signingAccount, + config.txLimit, + initSync_[ChainType::locking].dbLedgerSqn_, + l.journal("LListener")); + + std::shared_ptr sidechainListener = + std::make_shared( + ChainType::issuing, + config.bridge, + getSubmitAccount(ChainType::issuing), + shared_from_this(), + config.signingAccount, + config.txLimit, + initSync_[ChainType::issuing].dbLedgerSqn_, + l.journal("IListener")); + chains_[ChainType::locking].listener_ = std::move(mainchainListener); - chains_[ChainType::locking].listener_->init(ios, mainchainIp); + chains_[ChainType::locking].listener_->init( + ios, config.lockingChainConfig.chainIp); chains_[ChainType::issuing].listener_ = std::move(sidechainListener); - chains_[ChainType::issuing].listener_->init(ios, sidechainIp); + chains_[ChainType::issuing].listener_->init( + ios, config.issuingChainConfig.chainIp); } void @@ -321,31 +322,17 @@ Federator::readDBAttests(ChainType ct) while (st.fetch()) { - ripple::AccountID signingAccount; - convert(signingAccountBlob, signingAccount); - - ripple::PublicKey signingPK; - convert(publicKeyBlob, signingPK); - - ripple::Buffer sigBuf; - convert(signatureBlob, sigBuf); - - ripple::STAmount sendingAmount; - convert(amtBlob, sendingAmount, ripple::sfAmount); - - ripple::STAmount rewardAmount; - convert(rewardAmtBlob, rewardAmount, ripple::sfAmount); - - ripple::AccountID sendingAccount; - convert(sendingAccountBlob, sendingAccount); - - ripple::AccountID rewardAccount; - convert(rewardAccountBlob, rewardAccount); - - ripple::AccountID dstAccount; - convert(otherChainDstBlob, dstAccount); - - convert(bridgeBlob, bridge, ripple::sfXChainBridge); + auto signingAccount = + convert(signingAccountBlob); + auto signingPK = convert(publicKeyBlob); + auto sigBuf = convert(signatureBlob); + auto sendingAmount = convert(amtBlob); + auto rewardAmount = convert(rewardAmtBlob); + auto sendingAccount = + convert(sendingAccountBlob); + auto rewardAccount = convert(rewardAccountBlob); + auto dstAccount = convert(otherChainDstBlob); + auto bridge = convert(bridgeBlob); if (bridge != bridge_) { JLOGV( @@ -434,36 +421,25 @@ Federator::readDBAttests(ChainType ct) soci::into(signatureBlob)); st.execute(); - ripple::STXChainBridge bridge; - while (st.fetch()) { - ripple::AccountID signingAccount; - convert(signingAccountBlob, signingAccount); - - ripple::PublicKey signingPK; - convert(publicKeyBlob, signingPK); - - ripple::Buffer sigBuf; - convert(signatureBlob, sigBuf); - - ripple::STAmount sendingAmount; - convert(amtBlob, sendingAmount, ripple::sfAmount); - - ripple::AccountID sendingAccount; - convert(sendingAccountBlob, sendingAccount); - - ripple::AccountID rewardAccount; - convert(rewardAccountBlob, rewardAccount); + auto signingAccount = + convert(signingAccountBlob); + auto signingPK = convert(publicKeyBlob); + auto sigBuf = convert(signatureBlob); + auto sendingAmount = convert(amtBlob); + auto sendingAccount = + convert(sendingAccountBlob); + auto rewardAccount = convert(rewardAccountBlob); std::optional optDst; if (otherChainDstInd == soci::i_ok) { optDst.emplace(); - convert(otherChainDstBlob, *optDst); + *optDst = convert(otherChainDstBlob); } - convert(bridgeBlob, bridge, ripple::sfXChainBridge); + auto bridge = convert(bridgeBlob); if (bridge != bridge_) { JLOGV( @@ -692,7 +668,7 @@ Federator::tryFinishInitSync(ChainType const ct) { auto const ocht = otherChain(cht); auto& repl(replays_[cht]); - unsigned del_cnt = 0; + std::uint32_t del_cnt = 0; std::size_t const rel_size = repl.size(); for (auto it = repl.begin(); it != repl.end();) { @@ -724,6 +700,7 @@ Federator::tryFinishInitSync(ChainType const ct) repl.clear(); initSync_[cht].attestedTx_.clear(); } + syncFinished_ = true; } bool @@ -822,64 +799,27 @@ Federator::onEvent(event::XChainCommitDetected const& e) assert(!claimOpt || claimOpt->verify(e.bridge_)); - auto const encodedAmtOpt = - [&]() -> std::optional> { - if (!e.deliveredAmt_) - return std::nullopt; - ripple::Serializer s; - e.deliveredAmt_->add(s); - return std::move(s.modData()); - }(); - - std::vector const encodedBridge = [&] { - ripple::Serializer s; - bridge_.add(s); - return std::move(s.modData()); - }(); - { auto session = app_.getXChainTxnDB().checkoutDb(); // Soci blob does not play well with optional. Store an empty blob // when missing delivered amount - soci::blob amtBlob{*session}; - if (encodedAmtOpt) - { - convert(*encodedAmtOpt, amtBlob); - } - - soci::blob bridgeBlob(*session); - convert(encodedBridge, bridgeBlob); - - soci::blob sendingAccountBlob(*session); - // Convert to an AccountID first, because if the type changes we - // want to catch it. - ripple::AccountID const& sendingAccount{e.src_}; - convert(sendingAccount, sendingAccountBlob); - - soci::blob rewardAccountBlob(*session); - convert(rewardAccount, rewardAccountBlob); - - soci::blob signingAccountBlob(*session); - if (claimOpt) - { - convert(claimOpt->attestationSignerAccount, signingAccountBlob); - } - - soci::blob publicKeyBlob(*session); - convert(signingPK_, publicKeyBlob); - - soci::blob signatureBlob(*session); - if (claimOpt) - { - convert(claimOpt->signature, signatureBlob); - } - - soci::blob otherChainDstBlob(*session); - if (optDst) - { - convert(*optDst, otherChainDstBlob); - } + soci::blob amtBlob = e.deliveredAmt_ + ? convert(*e.deliveredAmt_, *session) + : soci::blob(*session); + soci::blob bridgeBlob = convert(bridge_, *session); + soci::blob sendingAccountBlob = + convert(ripple::AccountID(e.src_), *session); + soci::blob rewardAccountBlob = convert(rewardAccount, *session); + soci::blob signingAccountBlob = claimOpt + ? convert(claimOpt->attestationSignerAccount, *session) + : soci::blob(*session); + soci::blob publicKeyBlob = convert(signingPK_, *session); + soci::blob signatureBlob = claimOpt + ? convert(claimOpt->signature, *session) + : soci::blob(*session); + soci::blob otherChainDstBlob = + optDst ? convert(*optDst, *session) : soci::blob(*session); JLOGV( j_.trace(), @@ -1030,44 +970,24 @@ Federator::onEvent(event::XChainAccountCreateCommitDetected const& e) // Soci blob does not play well with optional. Store an empty blob when // missing delivered amount - soci::blob amtBlob{*session}; - if (e.deliveredAmt_) - { - convert(*e.deliveredAmt_, amtBlob); - } - - soci::blob rewardAmtBlob{*session}; - convert(e.rewardAmt_, rewardAmtBlob); - - soci::blob bridgeBlob(*session); - convert(bridge_, bridgeBlob); - - soci::blob sendingAccountBlob(*session); + soci::blob amtBlob = e.deliveredAmt_ + ? convert(*e.deliveredAmt_, *session) + : soci::blob(*session); + soci::blob rewardAmtBlob = convert(e.rewardAmt_, *session); + soci::blob bridgeBlob = convert(bridge_, *session); // Convert to an AccountID first, because if the type changes we want to // catch it. ripple::AccountID const& sendingAccount{e.src_}; - convert(sendingAccount, sendingAccountBlob); - - soci::blob rewardAccountBlob(*session); - convert(rewardAccount, rewardAccountBlob); - - soci::blob signingAccountBlob(*session); - if (createOpt) - { - convert(createOpt->attestationSignerAccount, signingAccountBlob); - } - - soci::blob publicKeyBlob(*session); - convert(signingPK_, publicKeyBlob); - - soci::blob signatureBlob(*session); - if (createOpt) - { - convert(createOpt->signature, signatureBlob); - } - - soci::blob otherChainDstBlob(*session); - convert(dst, otherChainDstBlob); + soci::blob sendingAccountBlob = convert(sendingAccount, *session); + soci::blob rewardAccountBlob = convert(rewardAccount, *session); + soci::blob signingAccountBlob = createOpt + ? convert(createOpt->attestationSignerAccount, *session) + : soci::blob(*session); + soci::blob publicKeyBlob = convert(signingPK_, *session); + soci::blob signatureBlob = createOpt + ? convert(createOpt->signature, *session) + : soci::blob(*session); + soci::blob otherChainDstBlob = convert(dst, *session); JLOGV( j_.trace(), @@ -1321,9 +1241,9 @@ void Federator::onEvent(event::NewLedger const& e) { auto const ct = e.chainType_; - unsigned const doorLedgerIndex = + std::uint32_t const doorLedgerIndex = chains_[ct].listener_->getDoorProcessedLedger(); - unsigned const submitLedgerIndex = + std::uint32_t const submitLedgerIndex = chains_[ct].listener_->getSubmitProcessedLedger(); JLOGV( @@ -1333,18 +1253,16 @@ Federator::onEvent(event::NewLedger const& e) jv("processedSubmitLedger", submitLedgerIndex), jv("event", e.toJson())); - auto const prevIdx = ledgerIndexes_[ct].exchange(e.ledgerIndex_); - ledgerFees_[ct].store(e.fee_); - // Fix TTL for tx from DB - if (!prevIdx) - { + [[maybe_unused]] static bool runOnce = [&]() { std::lock_guard l{txnsMutex_}; auto& subs = submitted_[ct]; for (auto& s : subs) if (!s->lastLedgerSeq_) - s->lastLedgerSeq_ = e.ledgerIndex_ + TxnTTLLedgers; - } + s->lastLedgerSeq_ = + chains_[ct].listener_->getCurrentLedger() + TxnTTLLedgers; + return true; + }(); // tryFinishInitSync checkProcessedLedger(ct); @@ -1352,8 +1270,11 @@ Federator::onEvent(event::NewLedger const& e) if (!autoSubmit_[ct] || isSyncing()) return; - saveProcessedLedger(ct, std::min(submitLedgerIndex, doorLedgerIndex)); - checkExpired(ct, submitLedgerIndex); + auto const x = + std::min(std::min(submitLedgerIndex, doorLedgerIndex), e.ledgerIndex_); + auto const minLedger = x ? x - 1 : 0; + saveProcessedLedger(ct, minLedger); + checkExpired(ct, minLedger); } void @@ -1383,7 +1304,7 @@ Federator::checkExpired(ChainType ct, std::uint32_t ledger) "Ledger TTL expired, move to errored", jv("chainType", to_string(ct)), jv("retries", - static_cast(front->retriesAllowed_)), + static_cast(front->retriesAllowed_)), jv("accSqn", front->accountSqn_), jv("lastLedger", front->lastLedgerSeq_), jv("tx", front->getJson())); @@ -1685,7 +1606,8 @@ Federator::submitTxn(SubmissionPtr&& submission, ChainType ct) // already verified txnSubmit before call submitTxn() config::TxnSubmit const& txnSubmit = *chains_[ct].txnSubmit_; - ripple::XRPAmount fee{ledgerFees_[ct].load() + FeeExtraDrops}; + ripple::XRPAmount fee{ + chains_[ct].listener_->getCurrentFee() + FeeExtraDrops}; ripple::STTx const toSubmit = submission->getSignedTxn(txnSubmit, fee, j_); auto const attestedIDs = submission->forAttestIDs(); @@ -1819,8 +1741,7 @@ Federator::txnSubmitLoop() ChainArray accountStrs; for (ChainType ct : {ChainType::locking, ChainType::issuing}) { - config::TxnSubmit const& txnSubmit = *chains_[ct].txnSubmit_; - if (chains_[ct].txnSubmit_ && chains_[ct].txnSubmit_->shouldSubmit) + if (autoSubmit_[ct]) accountStrs[ct] = ripple::toBase58(chains_[ct].txnSubmit_->submittingAccount); else @@ -1849,7 +1770,8 @@ Federator::txnSubmitLoop() // (!requestStop_)' loop will never stop. The loop will stop just before // shutdown and connections will be closed too, so callback will not fire. auto getReady = [&](ChainType chain) -> bool { - if (ledgerIndexes_[chain] == 0 || ledgerFees_[chain] == 0) + if (!chains_[chain].listener_->getCurrentLedger() || + !chains_[chain].listener_->getCurrentFee()) { JLOG(j_.trace()) << "Not ready, waiting for validated ledgers from stream"; @@ -1902,6 +1824,7 @@ Federator::txnSubmitLoop() return false; }; + std::uint32_t skipCtr = 0; while (!requestStop_) { bool waitForEvent = true; @@ -1951,7 +1874,10 @@ Federator::txnSubmitLoop() : 0) : pLocal->size(); if (!numToSend) + { + ++skipCtr; continue; + } if (pLocal->size() <= numToSend) localTxns.swap(*pLocal); @@ -1963,7 +1889,9 @@ Federator::txnSubmitLoop() jv("chainType", to_string(ct)), jv("waiting size", pLocal->size()), jv("window size", maxAttToSend_), - jv("send size", numToSend)); + jv("send size", numToSend), + jv("skipped iterations", skipCtr)); + skipCtr = 0; auto start = pLocal->begin(); auto finish = start + numToSend; @@ -1979,7 +1907,7 @@ Federator::txnSubmitLoop() for (auto& txn : localTxns) { auto const lastLedgerSeq = - ledgerIndexes_[ct].load() + TxnTTLLedgers; + chains_[ct].listener_->getCurrentLedger() + TxnTTLLedgers; txn->lastLedgerSeq_ = lastLedgerSeq; txn->accountSqn_ = accountSqns_[ct]++; submitTxn(std::move(txn), ct); @@ -2005,7 +1933,7 @@ Json::Value Federator::getInfo() const { // TODO - // Track transactons per secons + // Track transactions per seconds // Track when last transaction or event was submitted Json::Value ret{Json::objectValue}; { @@ -2029,9 +1957,9 @@ Federator::getInfo() const for (ChainType ct : {ChainType::locking, ChainType::issuing}) { Json::Value side{Json::objectValue}; - side["initiating"] = initSync_[ct].syncing_ ? "True" : "False"; - side["ledger_index"] = ledgerIndexes_[ct].load(); - side["fee"] = ledgerFees_[ct].load(); + side["initiating"] = !syncFinished_ ? "True" : "False"; + side["ledger_index"] = chains_[ct].listener_->getCurrentLedger(); + side["fee"] = chains_[ct].listener_->getCurrentFee(); int commitCount = 0; int createCount = 0; diff --git a/src/xbwd/federator/Federator.h b/src/xbwd/federator/Federator.h index 3ea9c2f..098a3be 100644 --- a/src/xbwd/federator/Federator.h +++ b/src/xbwd/federator/Federator.h @@ -359,14 +359,12 @@ class Federator : public std::enable_shared_from_this batchMutex_) curClaimAtts_; ChainArray> GUARDED_BY(batchMutex_) curCreateAtts_; - ChainArray ledgerIndexes_{0u, 0u}; - ChainArray ledgerFees_{0u, 0u}; ChainArray accountSqns_{0u, 0u}; // tx submit thread only struct InitSync { // Indicate that chain still processing history - std::atomic syncing_{true}; + std::atomic_bool syncing_{true}; // The hash of the latest event that require attestation from the // previous session. Saved at the event chain side. @@ -388,6 +386,9 @@ class Federator : public std::enable_shared_from_this }; ChainArray initSync_; + // flag show that sync is finished AND all historical transactions are + // already replayed + std::atomic_bool syncFinished_{false}; ChainArray> replays_; beast::Journal j_; @@ -460,10 +461,8 @@ class Federator : public std::enable_shared_from_this void init( boost::asio::io_service& ios, - beast::IP::Endpoint const& mainchainIp, - std::shared_ptr&& mainchainListener, - beast::IP::Endpoint const& sidechainIp, - std::shared_ptr&& sidechainListener); + config::Config const& config, + ripple::Logs& l); void mainLoop() EXCLUDES(mainLoopMutex_); diff --git a/src/xbwd/rpc/RPCHandler.cpp b/src/xbwd/rpc/RPCHandler.cpp index 32793e5..d41579c 100644 --- a/src/xbwd/rpc/RPCHandler.cpp +++ b/src/xbwd/rpc/RPCHandler.cpp @@ -106,36 +106,25 @@ doSelectAll( st.execute(); std::vector claims; - ripple::STXChainBridge bridge; std::optional firstBridge; while (st.fetch()) { - ripple::AccountID signingAccount; - convert(signingAccountBlob, signingAccount); - - ripple::PublicKey signingPK; - convert(publicKeyBlob, signingPK); - - ripple::Buffer sigBuf; - convert(signatureBlob, sigBuf); - - ripple::STAmount sendingAmount; - convert(amtBlob, sendingAmount, ripple::sfAmount); - - ripple::AccountID sendingAccount; - convert(sendingAccountBlob, sendingAccount); - - ripple::AccountID rewardAccount; - convert(rewardAccountBlob, rewardAccount); - + auto signingAccount = + convert(signingAccountBlob); + auto signingPK = convert(publicKeyBlob); + auto sigBuf = convert(signatureBlob); + auto sendingAmount = convert(amtBlob); + auto sendingAccount = + convert(sendingAccountBlob); + auto rewardAccount = convert(rewardAccountBlob); std::optional optDst; if (otherChainDstInd == soci::i_ok) { optDst.emplace(); - convert(otherChainDstBlob, *optDst); + *optDst = convert(otherChainDstBlob); } - convert(bridgeBlob, bridge, ripple::sfXChainBridge); + auto bridge = convert(bridgeBlob); if (!firstBridge) { firstBridge = bridge; @@ -162,7 +151,7 @@ doSelectAll( { #ifdef USE_BATCH_ATTESTATION ripple::STXChainAttestationBatch batch{ - bridge, claims.begin(), claims.end()}; + *firstBridge, claims.begin(), claims.end()}; result[ripple::sfXChainAttestationBatch.getJsonName()] = batch.getJson(ripple::JsonOptions::none); #else @@ -176,7 +165,7 @@ doSelectAll( auto& jclaims = (result["claims"] = Json::arrayValue); for (auto const& claim : claims) { - SubmissionClaim sc(0, 0, 0, bridge, claim); + SubmissionClaim sc(0, 0, 0, *firstBridge, claim); jclaims.append(sc.getJson(ripple::JsonOptions::none)); } } @@ -253,22 +242,19 @@ doWitness(App& app, Json::Value const& in, Json::Value& result) { auto session = app.getXChainTxnDB().checkoutDb(); - soci::blob amtBlob(*session); - soci::blob bridgeBlob(*session); - soci::blob sendingAccountBlob(*session); + soci::blob amtBlob = convert(sendingAmount, *session); + soci::blob bridgeBlob = convert(bridge, *session); + soci::blob sendingAccountBlob = convert(sendingAccount, *session); soci::blob rewardAccountBlob(*session); soci::blob otherChainDstBlob(*session); soci::blob signingAccountBlob(*session); soci::blob publicKeyBlob(*session); soci::blob signatureBlob(*session); - convert(sendingAmount, amtBlob); - convert(bridge, bridgeBlob); - convert(sendingAccount, sendingAccountBlob); soci::indicator sigInd; if (optDst) { - convert(*optDst, otherChainDstBlob); + otherChainDstBlob = convert(*optDst, *session); auto sql = fmt::format( R"sql(SELECT SigningAccount, Signature, PublicKey, RewardAccount FROM {table_name} @@ -310,7 +296,7 @@ doWitness(App& app, Json::Value const& in, Json::Value& result) if (otherChainDstInd == soci::i_ok) { optDst.emplace(); - convert(otherChainDstBlob, *optDst); + *optDst = convert(otherChainDstBlob); } } @@ -318,14 +304,11 @@ doWitness(App& app, Json::Value const& in, Json::Value& result) if (sigInd == soci::i_ok && publicKeyBlob.get_len() > 0 && rewardAccountBlob.get_len() > 0) { - ripple::AccountID rewardAccount; - convert(rewardAccountBlob, rewardAccount); - ripple::AccountID signingAccount; - convert(signingAccountBlob, signingAccount); - ripple::PublicKey signingPK; - convert(publicKeyBlob, signingPK); - ripple::Buffer sigBuf; - convert(signatureBlob, sigBuf); + auto rewardAccount = convert(rewardAccountBlob); + auto signingAccount = + convert(signingAccountBlob); + auto signingPK = convert(publicKeyBlob); + auto sigBuf = convert(signatureBlob); ripple::Attestations::AttestationClaim claim{ signingAccount, @@ -432,39 +415,14 @@ doWitnessAccountCreate(App& app, Json::Value const& in, Json::Value& result) auto const& tblName = db_init::xChainCreateAccountTableName(ct); - std::vector const encodedBridge = [&] { - ripple::Serializer s; - bridge.add(s); - return std::move(s.modData()); - }(); - - auto const encodedAmt = [&]() -> std::vector { - ripple::Serializer s; - sendingAmount.add(s); - return std::move(s.modData()); - }(); - auto const encodedRewardAmt = [&]() -> std::vector { - ripple::Serializer s; - rewardAmount.add(s); - return std::move(s.modData()); - }(); { auto session = app.getXChainTxnDB().checkoutDb(); - soci::blob amtBlob(*session); - convert(encodedAmt, amtBlob); - - soci::blob rewardAmtBlob(*session); - convert(encodedRewardAmt, rewardAmtBlob); - - soci::blob bridgeBlob(*session); - convert(encodedBridge, bridgeBlob); - - soci::blob sendingAccountBlob(*session); - convert(sendingAccount, sendingAccountBlob); - - soci::blob otherChainDstBlob(*session); - convert(dst, otherChainDstBlob); + soci::blob amtBlob = convert(sendingAmount, *session); + soci::blob rewardAmtBlob = convert(rewardAmount, *session); + soci::blob bridgeBlob = convert(bridge, *session); + soci::blob sendingAccountBlob = convert(sendingAccount, *session); + soci::blob otherChainDstBlob = convert(dst, *session); soci::blob rewardAccountBlob(*session); soci::blob signingAccountBlob(*session); @@ -493,14 +451,11 @@ doWitnessAccountCreate(App& app, Json::Value const& in, Json::Value& result) if (signatureBlob.get_len() > 0 && publicKeyBlob.get_len() > 0 && rewardAccountBlob.get_len() > 0) { - ripple::AccountID rewardAccount; - convert(rewardAccountBlob, rewardAccount); - ripple::AccountID signingAccount; - convert(signingAccountBlob, signingAccount); - ripple::PublicKey signingPK; - convert(publicKeyBlob, signingPK); - ripple::Buffer sigBuf; - convert(signatureBlob, sigBuf); + auto rewardAccount = convert(rewardAccountBlob); + auto signingAccount = + convert(signingAccountBlob); + auto signingPK = convert(publicKeyBlob); + auto sigBuf = convert(signatureBlob); ripple::Attestations::AttestationCreateAccount createAccount{ signingAccount, diff --git a/src/xbwd/rpc/ServerHandler.cpp b/src/xbwd/rpc/ServerHandler.cpp index 90e3a03..d269689 100644 --- a/src/xbwd/rpc/ServerHandler.cpp +++ b/src/xbwd/rpc/ServerHandler.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include