mirror of
				https://github.com/Xahau/xahaud.git
				synced 2025-11-04 10:45:50 +00:00 
			
		
		
		
	Add gRPC support (#3127):
* add support for AccountInfo, Fee and Submit RPCs * add partial support for Tx RPC (only supports Payments)
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -25,6 +25,9 @@ build
 | 
			
		||||
.nih_c
 | 
			
		||||
tags
 | 
			
		||||
TAGS
 | 
			
		||||
GTAGS
 | 
			
		||||
GRTAGS
 | 
			
		||||
GPATH
 | 
			
		||||
bin/rippled
 | 
			
		||||
Debug/*.*
 | 
			
		||||
Release/*.*
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ services:
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
  global:
 | 
			
		||||
    - DOCKER_IMAGE="mellery451/rippled-ci-builder:2019-08-26"
 | 
			
		||||
    - DOCKER_IMAGE="mellery451/rippled-ci-builder:2019-11-27_grpc"
 | 
			
		||||
    - CMAKE_EXTRA_ARGS="-Dwerr=ON -Dwextra=ON"
 | 
			
		||||
    - NINJA_BUILD=true
 | 
			
		||||
    # change this if we get more VM capacity
 | 
			
		||||
@@ -225,6 +225,8 @@ matrix:
 | 
			
		||||
      addons:
 | 
			
		||||
        homebrew:
 | 
			
		||||
          packages:
 | 
			
		||||
            - protobuf
 | 
			
		||||
            - grpc
 | 
			
		||||
            - bash
 | 
			
		||||
            - ninja
 | 
			
		||||
            - cmake
 | 
			
		||||
 
 | 
			
		||||
@@ -435,6 +435,7 @@ else ()
 | 
			
		||||
    src/ripple/app/main/Application.cpp
 | 
			
		||||
    src/ripple/app/main/BasicApp.cpp
 | 
			
		||||
    src/ripple/app/main/CollectorManager.cpp
 | 
			
		||||
    src/ripple/app/main/GRPCServer.cpp
 | 
			
		||||
    src/ripple/app/main/LoadManager.cpp
 | 
			
		||||
    src/ripple/app/main/Main.cpp
 | 
			
		||||
    src/ripple/app/main/NodeIdentity.cpp
 | 
			
		||||
@@ -969,6 +970,7 @@ else ()
 | 
			
		||||
    src/test/rpc/DepositAuthorized_test.cpp
 | 
			
		||||
    src/test/rpc/DeliveredAmount_test.cpp
 | 
			
		||||
    src/test/rpc/Feature_test.cpp
 | 
			
		||||
    src/test/rpc/Fee_test.cpp
 | 
			
		||||
    src/test/rpc/GatewayBalances_test.cpp
 | 
			
		||||
    src/test/rpc/GetCounts_test.cpp
 | 
			
		||||
    src/test/rpc/JSONRPC_test.cpp
 | 
			
		||||
@@ -987,10 +989,12 @@ else ()
 | 
			
		||||
    src/test/rpc/RobustTransaction_test.cpp
 | 
			
		||||
    src/test/rpc/ServerInfo_test.cpp
 | 
			
		||||
    src/test/rpc/Status_test.cpp
 | 
			
		||||
    src/test/rpc/Submit_test.cpp
 | 
			
		||||
    src/test/rpc/Subscribe_test.cpp
 | 
			
		||||
    src/test/rpc/Transaction_test.cpp
 | 
			
		||||
    src/test/rpc/TransactionEntry_test.cpp
 | 
			
		||||
    src/test/rpc/TransactionHistory_test.cpp
 | 
			
		||||
    src/test/rpc/Tx_test.cpp
 | 
			
		||||
    src/test/rpc/ValidatorRPC_test.cpp
 | 
			
		||||
    src/test/rpc/Version_test.cpp
 | 
			
		||||
    #[===============================[
 | 
			
		||||
@@ -1016,10 +1020,12 @@ target_link_libraries (rippled
 | 
			
		||||
  Ripple::boost
 | 
			
		||||
  Ripple::opts
 | 
			
		||||
  Ripple::libs
 | 
			
		||||
  Ripple::xrpl_core)
 | 
			
		||||
  Ripple::xrpl_core
 | 
			
		||||
  )
 | 
			
		||||
exclude_if_included (rippled)
 | 
			
		||||
# define a macro for tests that might need to
 | 
			
		||||
# be exluded or run differently in CI environment
 | 
			
		||||
if (is_ci)
 | 
			
		||||
  target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI)
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,9 @@ endif ()
 | 
			
		||||
option (jemalloc "Enables jemalloc for heap profiling" OFF)
 | 
			
		||||
option (werr "treat warnings as errors" OFF)
 | 
			
		||||
option (local_protobuf
 | 
			
		||||
  "Force use of a local build of protobuf instead of system version." OFF)
 | 
			
		||||
  "Force a local build of protobuf instead of looking for an installed version." OFF)
 | 
			
		||||
option (local_grpc
 | 
			
		||||
  "Force a local build of gRPC instead of looking for an installed version." OFF)
 | 
			
		||||
 | 
			
		||||
# this one is a string and therefore can't be an option
 | 
			
		||||
set (san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation")
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@
 | 
			
		||||
if (static)
 | 
			
		||||
  set (Protobuf_USE_STATIC_LIBS ON)
 | 
			
		||||
endif ()
 | 
			
		||||
find_package (Protobuf)
 | 
			
		||||
if (local_protobuf OR NOT TARGET protobuf::libprotobuf)
 | 
			
		||||
find_package (Protobuf 3.8)
 | 
			
		||||
if (local_protobuf OR NOT Protobuf_FOUND)
 | 
			
		||||
  message (STATUS "using local protobuf build.")
 | 
			
		||||
  if (WIN32)
 | 
			
		||||
    # protobuf prepends lib even on windows
 | 
			
		||||
@@ -25,11 +25,12 @@ if (local_protobuf OR NOT TARGET protobuf::libprotobuf)
 | 
			
		||||
  ExternalProject_Add (protobuf_src
 | 
			
		||||
    PREFIX ${nih_cache_path}
 | 
			
		||||
    GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
 | 
			
		||||
    GIT_TAG v3.6.1
 | 
			
		||||
    GIT_TAG v3.8.0
 | 
			
		||||
    SOURCE_SUBDIR cmake
 | 
			
		||||
    CMAKE_ARGS
 | 
			
		||||
      -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
 | 
			
		||||
      -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
 | 
			
		||||
      -DCMAKE_INSTALL_PREFIX=<BINARY_DIR>/_installed_
 | 
			
		||||
      -Dprotobuf_BUILD_TESTS=OFF
 | 
			
		||||
      -Dprotobuf_BUILD_EXAMPLES=OFF
 | 
			
		||||
      -Dprotobuf_BUILD_PROTOC_BINARIES=ON
 | 
			
		||||
@@ -51,51 +52,67 @@ if (local_protobuf OR NOT TARGET protobuf::libprotobuf)
 | 
			
		||||
      --build .
 | 
			
		||||
      --config $<CONFIG>
 | 
			
		||||
      $<$<VERSION_GREATER_EQUAL:${CMAKE_VERSION},3.12>:--parallel ${ep_procs}>
 | 
			
		||||
      $<$<BOOL:${is_multiconfig}>:
 | 
			
		||||
        COMMAND
 | 
			
		||||
          ${CMAKE_COMMAND} -E copy
 | 
			
		||||
          <BINARY_DIR>/$<CONFIG>/${pbuf_lib_pre}protobuf$<$<CONFIG:Debug>:_d>${ep_lib_suffix}
 | 
			
		||||
          <BINARY_DIR>
 | 
			
		||||
        COMMAND
 | 
			
		||||
          ${CMAKE_COMMAND} -E copy
 | 
			
		||||
          <BINARY_DIR>/$<CONFIG>/protoc${CMAKE_EXECUTABLE_SUFFIX}
 | 
			
		||||
          <BINARY_DIR>
 | 
			
		||||
        >
 | 
			
		||||
    TEST_COMMAND ""
 | 
			
		||||
    INSTALL_COMMAND ""
 | 
			
		||||
    INSTALL_COMMAND
 | 
			
		||||
      ${CMAKE_COMMAND} -E env --unset=DESTDIR ${CMAKE_COMMAND} --build . --config $<CONFIG> --target install
 | 
			
		||||
    BUILD_BYPRODUCTS
 | 
			
		||||
      <BINARY_DIR>/${pbuf_lib_pre}protobuf${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/${pbuf_lib_pre}protobuf_d${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/protoc${CMAKE_EXECUTABLE_SUFFIX}
 | 
			
		||||
      <BINARY_DIR>/_installed_/lib/${pbuf_lib_pre}protobuf${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/_installed_/lib/${pbuf_lib_pre}protobuf_d${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/_installed_/lib/${pbuf_lib_pre}protoc${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/_installed_/lib/${pbuf_lib_pre}protoc_d${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/_installed_/bin/protoc${CMAKE_EXECUTABLE_SUFFIX}
 | 
			
		||||
  )
 | 
			
		||||
  ExternalProject_Get_Property (protobuf_src BINARY_DIR)
 | 
			
		||||
  ExternalProject_Get_Property (protobuf_src SOURCE_DIR)
 | 
			
		||||
  if (CMAKE_VERBOSE_MAKEFILE)
 | 
			
		||||
    print_ep_logs (protobuf_src)
 | 
			
		||||
  endif ()
 | 
			
		||||
  exclude_if_included (protobuf_src)
 | 
			
		||||
 | 
			
		||||
  if (NOT TARGET protobuf::libprotobuf)
 | 
			
		||||
    add_library (protobuf::libprotobuf STATIC IMPORTED GLOBAL)
 | 
			
		||||
  endif ()
 | 
			
		||||
  file (MAKE_DIRECTORY ${SOURCE_DIR}/src)
 | 
			
		||||
  file (MAKE_DIRECTORY ${BINARY_DIR}/_installed_/include)
 | 
			
		||||
  set_target_properties (protobuf::libprotobuf PROPERTIES
 | 
			
		||||
    IMPORTED_LOCATION_DEBUG
 | 
			
		||||
      ${BINARY_DIR}/${pbuf_lib_pre}protobuf_d${ep_lib_suffix}
 | 
			
		||||
      ${BINARY_DIR}/_installed_/lib/${pbuf_lib_pre}protobuf_d${ep_lib_suffix}
 | 
			
		||||
    IMPORTED_LOCATION_RELEASE
 | 
			
		||||
      ${BINARY_DIR}/${pbuf_lib_pre}protobuf${ep_lib_suffix}
 | 
			
		||||
      ${BINARY_DIR}/_installed_/lib/${pbuf_lib_pre}protobuf${ep_lib_suffix}
 | 
			
		||||
    INTERFACE_INCLUDE_DIRECTORIES
 | 
			
		||||
      ${SOURCE_DIR}/src)
 | 
			
		||||
      ${BINARY_DIR}/_installed_/include)
 | 
			
		||||
  add_dependencies (protobuf::libprotobuf protobuf_src)
 | 
			
		||||
  exclude_if_included (protobuf_src)
 | 
			
		||||
  exclude_if_included (protobuf::libprotobuf)
 | 
			
		||||
 | 
			
		||||
  if (NOT TARGET protobuf::libprotoc)
 | 
			
		||||
    add_library (protobuf::libprotoc STATIC IMPORTED GLOBAL)
 | 
			
		||||
  endif ()
 | 
			
		||||
  set_target_properties (protobuf::libprotoc PROPERTIES
 | 
			
		||||
    IMPORTED_LOCATION_DEBUG
 | 
			
		||||
      ${BINARY_DIR}/_installed_/lib/${pbuf_lib_pre}protoc_d${ep_lib_suffix}
 | 
			
		||||
    IMPORTED_LOCATION_RELEASE
 | 
			
		||||
      ${BINARY_DIR}/_installed_/lib/${pbuf_lib_pre}protoc${ep_lib_suffix}
 | 
			
		||||
    INTERFACE_INCLUDE_DIRECTORIES
 | 
			
		||||
      ${BINARY_DIR}/_installed_/include)
 | 
			
		||||
  add_dependencies (protobuf::libprotoc protobuf_src)
 | 
			
		||||
  exclude_if_included (protobuf::libprotoc)
 | 
			
		||||
 | 
			
		||||
  if (NOT TARGET protobuf::protoc)
 | 
			
		||||
    add_executable (protobuf::protoc IMPORTED)
 | 
			
		||||
    exclude_if_included (protobuf::protoc)
 | 
			
		||||
  endif ()
 | 
			
		||||
  set_target_properties (protobuf::protoc PROPERTIES
 | 
			
		||||
    IMPORTED_LOCATION "${BINARY_DIR}/protoc${CMAKE_EXECUTABLE_SUFFIX}")
 | 
			
		||||
    IMPORTED_LOCATION "${BINARY_DIR}/_installed_/bin/protoc${CMAKE_EXECUTABLE_SUFFIX}")
 | 
			
		||||
  add_dependencies (protobuf::protoc protobuf_src)
 | 
			
		||||
else ()
 | 
			
		||||
  if (NOT TARGET protobuf::protoc)
 | 
			
		||||
    if (EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
 | 
			
		||||
      add_executable (protobuf::protoc IMPORTED)
 | 
			
		||||
      set_target_properties (protobuf::protoc PROPERTIES
 | 
			
		||||
        IMPORTED_LOCATION "${Protobuf_PROTOC_EXECUTABLE}")
 | 
			
		||||
    else ()
 | 
			
		||||
      message (FATAL_ERROR "Protobuf import failed")
 | 
			
		||||
    endif ()
 | 
			
		||||
  endif ()
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/proto_gen)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										343
									
								
								Builds/CMake/deps/gRPC.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								Builds/CMake/deps/gRPC.cmake
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,343 @@
 | 
			
		||||
 | 
			
		||||
# currently linking to unsecure versions...if we switch, we'll
 | 
			
		||||
# need to add ssl as a link dependency to the grpc targets
 | 
			
		||||
option (use_secure_grpc "use TLS version of grpc libs." OFF)
 | 
			
		||||
if (use_secure_grpc)
 | 
			
		||||
  set (grpc_suffix "")
 | 
			
		||||
else ()
 | 
			
		||||
  set (grpc_suffix "_unsecure")
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
find_package (PkgConfig QUIET)
 | 
			
		||||
if (PKG_CONFIG_FOUND)
 | 
			
		||||
  pkg_check_modules (grpc QUIET "grpc${grpc_suffix}>=1.25" "grpc++${grpc_suffix}" gpr)
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
if (grpc_FOUND)
 | 
			
		||||
  message (STATUS "Found gRPC using pkg-config. Using ${grpc_gpr_PREFIX}.")
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
add_executable (gRPC::grpc_cpp_plugin IMPORTED)
 | 
			
		||||
exclude_if_included (gRPC::grpc_cpp_plugin)
 | 
			
		||||
 | 
			
		||||
if (grpc_FOUND AND NOT local_grpc)
 | 
			
		||||
  # use installed grpc (via pkg-config)
 | 
			
		||||
  macro (add_imported_grpc libname_)
 | 
			
		||||
    if (static)
 | 
			
		||||
      set (_search "${CMAKE_STATIC_LIBRARY_PREFIX}${libname_}${CMAKE_STATIC_LIBRARY_SUFFIX}")
 | 
			
		||||
    else ()
 | 
			
		||||
      set (_search "${CMAKE_SHARED_LIBRARY_PREFIX}${libname_}${CMAKE_SHARED_LIBRARY_SUFFIX}")
 | 
			
		||||
    endif()
 | 
			
		||||
    find_library(_found_${libname_}
 | 
			
		||||
      NAMES ${_search}
 | 
			
		||||
      HINTS ${grpc_LIBRARY_DIRS})
 | 
			
		||||
    if (_found_${libname_})
 | 
			
		||||
      message (STATUS "importing ${libname_} as ${_found_${libname_}}")
 | 
			
		||||
    else ()
 | 
			
		||||
      message (FATAL_ERROR "using pkg-config for grpc, can't find ${_search}")
 | 
			
		||||
    endif ()
 | 
			
		||||
    add_library ("gRPC::${libname_}" STATIC IMPORTED GLOBAL)
 | 
			
		||||
    set_target_properties ("gRPC::${libname_}" PROPERTIES IMPORTED_LOCATION ${_found_${libname_}})
 | 
			
		||||
    if (grpc_INCLUDE_DIRS)
 | 
			
		||||
      set_target_properties ("gRPC::${libname_}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${grpc_INCLUDE_DIRS})
 | 
			
		||||
    endif ()
 | 
			
		||||
    target_link_libraries (ripple_libs INTERFACE "gRPC::${libname_}")
 | 
			
		||||
    exclude_if_included ("gRPC::${libname_}")
 | 
			
		||||
  endmacro ()
 | 
			
		||||
 | 
			
		||||
  set_target_properties (gRPC::grpc_cpp_plugin PROPERTIES
 | 
			
		||||
      IMPORTED_LOCATION "${grpc_gpr_PREFIX}/bin/grpc_cpp_plugin${CMAKE_EXECUTABLE_SUFFIX}")
 | 
			
		||||
 | 
			
		||||
  pkg_check_modules (cares QUIET libcares)
 | 
			
		||||
  if (cares_FOUND)
 | 
			
		||||
    if (static)
 | 
			
		||||
      set (_search "${CMAKE_STATIC_LIBRARY_PREFIX}cares${CMAKE_STATIC_LIBRARY_SUFFIX}")
 | 
			
		||||
    else ()
 | 
			
		||||
      set (_search "${CMAKE_SHARED_LIBRARY_PREFIX}cares${CMAKE_SHARED_LIBRARY_SUFFIX}")
 | 
			
		||||
    endif()
 | 
			
		||||
    find_library(_cares
 | 
			
		||||
      NAMES ${_search}
 | 
			
		||||
      HINTS ${cares_LIBRARY_DIRS})
 | 
			
		||||
    if (NOT _cares)
 | 
			
		||||
      message (FATAL_ERROR "using pkg-config for grpc, can't find c-ares")
 | 
			
		||||
    endif ()
 | 
			
		||||
    add_library (c-ares::cares STATIC IMPORTED GLOBAL)
 | 
			
		||||
    set_target_properties (c-ares::cares PROPERTIES IMPORTED_LOCATION ${_cares})
 | 
			
		||||
    if (cares_INCLUDE_DIRS)
 | 
			
		||||
      set_target_properties (c-ares::cares PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${cares_INCLUDE_DIRS})
 | 
			
		||||
    endif ()
 | 
			
		||||
    exclude_if_included (c-ares::cares)
 | 
			
		||||
  else ()
 | 
			
		||||
    message (FATAL_ERROR "using pkg-config for grpc, can't find c-ares")
 | 
			
		||||
  endif ()
 | 
			
		||||
else ()
 | 
			
		||||
  #[===========================[
 | 
			
		||||
     c-ares (grpc requires)
 | 
			
		||||
  #]===========================]
 | 
			
		||||
  ExternalProject_Add (c-ares_src
 | 
			
		||||
    PREFIX ${nih_cache_path}
 | 
			
		||||
    GIT_REPOSITORY https://github.com/c-ares/c-ares.git
 | 
			
		||||
    GIT_TAG cares-1_15_0
 | 
			
		||||
    CMAKE_ARGS
 | 
			
		||||
      -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
 | 
			
		||||
      $<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:-DCMAKE_VERBOSE_MAKEFILE=ON>
 | 
			
		||||
      -DCMAKE_DEBUG_POSTFIX=_d
 | 
			
		||||
      $<$<NOT:$<BOOL:${is_multiconfig}>>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}>
 | 
			
		||||
      -DCMAKE_INSTALL_PREFIX=<BINARY_DIR>/_installed_
 | 
			
		||||
      -DCARES_SHARED=OFF
 | 
			
		||||
      -DCARES_STATIC=ON
 | 
			
		||||
      -DCARES_STATIC_PIC=ON
 | 
			
		||||
      -DCARES_INSTALL=ON
 | 
			
		||||
      -DCARES_MSVC_STATIC_RUNTIME=ON
 | 
			
		||||
      $<$<BOOL:${MSVC}>:
 | 
			
		||||
        "-DCMAKE_C_FLAGS=-GR -Gd -fp:precise -FS -MP"
 | 
			
		||||
      >
 | 
			
		||||
    LOG_BUILD ON
 | 
			
		||||
    LOG_CONFIGURE ON
 | 
			
		||||
    BUILD_COMMAND
 | 
			
		||||
      ${CMAKE_COMMAND}
 | 
			
		||||
        --build .
 | 
			
		||||
        --config $<CONFIG>
 | 
			
		||||
        $<$<VERSION_GREATER_EQUAL:${CMAKE_VERSION},3.12>:--parallel ${ep_procs}>
 | 
			
		||||
    TEST_COMMAND ""
 | 
			
		||||
    INSTALL_COMMAND
 | 
			
		||||
      ${CMAKE_COMMAND} -E env --unset=DESTDIR ${CMAKE_COMMAND} --build . --config $<CONFIG> --target install
 | 
			
		||||
    BUILD_BYPRODUCTS
 | 
			
		||||
      <BINARY_DIR>/_installed_/lib/${ep_lib_prefix}cares${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/_installed_/lib/${ep_lib_prefix}cares_d${ep_lib_suffix}
 | 
			
		||||
  )
 | 
			
		||||
  exclude_if_included (c-ares_src)
 | 
			
		||||
  ExternalProject_Get_Property (c-ares_src BINARY_DIR)
 | 
			
		||||
  set (cares_binary_dir "${BINARY_DIR}")
 | 
			
		||||
 | 
			
		||||
  add_library (c-ares::cares STATIC IMPORTED GLOBAL)
 | 
			
		||||
  file (MAKE_DIRECTORY ${BINARY_DIR}/_installed_/include)
 | 
			
		||||
  set_target_properties (c-ares::cares PROPERTIES
 | 
			
		||||
    IMPORTED_LOCATION_DEBUG
 | 
			
		||||
      ${BINARY_DIR}/_installed_/lib/${ep_lib_prefix}cares_d${ep_lib_suffix}
 | 
			
		||||
    IMPORTED_LOCATION_RELEASE
 | 
			
		||||
      ${BINARY_DIR}/_installed_/lib/${ep_lib_prefix}cares${ep_lib_suffix}
 | 
			
		||||
    INTERFACE_INCLUDE_DIRECTORIES
 | 
			
		||||
      ${BINARY_DIR}/_installed_/include)
 | 
			
		||||
  add_dependencies (c-ares::cares c-ares_src)
 | 
			
		||||
  exclude_if_included (c-ares::cares)
 | 
			
		||||
 | 
			
		||||
  if (NOT has_zlib)
 | 
			
		||||
    #[===========================[
 | 
			
		||||
       zlib (grpc requires)
 | 
			
		||||
    #]===========================]
 | 
			
		||||
    if (MSVC)
 | 
			
		||||
      set (zlib_debug_postfix "d") # zlib cmake sets this internally for MSVC, so we really don't have a choice
 | 
			
		||||
      set (zlib_base "zlibstatic")
 | 
			
		||||
    else ()
 | 
			
		||||
      set (zlib_debug_postfix "_d")
 | 
			
		||||
      set (zlib_base "z")
 | 
			
		||||
    endif ()
 | 
			
		||||
    ExternalProject_Add (zlib_src
 | 
			
		||||
      PREFIX ${nih_cache_path}
 | 
			
		||||
      GIT_REPOSITORY https://github.com/madler/zlib.git
 | 
			
		||||
      GIT_TAG v1.2.11
 | 
			
		||||
      CMAKE_ARGS
 | 
			
		||||
        -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
 | 
			
		||||
        $<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:-DCMAKE_VERBOSE_MAKEFILE=ON>
 | 
			
		||||
        -DCMAKE_DEBUG_POSTFIX=${zlib_debug_postfix}
 | 
			
		||||
        $<$<NOT:$<BOOL:${is_multiconfig}>>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}>
 | 
			
		||||
        -DCMAKE_INSTALL_PREFIX=<BINARY_DIR>/_installed_
 | 
			
		||||
        -DBUILD_SHARED_LIBS=OFF
 | 
			
		||||
        $<$<BOOL:${MSVC}>:
 | 
			
		||||
          "-DCMAKE_C_FLAGS=-GR -Gd -fp:precise -FS -MP"
 | 
			
		||||
          "-DCMAKE_C_FLAGS_DEBUG=-MTd"
 | 
			
		||||
          "-DCMAKE_C_FLAGS_RELEASE=-MT"
 | 
			
		||||
        >
 | 
			
		||||
      LOG_BUILD ON
 | 
			
		||||
      LOG_CONFIGURE ON
 | 
			
		||||
      BUILD_COMMAND
 | 
			
		||||
        ${CMAKE_COMMAND}
 | 
			
		||||
          --build .
 | 
			
		||||
          --config $<CONFIG>
 | 
			
		||||
          $<$<VERSION_GREATER_EQUAL:${CMAKE_VERSION},3.12>:--parallel ${ep_procs}>
 | 
			
		||||
      TEST_COMMAND ""
 | 
			
		||||
      INSTALL_COMMAND
 | 
			
		||||
        ${CMAKE_COMMAND} -E env --unset=DESTDIR ${CMAKE_COMMAND} --build . --config $<CONFIG> --target install
 | 
			
		||||
      BUILD_BYPRODUCTS
 | 
			
		||||
        <BINARY_DIR>/_installed_/lib/${ep_lib_prefix}${zlib_base}${ep_lib_suffix}
 | 
			
		||||
        <BINARY_DIR>/_installed_/lib/${ep_lib_prefix}${zlib_base}${zlib_debug_postfix}${ep_lib_suffix}
 | 
			
		||||
    )
 | 
			
		||||
    exclude_if_included (zlib_src)
 | 
			
		||||
    ExternalProject_Get_Property (zlib_src BINARY_DIR)
 | 
			
		||||
    set (zlib_binary_dir "${BINARY_DIR}")
 | 
			
		||||
 | 
			
		||||
    add_library (ZLIB::ZLIB STATIC IMPORTED GLOBAL)
 | 
			
		||||
    file (MAKE_DIRECTORY ${BINARY_DIR}/_installed_/include)
 | 
			
		||||
    set_target_properties (ZLIB::ZLIB PROPERTIES
 | 
			
		||||
      IMPORTED_LOCATION_DEBUG
 | 
			
		||||
        ${BINARY_DIR}/_installed_/lib/${ep_lib_prefix}${zlib_base}${zlib_debug_postfix}${ep_lib_suffix}
 | 
			
		||||
      IMPORTED_LOCATION_RELEASE
 | 
			
		||||
        ${BINARY_DIR}/_installed_/lib/${ep_lib_prefix}${zlib_base}${ep_lib_suffix}
 | 
			
		||||
      INTERFACE_INCLUDE_DIRECTORIES
 | 
			
		||||
        ${BINARY_DIR}/_installed_/include)
 | 
			
		||||
    add_dependencies (ZLIB::ZLIB zlib_src)
 | 
			
		||||
    exclude_if_included (ZLIB::ZLIB)
 | 
			
		||||
  endif ()
 | 
			
		||||
 | 
			
		||||
  #[===========================[
 | 
			
		||||
     grpc
 | 
			
		||||
  #]===========================]
 | 
			
		||||
  ExternalProject_Add (grpc_src
 | 
			
		||||
    PREFIX ${nih_cache_path}
 | 
			
		||||
    GIT_REPOSITORY https://github.com/grpc/grpc.git
 | 
			
		||||
    GIT_TAG v1.25.0
 | 
			
		||||
    CMAKE_ARGS
 | 
			
		||||
      -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
 | 
			
		||||
      -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
 | 
			
		||||
      $<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:-DCMAKE_VERBOSE_MAKEFILE=ON>
 | 
			
		||||
      $<$<BOOL:${CMAKE_TOOLCHAIN_FILE}>:-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}>
 | 
			
		||||
      $<$<BOOL:${VCPKG_TARGET_TRIPLET}>:-DVCPKG_TARGET_TRIPLET=${VCPKG_TARGET_TRIPLET}>
 | 
			
		||||
      -DCMAKE_DEBUG_POSTFIX=_d
 | 
			
		||||
      $<$<NOT:$<BOOL:${is_multiconfig}>>:-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}>
 | 
			
		||||
      -DgRPC_BUILD_TESTS=OFF
 | 
			
		||||
      -DgRPC_BUILD_CSHARP_EXT=OFF
 | 
			
		||||
      -DgRPC_MSVC_STATIC_RUNTIME=ON
 | 
			
		||||
      -DgRPC_INSTALL=OFF
 | 
			
		||||
      -DgRPC_CARES_PROVIDER=package
 | 
			
		||||
      -Dc-ares_DIR=${cares_binary_dir}/_installed_/lib/cmake/c-ares
 | 
			
		||||
      -DgRPC_SSL_PROVIDER=package
 | 
			
		||||
      -DOPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR}
 | 
			
		||||
      -DgRPC_PROTOBUF_PROVIDER=package
 | 
			
		||||
      -DProtobuf_USE_STATIC_LIBS=$<IF:$<AND:$<BOOL:${Protobuf_FOUND}>,$<NOT:$<BOOL:${static}>>>,OFF,ON>
 | 
			
		||||
      -DProtobuf_INCLUDE_DIR=$<JOIN:$<TARGET_PROPERTY:protobuf::libprotobuf,INTERFACE_INCLUDE_DIRECTORIES>,:_:>
 | 
			
		||||
      -DProtobuf_LIBRARY=$<IF:$<CONFIG:Debug>,$<TARGET_PROPERTY:protobuf::libprotobuf,IMPORTED_LOCATION_DEBUG>,$<TARGET_PROPERTY:protobuf::libprotobuf,IMPORTED_LOCATION_RELEASE>>
 | 
			
		||||
      -DProtobuf_PROTOC_LIBRARY=$<IF:$<CONFIG:Debug>,$<TARGET_PROPERTY:protobuf::libprotoc,IMPORTED_LOCATION_DEBUG>,$<TARGET_PROPERTY:protobuf::libprotoc,IMPORTED_LOCATION_RELEASE>>
 | 
			
		||||
      -DProtobuf_PROTOC_EXECUTABLE=$<TARGET_PROPERTY:protobuf::protoc,IMPORTED_LOCATION>
 | 
			
		||||
      -DgRPC_ZLIB_PROVIDER=package
 | 
			
		||||
      $<$<NOT:$<BOOL:${has_zlib}>>:-DZLIB_ROOT=${zlib_binary_dir}/_installed_>
 | 
			
		||||
      $<$<BOOL:${MSVC}>:
 | 
			
		||||
        "-DCMAKE_CXX_FLAGS=-GR -Gd -fp:precise -FS -EHa -MP"
 | 
			
		||||
        "-DCMAKE_C_FLAGS=-GR -Gd -fp:precise -FS -MP"
 | 
			
		||||
      >
 | 
			
		||||
    LOG_BUILD ON
 | 
			
		||||
    LOG_CONFIGURE ON
 | 
			
		||||
    BUILD_COMMAND
 | 
			
		||||
      ${CMAKE_COMMAND}
 | 
			
		||||
      --build .
 | 
			
		||||
      --config $<CONFIG>
 | 
			
		||||
      $<$<VERSION_GREATER_EQUAL:${CMAKE_VERSION},3.12>:--parallel ${ep_procs}>
 | 
			
		||||
      $<$<BOOL:${is_multiconfig}>:
 | 
			
		||||
        COMMAND
 | 
			
		||||
          ${CMAKE_COMMAND} -E copy
 | 
			
		||||
          <BINARY_DIR>/$<CONFIG>/${ep_lib_prefix}grpc${grpc_suffix}$<$<CONFIG:Debug>:_d>${ep_lib_suffix}
 | 
			
		||||
          <BINARY_DIR>/$<CONFIG>/${ep_lib_prefix}grpc++${grpc_suffix}$<$<CONFIG:Debug>:_d>${ep_lib_suffix}
 | 
			
		||||
          <BINARY_DIR>/$<CONFIG>/${ep_lib_prefix}address_sorting$<$<CONFIG:Debug>:_d>${ep_lib_suffix}
 | 
			
		||||
          <BINARY_DIR>/$<CONFIG>/${ep_lib_prefix}gpr$<$<CONFIG:Debug>:_d>${ep_lib_suffix}
 | 
			
		||||
          <BINARY_DIR>/$<CONFIG>/grpc_cpp_plugin${CMAKE_EXECUTABLE_SUFFIX}
 | 
			
		||||
          <BINARY_DIR>
 | 
			
		||||
        >
 | 
			
		||||
    LIST_SEPARATOR :_:
 | 
			
		||||
    TEST_COMMAND ""
 | 
			
		||||
    INSTALL_COMMAND ""
 | 
			
		||||
    DEPENDS c-ares_src
 | 
			
		||||
    BUILD_BYPRODUCTS
 | 
			
		||||
      <BINARY_DIR>/${ep_lib_prefix}grpc${grpc_suffix}${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/${ep_lib_prefix}grpc${grpc_suffix}_d${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/${ep_lib_prefix}grpc++${grpc_suffix}${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/${ep_lib_prefix}grpc++${grpc_suffix}_d${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/${ep_lib_prefix}address_sorting${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/${ep_lib_prefix}address_sorting_d${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/${ep_lib_prefix}gpr${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/${ep_lib_prefix}gpr_d${ep_lib_suffix}
 | 
			
		||||
      <BINARY_DIR>/grpc_cpp_plugin${CMAKE_EXECUTABLE_SUFFIX}
 | 
			
		||||
  )
 | 
			
		||||
  if (TARGET protobuf_src)
 | 
			
		||||
    ExternalProject_Add_StepDependencies(grpc_src build protobuf_src)
 | 
			
		||||
  endif ()
 | 
			
		||||
  exclude_if_included (grpc_src)
 | 
			
		||||
  ExternalProject_Get_Property (grpc_src BINARY_DIR)
 | 
			
		||||
  ExternalProject_Get_Property (grpc_src SOURCE_DIR)
 | 
			
		||||
  set (grpc_binary_dir "${BINARY_DIR}")
 | 
			
		||||
  set (grpc_source_dir "${SOURCE_DIR}")
 | 
			
		||||
  if (CMAKE_VERBOSE_MAKEFILE)
 | 
			
		||||
    print_ep_logs (grpc_src)
 | 
			
		||||
  endif ()
 | 
			
		||||
  file (MAKE_DIRECTORY ${SOURCE_DIR}/include)
 | 
			
		||||
 | 
			
		||||
  macro (add_imported_grpc libname_)
 | 
			
		||||
    add_library ("gRPC::${libname_}" STATIC IMPORTED GLOBAL)
 | 
			
		||||
    set_target_properties ("gRPC::${libname_}" PROPERTIES
 | 
			
		||||
      IMPORTED_LOCATION_DEBUG
 | 
			
		||||
        ${grpc_binary_dir}/${ep_lib_prefix}${libname_}_d${ep_lib_suffix}
 | 
			
		||||
      IMPORTED_LOCATION_RELEASE
 | 
			
		||||
        ${grpc_binary_dir}/${ep_lib_prefix}${libname_}${ep_lib_suffix}
 | 
			
		||||
      INTERFACE_INCLUDE_DIRECTORIES
 | 
			
		||||
        ${grpc_source_dir}/include)
 | 
			
		||||
    add_dependencies ("gRPC::${libname_}" grpc_src)
 | 
			
		||||
    target_link_libraries (ripple_libs INTERFACE "gRPC::${libname_}")
 | 
			
		||||
    exclude_if_included ("gRPC::${libname_}")
 | 
			
		||||
  endmacro ()
 | 
			
		||||
 | 
			
		||||
  set_target_properties (gRPC::grpc_cpp_plugin PROPERTIES
 | 
			
		||||
      IMPORTED_LOCATION "${grpc_binary_dir}/grpc_cpp_plugin${CMAKE_EXECUTABLE_SUFFIX}")
 | 
			
		||||
  add_dependencies (gRPC::grpc_cpp_plugin grpc_src)
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
add_imported_grpc (gpr)
 | 
			
		||||
add_imported_grpc ("grpc${grpc_suffix}")
 | 
			
		||||
add_imported_grpc ("grpc++${grpc_suffix}")
 | 
			
		||||
add_imported_grpc (address_sorting)
 | 
			
		||||
 | 
			
		||||
target_link_libraries ("gRPC::grpc${grpc_suffix}" INTERFACE c-ares::cares gRPC::gpr gRPC::address_sorting ZLIB::ZLIB)
 | 
			
		||||
target_link_libraries ("gRPC::grpc++${grpc_suffix}" INTERFACE "gRPC::grpc${grpc_suffix}" gRPC::gpr)
 | 
			
		||||
 | 
			
		||||
#[=================================[
 | 
			
		||||
   generate protobuf sources for
 | 
			
		||||
   grpc defs and bundle into a
 | 
			
		||||
   static lib
 | 
			
		||||
#]=================================]
 | 
			
		||||
set (GRPC_GEN_DIR "${CMAKE_BINARY_DIR}/proto_gen_grpc")
 | 
			
		||||
file (MAKE_DIRECTORY ${GRPC_GEN_DIR})
 | 
			
		||||
set (GRPC_PROTO_SRCS)
 | 
			
		||||
set (GRPC_PROTO_HDRS)
 | 
			
		||||
set (GRPC_PROTO_ROOT "${CMAKE_SOURCE_DIR}/src/ripple/proto/rpc")
 | 
			
		||||
file(GLOB_RECURSE GRPC_DEFINITION_FILES LIST_DIRECTORIES false "${GRPC_PROTO_ROOT}/*.proto")
 | 
			
		||||
foreach(file ${GRPC_DEFINITION_FILES})
 | 
			
		||||
  get_filename_component(_abs_file ${file} ABSOLUTE)
 | 
			
		||||
  get_filename_component(_abs_dir ${_abs_file} DIRECTORY)
 | 
			
		||||
  get_filename_component(_basename ${file} NAME_WE)
 | 
			
		||||
  get_filename_component(_proto_inc ${GRPC_PROTO_ROOT} DIRECTORY) # updir one level
 | 
			
		||||
  file(RELATIVE_PATH _rel_root_file ${_proto_inc} ${_abs_file})
 | 
			
		||||
  get_filename_component(_rel_root_dir ${_rel_root_file} DIRECTORY)
 | 
			
		||||
  file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir})
 | 
			
		||||
 | 
			
		||||
  set (src_1 "${GRPC_GEN_DIR}/${_rel_root_dir}/${_basename}.grpc.pb.cc")
 | 
			
		||||
  set (src_2 "${GRPC_GEN_DIR}/${_rel_root_dir}/${_basename}.pb.cc")
 | 
			
		||||
  set (hdr_1 "${GRPC_GEN_DIR}/${_rel_root_dir}/${_basename}.grpc.pb.h")
 | 
			
		||||
  set (hdr_2 "${GRPC_GEN_DIR}/${_rel_root_dir}/${_basename}.pb.h")
 | 
			
		||||
  add_custom_command(
 | 
			
		||||
    OUTPUT ${src_1} ${src_2} ${hdr_1} ${hdr_2}
 | 
			
		||||
    COMMAND protobuf::protoc
 | 
			
		||||
    ARGS --grpc_out=${GRPC_GEN_DIR}
 | 
			
		||||
         --cpp_out=${GRPC_GEN_DIR}
 | 
			
		||||
         --plugin=protoc-gen-grpc=$<TARGET_FILE:gRPC::grpc_cpp_plugin>
 | 
			
		||||
         -I ${_proto_inc} -I ${_rel_dir}
 | 
			
		||||
         ${_abs_file}
 | 
			
		||||
    DEPENDS ${_abs_file} protobuf::protoc gRPC::grpc_cpp_plugin
 | 
			
		||||
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
			
		||||
    COMMENT "Running gRPC C++ protocol buffer compiler on ${file}"
 | 
			
		||||
    VERBATIM)
 | 
			
		||||
    set_source_files_properties(${src_1} ${src_2} ${hdr_1} ${hdr_2} PROPERTIES GENERATED TRUE)
 | 
			
		||||
    list(APPEND GRPC_PROTO_SRCS ${src_1} ${src_2})
 | 
			
		||||
    list(APPEND GRPC_PROTO_HDRS ${hdr_1} ${hdr_2})
 | 
			
		||||
endforeach()
 | 
			
		||||
 | 
			
		||||
add_library (grpc_pbufs STATIC ${GRPC_PROTO_SRCS} ${GRPC_PROTO_HDRS})
 | 
			
		||||
#target_include_directories (grpc_pbufs PRIVATE src)
 | 
			
		||||
target_include_directories (grpc_pbufs SYSTEM PUBLIC ${GRPC_GEN_DIR})
 | 
			
		||||
target_link_libraries (grpc_pbufs protobuf::libprotobuf "gRPC::grpc++${grpc_suffix}")
 | 
			
		||||
target_compile_options (grpc_pbufs
 | 
			
		||||
  PUBLIC
 | 
			
		||||
    $<$<BOOL:${is_xcode}>:
 | 
			
		||||
      --system-header-prefix="google/protobuf"
 | 
			
		||||
      -Wno-deprecated-dynamic-exception-spec
 | 
			
		||||
    >)
 | 
			
		||||
add_library (Ripple::grpc_pbufs ALIAS grpc_pbufs)
 | 
			
		||||
target_link_libraries (ripple_libs INTERFACE Ripple::grpc_pbufs)
 | 
			
		||||
exclude_if_included (grpc_pbufs)
 | 
			
		||||
@@ -7,7 +7,7 @@ yum -y upgrade
 | 
			
		||||
yum -y update
 | 
			
		||||
yum -y install epel-release centos-release-scl
 | 
			
		||||
yum -y install \
 | 
			
		||||
    wget curl time gcc-c++ time yum-utils \
 | 
			
		||||
    wget curl time gcc-c++ time yum-utils autoconf pkgconfig \
 | 
			
		||||
    libstdc++-static rpm-build gnupg which make cmake \
 | 
			
		||||
    devtoolset-7 devtoolset-7-gdb devtoolset-7-libasan-devel devtoolset-7-libtsan-devel devtoolset-7-libubsan-devel \
 | 
			
		||||
    devtoolset-8 devtoolset-8-gdb devtoolset-8-binutils devtoolset-8-libstdc++-devel \
 | 
			
		||||
@@ -22,8 +22,6 @@ yum -y install \
 | 
			
		||||
    python-devel python27-python-devel rh-python35-python-devel \
 | 
			
		||||
    python27 rh-python35 \
 | 
			
		||||
    ninja-build git svn \
 | 
			
		||||
    protobuf protobuf-static protobuf-c-devel \
 | 
			
		||||
    protobuf-compiler protobuf-devel \
 | 
			
		||||
    swig perl-Digest-MD5 python2-pip
 | 
			
		||||
 | 
			
		||||
if [ "${CI_USE}" = true ] ; then
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ Source: rippled
 | 
			
		||||
Section: misc
 | 
			
		||||
Priority: extra
 | 
			
		||||
Maintainer: Ripple Labs Inc. <support@ripple.com>
 | 
			
		||||
Build-Depends: cmake, debhelper (>=9), libprotobuf-dev, libssl-dev, zlib1g-dev, dh-systemd, ninja-build
 | 
			
		||||
Build-Depends: cmake, debhelper (>=9), zlib1g-dev, dh-systemd, ninja-build
 | 
			
		||||
Standards-Version: 3.9.7
 | 
			
		||||
Homepage: http://ripple.com/
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,6 @@ override_dh_auto_configure:
 | 
			
		||||
		-DCMAKE_INSTALL_PREFIX=/opt/ripple \
 | 
			
		||||
		-DCMAKE_BUILD_TYPE=Release \
 | 
			
		||||
		-Dstatic=true \
 | 
			
		||||
		-Dlocal_protobuf=ON \
 | 
			
		||||
		-Dvalidator_keys=ON \
 | 
			
		||||
		-DCMAKE_VERBOSE_MAKEFILE=ON
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ License:        MIT
 | 
			
		||||
URL:            http://ripple.com/
 | 
			
		||||
Source0:        rippled.tar.gz
 | 
			
		||||
 | 
			
		||||
BuildRequires:  protobuf-static openssl-static cmake zlib-static ninja-build
 | 
			
		||||
BuildRequires:  cmake zlib-static ninja-build
 | 
			
		||||
 | 
			
		||||
%description
 | 
			
		||||
rippled
 | 
			
		||||
@@ -32,7 +32,7 @@ core library for development of standalone applications that sign transactions.
 | 
			
		||||
cd rippled
 | 
			
		||||
mkdir -p bld.release
 | 
			
		||||
cd bld.release
 | 
			
		||||
cmake .. -G Ninja -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_BUILD_TYPE=Release -Dstatic=true -DCMAKE_VERBOSE_MAKEFILE=ON -Dlocal_protobuf=ON -Dvalidator_keys=ON
 | 
			
		||||
cmake .. -G Ninja -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_BUILD_TYPE=Release -Dstatic=true -DCMAKE_VERBOSE_MAKEFILE=ON -Dvalidator_keys=ON
 | 
			
		||||
cmake --build . --parallel --target rippled --target validator-keys -- -v
 | 
			
		||||
 | 
			
		||||
%pre
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,40 @@ rm -f openssl-${OPENSSL_VER}.tar.gz
 | 
			
		||||
rm -rf openssl-${OPENSSL_VER}
 | 
			
		||||
LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:/opt/local/openssl/lib /opt/local/openssl/bin/openssl version -a
 | 
			
		||||
 | 
			
		||||
cd /tmp
 | 
			
		||||
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.10.1/protobuf-all-3.10.1.tar.gz
 | 
			
		||||
tar xf protobuf-all-3.10.1.tar.gz
 | 
			
		||||
cd protobuf-3.10.1
 | 
			
		||||
./autogen.sh
 | 
			
		||||
./configure
 | 
			
		||||
make -j$(nproc)
 | 
			
		||||
make install
 | 
			
		||||
ldconfig
 | 
			
		||||
cd ..
 | 
			
		||||
rm -f protobuf-all-3.10.1.tar.gz
 | 
			
		||||
rm -rf protobuf-3.10.1
 | 
			
		||||
 | 
			
		||||
cd /tmp
 | 
			
		||||
wget https://github.com/c-ares/c-ares/releases/download/cares-1_15_0/c-ares-1.15.0.tar.gz
 | 
			
		||||
tar xf c-ares-1.15.0.tar.gz
 | 
			
		||||
cd c-ares-1.15.0
 | 
			
		||||
./configure
 | 
			
		||||
make -j$(nproc)
 | 
			
		||||
make install
 | 
			
		||||
cd ..
 | 
			
		||||
rm -f c-ares-1.15.0.tar.gz
 | 
			
		||||
rm -rf c-ares-1.15.0
 | 
			
		||||
 | 
			
		||||
cd /tmp
 | 
			
		||||
wget https://github.com/grpc/grpc/archive/v1.25.0.tar.gz
 | 
			
		||||
tar xf v1.25.0.tar.gz
 | 
			
		||||
cd grpc-1.25.0
 | 
			
		||||
make -j$(nproc)
 | 
			
		||||
make install
 | 
			
		||||
cd ..
 | 
			
		||||
rm -f xf v1.25.0.tar.gz
 | 
			
		||||
rm -rf grpc-1.25.0
 | 
			
		||||
 | 
			
		||||
if [ "${CI_USE}" = true ] ; then
 | 
			
		||||
    cd /tmp
 | 
			
		||||
    wget https://github.com/doxygen/doxygen/archive/Release_1_8_16.tar.gz
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,8 @@ apt-get -y clean
 | 
			
		||||
apt-get -y update
 | 
			
		||||
 | 
			
		||||
apt-get -y --fix-missing install \
 | 
			
		||||
    make cmake ninja-build \
 | 
			
		||||
    protobuf-compiler libprotobuf-dev openssl libssl-dev \
 | 
			
		||||
    make cmake ninja-build autoconf libtool pkg-config \
 | 
			
		||||
    openssl libssl-dev \
 | 
			
		||||
    liblzma-dev libbz2-dev zlib1g-dev \
 | 
			
		||||
    libjemalloc-dev \
 | 
			
		||||
    python-pip \
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,7 @@ include(deps/Rocksdb)
 | 
			
		||||
include(deps/Nudb)
 | 
			
		||||
include(deps/date)
 | 
			
		||||
include(deps/Protobuf)
 | 
			
		||||
include(deps/gRPC)
 | 
			
		||||
 | 
			
		||||
###
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ if [[ -d "${VCPKG_DIR}" ]] ; then
 | 
			
		||||
    rm -rf "${VCPKG_DIR}"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
git clone --branch 2019.06 https://github.com/Microsoft/vcpkg.git ${VCPKG_DIR}
 | 
			
		||||
git clone --branch 2019.10 https://github.com/Microsoft/vcpkg.git ${VCPKG_DIR}
 | 
			
		||||
pushd ${VCPKG_DIR}
 | 
			
		||||
if [[ -z ${COMSPEC:-} ]]; then
 | 
			
		||||
    chmod +x ./bootstrap-vcpkg.sh
 | 
			
		||||
 
 | 
			
		||||
@@ -1168,6 +1168,10 @@ ip = 127.0.0.1
 | 
			
		||||
admin = 127.0.0.1
 | 
			
		||||
protocol = ws
 | 
			
		||||
 | 
			
		||||
#[port_grpc]
 | 
			
		||||
#port = 50051
 | 
			
		||||
#ip = 0.0.0.0
 | 
			
		||||
 | 
			
		||||
#[port_ws_public]
 | 
			
		||||
#port = 6005
 | 
			
		||||
#ip = 127.0.0.1
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,7 @@
 | 
			
		||||
#include <ripple/beast/core/LexicalCast.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/algorithm/string/predicate.hpp>
 | 
			
		||||
#include <ripple/app/main/GRPCServer.h>
 | 
			
		||||
#include <boost/asio/steady_timer.hpp>
 | 
			
		||||
#include <boost/system/error_code.hpp>
 | 
			
		||||
 | 
			
		||||
@@ -391,6 +392,8 @@ public:
 | 
			
		||||
 | 
			
		||||
    io_latency_sampler m_io_latency_sampler;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<GRPCServer> grpcServer_;
 | 
			
		||||
 | 
			
		||||
    //--------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
    static
 | 
			
		||||
@@ -552,6 +555,7 @@ public:
 | 
			
		||||
 | 
			
		||||
        , m_io_latency_sampler (m_collectorManager->collector()->make_event ("ios_latency"),
 | 
			
		||||
            logs_->journal("Application"), std::chrono::milliseconds (100), get_io_service())
 | 
			
		||||
        , grpcServer_(std::make_unique<GRPCServer>(*this))
 | 
			
		||||
    {
 | 
			
		||||
        if (shardStore_)
 | 
			
		||||
        {
 | 
			
		||||
@@ -1339,6 +1343,7 @@ bool ApplicationImp::setup()
 | 
			
		||||
    logs_->silent (config_->silent());
 | 
			
		||||
 | 
			
		||||
    m_jobQueue->setThreadCount (config_->WORKERS, config_->standalone());
 | 
			
		||||
    grpcServer_->run();
 | 
			
		||||
 | 
			
		||||
    if (!config_->standalone())
 | 
			
		||||
        timeKeeper_->run(config_->SNTP_SERVERS);
 | 
			
		||||
@@ -1583,9 +1588,15 @@ bool ApplicationImp::setup()
 | 
			
		||||
 | 
			
		||||
        Resource::Charge loadType = Resource::feeReferenceRPC;
 | 
			
		||||
        Resource::Consumer c;
 | 
			
		||||
        RPC::Context context { journal ("RPCHandler"), jvCommand, *this,
 | 
			
		||||
            loadType, getOPs (), getLedgerMaster(), c, Role::ADMIN,
 | 
			
		||||
            RPC::ApiMaximumSupportedVersion};
 | 
			
		||||
        RPC::JsonContext context{{journal("RPCHandler"),
 | 
			
		||||
                                  *this,
 | 
			
		||||
                                  loadType,
 | 
			
		||||
                                  getOPs(),
 | 
			
		||||
                                  getLedgerMaster(),
 | 
			
		||||
                                  c,
 | 
			
		||||
                                  Role::ADMIN},
 | 
			
		||||
                                 jvCommand,
 | 
			
		||||
                                 RPC::ApiMaximumSupportedVersion};
 | 
			
		||||
 | 
			
		||||
        Json::Value jvResult;
 | 
			
		||||
        RPC::doCommand (context, jvResult);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										408
									
								
								src/ripple/app/main/GRPCServer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										408
									
								
								src/ripple/app/main/GRPCServer.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,408 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    This file is part of rippled: https://github.com/ripple/rippled
 | 
			
		||||
    Copyright (c) 2020 Ripple Labs Inc.
 | 
			
		||||
 | 
			
		||||
    Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
    purpose  with  or without fee is hereby granted, provided that the above
 | 
			
		||||
    copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
    THE  SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
    WITH  REGARD  TO  THIS  SOFTWARE  INCLUDING  ALL  IMPLIED  WARRANTIES  OF
 | 
			
		||||
    MERCHANTABILITY  AND  FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
			
		||||
    ANY  SPECIAL ,  DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
    WHATSOEVER  RESULTING  FROM  LOSS  OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
			
		||||
    ACTION  OF  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
			
		||||
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#include <ripple/app/main/GRPCServer.h>
 | 
			
		||||
#include <ripple/resource/Fees.h>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
// helper function. strips scheme from endpoint string
 | 
			
		||||
std::string
 | 
			
		||||
getEndpoint(std::string const& peer)
 | 
			
		||||
{
 | 
			
		||||
    std::size_t first = peer.find_first_of(":");
 | 
			
		||||
    std::size_t last = peer.find_last_of(":");
 | 
			
		||||
    std::string peerClean(peer);
 | 
			
		||||
    if (first != last)
 | 
			
		||||
    {
 | 
			
		||||
        peerClean = peer.substr(first + 1);
 | 
			
		||||
    }
 | 
			
		||||
    return peerClean;
 | 
			
		||||
}
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::CallData(
 | 
			
		||||
    rpc::v1::XRPLedgerAPIService::AsyncService& service,
 | 
			
		||||
    grpc::ServerCompletionQueue& cq,
 | 
			
		||||
    Application& app,
 | 
			
		||||
    BindListener<Request, Response> bindListener,
 | 
			
		||||
    Handler<Request, Response> handler,
 | 
			
		||||
    RPC::Condition requiredCondition,
 | 
			
		||||
    Resource::Charge loadType)
 | 
			
		||||
    : service_(service)
 | 
			
		||||
    , cq_(cq)
 | 
			
		||||
    , finished_(false)
 | 
			
		||||
    , app_(app)
 | 
			
		||||
    , aborted_(false)
 | 
			
		||||
    , responder_(&ctx_)
 | 
			
		||||
    , bindListener_(std::move(bindListener))
 | 
			
		||||
    , handler_(std::move(handler))
 | 
			
		||||
    , requiredCondition_(std::move(requiredCondition))
 | 
			
		||||
    , loadType_(std::move(loadType))
 | 
			
		||||
{
 | 
			
		||||
    // Bind a listener. When a request is received, "this" will be returned
 | 
			
		||||
    // from CompletionQueue::Next
 | 
			
		||||
    bindListener_(service_, &ctx_, &request_, &responder_, &cq_, &cq_, this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
std::shared_ptr<Processor>
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::clone()
 | 
			
		||||
{
 | 
			
		||||
    return std::make_shared<CallData<Request, Response>>(
 | 
			
		||||
        service_,
 | 
			
		||||
        cq_,
 | 
			
		||||
        app_,
 | 
			
		||||
        bindListener_,
 | 
			
		||||
        handler_,
 | 
			
		||||
        requiredCondition_,
 | 
			
		||||
        loadType_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
void
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::process()
 | 
			
		||||
{
 | 
			
		||||
    // sanity check
 | 
			
		||||
    BOOST_ASSERT(!finished_);
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<CallData<Request, Response>> thisShared =
 | 
			
		||||
        this->shared_from_this();
 | 
			
		||||
    app_.getJobQueue().postCoro(
 | 
			
		||||
        JobType::jtRPC,
 | 
			
		||||
        "gRPC-Client",
 | 
			
		||||
        [thisShared](std::shared_ptr<JobQueue::Coro> coro) {
 | 
			
		||||
            std::lock_guard lock{thisShared->mut_};
 | 
			
		||||
 | 
			
		||||
            // Do nothing if call has been aborted due to server shutdown
 | 
			
		||||
            // or if handler was already executed
 | 
			
		||||
            if (thisShared->aborted_ || thisShared->finished_)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            thisShared->process(coro);
 | 
			
		||||
            thisShared->finished_ = true;
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
void
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::process(
 | 
			
		||||
    std::shared_ptr<JobQueue::Coro> coro)
 | 
			
		||||
{
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        auto usage = getUsage();
 | 
			
		||||
        if (usage.disconnect())
 | 
			
		||||
        {
 | 
			
		||||
            grpc::Status status{grpc::StatusCode::RESOURCE_EXHAUSTED,
 | 
			
		||||
                                "usage balance exceeds threshhold"};
 | 
			
		||||
            responder_.FinishWithError(status, this);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            auto loadType = getLoadType();
 | 
			
		||||
            usage.charge(loadType);
 | 
			
		||||
            auto role = getRole();
 | 
			
		||||
 | 
			
		||||
            RPC::GRPCContext<Request> context{{app_.journal("gRPCServer"),
 | 
			
		||||
                                               app_,
 | 
			
		||||
                                               loadType,
 | 
			
		||||
                                               app_.getOPs(),
 | 
			
		||||
                                               app_.getLedgerMaster(),
 | 
			
		||||
                                               usage,
 | 
			
		||||
                                               role,
 | 
			
		||||
                                               coro,
 | 
			
		||||
                                               InfoSub::pointer()},
 | 
			
		||||
                                              request_};
 | 
			
		||||
 | 
			
		||||
            // Make sure we can currently handle the rpc
 | 
			
		||||
            error_code_i conditionMetRes =
 | 
			
		||||
                RPC::conditionMet(requiredCondition_, context);
 | 
			
		||||
 | 
			
		||||
            if (conditionMetRes != rpcSUCCESS)
 | 
			
		||||
            {
 | 
			
		||||
                RPC::ErrorInfo errorInfo = RPC::get_error_info(conditionMetRes);
 | 
			
		||||
                grpc::Status status{grpc::StatusCode::INTERNAL,
 | 
			
		||||
                                    errorInfo.message.c_str()};
 | 
			
		||||
                responder_.FinishWithError(status, this);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                std::pair<Response, grpc::Status> result = handler_(context);
 | 
			
		||||
                responder_.Finish(result.first, result.second, this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception const& ex)
 | 
			
		||||
    {
 | 
			
		||||
        grpc::Status status{grpc::StatusCode::INTERNAL, ex.what()};
 | 
			
		||||
        responder_.FinishWithError(status, this);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
bool
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::isFinished()
 | 
			
		||||
{
 | 
			
		||||
    // Need to lock here because this object can be returned from cq_.Next(..)
 | 
			
		||||
    // as soon as the response is sent, which could be before finished_ is set
 | 
			
		||||
    // to true, causing the handler to be executed twice
 | 
			
		||||
    std::lock_guard lock{mut_};
 | 
			
		||||
    return finished_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
void
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::abort()
 | 
			
		||||
{
 | 
			
		||||
    std::lock_guard lock{mut_};
 | 
			
		||||
    aborted_ = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
Resource::Charge
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::getLoadType()
 | 
			
		||||
{
 | 
			
		||||
    return loadType_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
Role
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::getRole()
 | 
			
		||||
{
 | 
			
		||||
    return Role::USER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Request, class Response>
 | 
			
		||||
Resource::Consumer
 | 
			
		||||
GRPCServerImpl::CallData<Request, Response>::getUsage()
 | 
			
		||||
{
 | 
			
		||||
    std::string peer = getEndpoint(ctx_.peer());
 | 
			
		||||
    boost::optional<beast::IP::Endpoint> endpoint =
 | 
			
		||||
        beast::IP::Endpoint::from_string_checked(peer);
 | 
			
		||||
    return app_.getResourceManager().newInboundEndpoint(endpoint.get());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GRPCServerImpl::GRPCServerImpl(Application& app) : app_(app)
 | 
			
		||||
{
 | 
			
		||||
    // if present, get endpoint from config
 | 
			
		||||
    if (app_.config().exists("port_grpc"))
 | 
			
		||||
    {
 | 
			
		||||
        Section section = app_.config().section("port_grpc");
 | 
			
		||||
 | 
			
		||||
        std::pair<std::string, bool> ipPair = section.find("ip");
 | 
			
		||||
        if (!ipPair.second)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        std::pair<std::string, bool> portPair = section.find("port");
 | 
			
		||||
        if (!portPair.second)
 | 
			
		||||
            return;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            beast::IP::Endpoint endpoint(
 | 
			
		||||
                boost::asio::ip::make_address(ipPair.first),
 | 
			
		||||
                std::stoi(portPair.first));
 | 
			
		||||
 | 
			
		||||
            serverAddress_ = endpoint.to_string();
 | 
			
		||||
        }
 | 
			
		||||
        catch (std::exception const&)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
GRPCServerImpl::shutdown()
 | 
			
		||||
{
 | 
			
		||||
    server_->Shutdown();
 | 
			
		||||
    // Always shutdown the completion queue after the server.
 | 
			
		||||
    cq_->Shutdown();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
GRPCServerImpl::handleRpcs()
 | 
			
		||||
{
 | 
			
		||||
    // This collection should really be an unordered_set. However, to delete
 | 
			
		||||
    // from the unordered_set, we need a shared_ptr, but cq_.Next() (see below
 | 
			
		||||
    // while loop) sets the tag to a raw pointer.
 | 
			
		||||
    std::vector<std::shared_ptr<Processor>> requests = setupListeners();
 | 
			
		||||
 | 
			
		||||
    auto erase = [&requests](Processor* ptr) {
 | 
			
		||||
        auto it = std::find_if(
 | 
			
		||||
            requests.begin(),
 | 
			
		||||
            requests.end(),
 | 
			
		||||
            [ptr](std::shared_ptr<Processor>& sPtr) {
 | 
			
		||||
                return sPtr.get() == ptr;
 | 
			
		||||
            });
 | 
			
		||||
        BOOST_ASSERT(it != requests.end());
 | 
			
		||||
        it->swap(requests.back());
 | 
			
		||||
        requests.pop_back();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void* tag;  // uniquely identifies a request.
 | 
			
		||||
    bool ok;
 | 
			
		||||
    // Block waiting to read the next event from the completion queue. The
 | 
			
		||||
    // event is uniquely identified by its tag, which in this case is the
 | 
			
		||||
    // memory address of a CallData instance.
 | 
			
		||||
    // The return value of Next should always be checked. This return value
 | 
			
		||||
    // tells us whether there is any kind of event or cq_ is shutting down.
 | 
			
		||||
    while (cq_->Next(&tag, &ok))
 | 
			
		||||
    {
 | 
			
		||||
        auto ptr = static_cast<Processor*>(tag);
 | 
			
		||||
        // if ok is false, event was terminated as part of a shutdown sequence
 | 
			
		||||
        // need to abort any further processing
 | 
			
		||||
        if (!ok)
 | 
			
		||||
        {
 | 
			
		||||
            // abort first, then erase. Otherwise, erase can delete object
 | 
			
		||||
            ptr->abort();
 | 
			
		||||
            erase(ptr);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (!ptr->isFinished())
 | 
			
		||||
            {
 | 
			
		||||
                // ptr is now processing a request, so create a new CallData
 | 
			
		||||
                // object to handle additional requests
 | 
			
		||||
                auto cloned = ptr->clone();
 | 
			
		||||
                requests.push_back(cloned);
 | 
			
		||||
                // process the request
 | 
			
		||||
                ptr->process();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                erase(ptr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create a CallData instance for each RPC
 | 
			
		||||
std::vector<std::shared_ptr<Processor>>
 | 
			
		||||
GRPCServerImpl::setupListeners()
 | 
			
		||||
{
 | 
			
		||||
    std::vector<std::shared_ptr<Processor>> requests;
 | 
			
		||||
 | 
			
		||||
    auto addToRequests = [&requests](auto callData) {
 | 
			
		||||
        requests.push_back(std::move(callData));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        using cd = CallData<rpc::v1::GetFeeRequest, rpc::v1::GetFeeResponse>;
 | 
			
		||||
 | 
			
		||||
        addToRequests(std::make_shared<cd>(
 | 
			
		||||
            service_,
 | 
			
		||||
            *cq_,
 | 
			
		||||
            app_,
 | 
			
		||||
            &rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetFee,
 | 
			
		||||
            doFeeGrpc,
 | 
			
		||||
            RPC::NEEDS_CURRENT_LEDGER,
 | 
			
		||||
            Resource::feeReferenceRPC));
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        using cd = CallData<
 | 
			
		||||
            rpc::v1::GetAccountInfoRequest,
 | 
			
		||||
            rpc::v1::GetAccountInfoResponse>;
 | 
			
		||||
 | 
			
		||||
        addToRequests(std::make_shared<cd>(
 | 
			
		||||
            service_,
 | 
			
		||||
            *cq_,
 | 
			
		||||
            app_,
 | 
			
		||||
            &rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetAccountInfo,
 | 
			
		||||
            doAccountInfoGrpc,
 | 
			
		||||
            RPC::NEEDS_CURRENT_LEDGER,
 | 
			
		||||
            Resource::feeReferenceRPC));
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        using cd = CallData<rpc::v1::GetTxRequest, rpc::v1::GetTxResponse>;
 | 
			
		||||
 | 
			
		||||
        addToRequests(std::make_shared<cd>(
 | 
			
		||||
            service_,
 | 
			
		||||
            *cq_,
 | 
			
		||||
            app_,
 | 
			
		||||
            &rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetTx,
 | 
			
		||||
            doTxGrpc,
 | 
			
		||||
            RPC::NEEDS_CURRENT_LEDGER,
 | 
			
		||||
            Resource::feeReferenceRPC));
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        using cd = CallData<
 | 
			
		||||
            rpc::v1::SubmitTransactionRequest,
 | 
			
		||||
            rpc::v1::SubmitTransactionResponse>;
 | 
			
		||||
 | 
			
		||||
        addToRequests(std::make_shared<cd>(
 | 
			
		||||
            service_,
 | 
			
		||||
            *cq_,
 | 
			
		||||
            app_,
 | 
			
		||||
            &rpc::v1::XRPLedgerAPIService::AsyncService::
 | 
			
		||||
                RequestSubmitTransaction,
 | 
			
		||||
            doSubmitGrpc,
 | 
			
		||||
            RPC::NEEDS_CURRENT_LEDGER,
 | 
			
		||||
            Resource::feeMediumBurdenRPC));
 | 
			
		||||
    }
 | 
			
		||||
    return requests;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
GRPCServerImpl::start()
 | 
			
		||||
{
 | 
			
		||||
    // if config does not specify a grpc server address, don't start
 | 
			
		||||
    if (serverAddress_.empty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    grpc::ServerBuilder builder;
 | 
			
		||||
    // Listen on the given address without any authentication mechanism.
 | 
			
		||||
    builder.AddListeningPort(serverAddress_, grpc::InsecureServerCredentials());
 | 
			
		||||
    // Register "service_" as the instance through which we'll communicate with
 | 
			
		||||
    // clients. In this case it corresponds to an *asynchronous* service.
 | 
			
		||||
    builder.RegisterService(&service_);
 | 
			
		||||
    // Get hold of the completion queue used for the asynchronous communication
 | 
			
		||||
    // with the gRPC runtime.
 | 
			
		||||
    cq_ = builder.AddCompletionQueue();
 | 
			
		||||
    // Finally assemble the server.
 | 
			
		||||
    server_ = builder.BuildAndStart();
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
GRPCServer::run()
 | 
			
		||||
{
 | 
			
		||||
    // Start the server and setup listeners
 | 
			
		||||
    if ((running_ = impl_.start()))
 | 
			
		||||
    {
 | 
			
		||||
        thread_ = std::thread([this]() {
 | 
			
		||||
            // Start the event loop and begin handling requests
 | 
			
		||||
            this->impl_.handleRpcs();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GRPCServer::~GRPCServer()
 | 
			
		||||
{
 | 
			
		||||
    if (running_)
 | 
			
		||||
    {
 | 
			
		||||
        impl_.shutdown();
 | 
			
		||||
        thread_.join();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace ripple
 | 
			
		||||
							
								
								
									
										263
									
								
								src/ripple/app/main/GRPCServer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								src/ripple/app/main/GRPCServer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,263 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    This file is part of rippled: https://github.com/ripple/rippled
 | 
			
		||||
    Copyright (c) 2012, 2013 Ripple Labs Inc.
 | 
			
		||||
 | 
			
		||||
    Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
    purpose  with  or without fee is hereby granted, provided that the above
 | 
			
		||||
    copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
    THE  SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
    WITH  REGARD  TO  THIS  SOFTWARE  INCLUDING  ALL  IMPLIED  WARRANTIES  OF
 | 
			
		||||
    MERCHANTABILITY  AND  FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
			
		||||
    ANY  SPECIAL ,  DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
    WHATSOEVER  RESULTING  FROM  LOSS  OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
			
		||||
    ACTION  OF  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
			
		||||
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#ifndef RIPPLE_CORE_GRPCSERVER_H_INCLUDED
 | 
			
		||||
#define RIPPLE_CORE_GRPCSERVER_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <ripple/app/main/Application.h>
 | 
			
		||||
#include <ripple/core/JobQueue.h>
 | 
			
		||||
#include <ripple/net/InfoSub.h>
 | 
			
		||||
#include <ripple/protocol/ErrorCodes.h>
 | 
			
		||||
#include <ripple/resource/Charge.h>
 | 
			
		||||
#include <ripple/rpc/Context.h>
 | 
			
		||||
#include <ripple/rpc/GRPCHandlers.h>
 | 
			
		||||
#include <ripple/rpc/Role.h>
 | 
			
		||||
#include <ripple/rpc/impl/Handler.h>
 | 
			
		||||
#include <ripple/rpc/impl/RPCHelpers.h>
 | 
			
		||||
#include <ripple/rpc/impl/Tuning.h>
 | 
			
		||||
 | 
			
		||||
#include "rpc/v1/xrp_ledger.grpc.pb.h"
 | 
			
		||||
#include <grpcpp/grpcpp.h>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
// Interface that CallData implements
 | 
			
		||||
class Processor
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~Processor() = default;
 | 
			
		||||
 | 
			
		||||
    Processor() = default;
 | 
			
		||||
 | 
			
		||||
    Processor(const Processor&) = delete;
 | 
			
		||||
 | 
			
		||||
    Processor&
 | 
			
		||||
    operator=(const Processor&) = delete;
 | 
			
		||||
 | 
			
		||||
    // process a request that has arrived. Can only be called once per instance
 | 
			
		||||
    virtual void
 | 
			
		||||
    process() = 0;
 | 
			
		||||
 | 
			
		||||
    // abort processing this request. called when server shutsdown
 | 
			
		||||
    virtual void
 | 
			
		||||
    abort() = 0;
 | 
			
		||||
 | 
			
		||||
    // create a new instance of this CallData object, with the same type
 | 
			
		||||
    //(same template parameters) as original. This is called when a CallData
 | 
			
		||||
    // object starts processing a request. Creating a new instance allows the
 | 
			
		||||
    // server to handle additional requests while the first is being processed
 | 
			
		||||
    virtual std::shared_ptr<Processor>
 | 
			
		||||
    clone() = 0;
 | 
			
		||||
 | 
			
		||||
    // true if this object has finished processing the request. Object will be
 | 
			
		||||
    // deleted once this function returns true
 | 
			
		||||
    virtual bool
 | 
			
		||||
    isFinished() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GRPCServerImpl final
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    // CompletionQueue returns events that have occurred, or events that have
 | 
			
		||||
    // been cancelled
 | 
			
		||||
    std::unique_ptr<grpc::ServerCompletionQueue> cq_;
 | 
			
		||||
 | 
			
		||||
    std::vector<std::shared_ptr<Processor>> requests_;
 | 
			
		||||
 | 
			
		||||
    // The gRPC service defined by the .proto files
 | 
			
		||||
    rpc::v1::XRPLedgerAPIService::AsyncService service_;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<grpc::Server> server_;
 | 
			
		||||
 | 
			
		||||
    Application& app_;
 | 
			
		||||
 | 
			
		||||
    std::string serverAddress_;
 | 
			
		||||
 | 
			
		||||
    // typedef for function to bind a listener
 | 
			
		||||
    // This is always of the form:
 | 
			
		||||
    // rpc::v1::XRPLedgerAPIService::AsyncService::Request[RPC NAME]
 | 
			
		||||
    template <class Request, class Response>
 | 
			
		||||
    using BindListener = std::function<void(
 | 
			
		||||
        rpc::v1::XRPLedgerAPIService::AsyncService&,
 | 
			
		||||
        grpc::ServerContext*,
 | 
			
		||||
        Request*,
 | 
			
		||||
        grpc::ServerAsyncResponseWriter<Response>*,
 | 
			
		||||
        grpc::CompletionQueue*,
 | 
			
		||||
        grpc::ServerCompletionQueue*,
 | 
			
		||||
        void*)>;
 | 
			
		||||
 | 
			
		||||
    // typedef for actual handler (that populates a response)
 | 
			
		||||
    // handlers are defined in rpc/GRPCHandlers.h
 | 
			
		||||
    template <class Request, class Response>
 | 
			
		||||
    using Handler = std::function<std::pair<Response, grpc::Status>(
 | 
			
		||||
        RPC::GRPCContext<Request>&)>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit GRPCServerImpl(Application& app);
 | 
			
		||||
 | 
			
		||||
    GRPCServerImpl(const GRPCServerImpl&) = delete;
 | 
			
		||||
 | 
			
		||||
    GRPCServerImpl&
 | 
			
		||||
    operator=(const GRPCServerImpl&) = delete;
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    shutdown();
 | 
			
		||||
 | 
			
		||||
    // setup the server and listeners
 | 
			
		||||
    // returns true if server started successfully
 | 
			
		||||
    bool
 | 
			
		||||
    start();
 | 
			
		||||
 | 
			
		||||
    // the main event loop
 | 
			
		||||
    void
 | 
			
		||||
    handleRpcs();
 | 
			
		||||
 | 
			
		||||
    // Create a CallData object for each RPC. Return created objects in vector
 | 
			
		||||
    std::vector<std::shared_ptr<Processor>>
 | 
			
		||||
    setupListeners();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Class encompasing the state and logic needed to serve a request.
 | 
			
		||||
    template <class Request, class Response>
 | 
			
		||||
    class CallData
 | 
			
		||||
        : public Processor,
 | 
			
		||||
          public std::enable_shared_from_this<CallData<Request, Response>>
 | 
			
		||||
    {
 | 
			
		||||
    private:
 | 
			
		||||
        // The means of communication with the gRPC runtime for an asynchronous
 | 
			
		||||
        // server.
 | 
			
		||||
        rpc::v1::XRPLedgerAPIService::AsyncService& service_;
 | 
			
		||||
 | 
			
		||||
        // The producer-consumer queue for asynchronous server notifications.
 | 
			
		||||
        grpc::ServerCompletionQueue& cq_;
 | 
			
		||||
 | 
			
		||||
        // Context for the rpc, allowing to tweak aspects of it such as the use
 | 
			
		||||
        // of compression, authentication, as well as to send metadata back to
 | 
			
		||||
        // the client.
 | 
			
		||||
        grpc::ServerContext ctx_;
 | 
			
		||||
 | 
			
		||||
        // true if finished processing request
 | 
			
		||||
        bool finished_;
 | 
			
		||||
 | 
			
		||||
        Application& app_;
 | 
			
		||||
 | 
			
		||||
        // mutex for signaling abort
 | 
			
		||||
        std::mutex mut_;
 | 
			
		||||
 | 
			
		||||
        // whether the call should be aborted, due to server shutdown
 | 
			
		||||
        bool aborted_;
 | 
			
		||||
 | 
			
		||||
        // What we get from the client.
 | 
			
		||||
        Request request_;
 | 
			
		||||
 | 
			
		||||
        // What we send back to the client.
 | 
			
		||||
        Response reply_;
 | 
			
		||||
 | 
			
		||||
        // The means to get back to the client.
 | 
			
		||||
        grpc::ServerAsyncResponseWriter<Response> responder_;
 | 
			
		||||
 | 
			
		||||
        // Function that creates a listener for specific request type
 | 
			
		||||
        BindListener<Request, Response> bindListener_;
 | 
			
		||||
 | 
			
		||||
        // Function that processes a request
 | 
			
		||||
        Handler<Request, Response> handler_;
 | 
			
		||||
 | 
			
		||||
        // Condition required for this RPC
 | 
			
		||||
        RPC::Condition requiredCondition_;
 | 
			
		||||
 | 
			
		||||
        // Load type for this RPC
 | 
			
		||||
        Resource::Charge loadType_;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        virtual ~CallData() = default;
 | 
			
		||||
 | 
			
		||||
        // Take in the "service" instance (in this case representing an
 | 
			
		||||
        // asynchronous server) and the completion queue "cq" used for
 | 
			
		||||
        // asynchronous communication with the gRPC runtime.
 | 
			
		||||
        explicit CallData(
 | 
			
		||||
            rpc::v1::XRPLedgerAPIService::AsyncService& service,
 | 
			
		||||
            grpc::ServerCompletionQueue& cq,
 | 
			
		||||
            Application& app,
 | 
			
		||||
            BindListener<Request, Response> bindListener,
 | 
			
		||||
            Handler<Request, Response> handler,
 | 
			
		||||
            RPC::Condition requiredCondition,
 | 
			
		||||
            Resource::Charge loadType);
 | 
			
		||||
 | 
			
		||||
        CallData(const CallData&) = delete;
 | 
			
		||||
 | 
			
		||||
        CallData&
 | 
			
		||||
        operator=(const CallData&) = delete;
 | 
			
		||||
 | 
			
		||||
        virtual void
 | 
			
		||||
        process() override;
 | 
			
		||||
 | 
			
		||||
        virtual bool
 | 
			
		||||
        isFinished() override;
 | 
			
		||||
 | 
			
		||||
        virtual void
 | 
			
		||||
        abort() override;
 | 
			
		||||
 | 
			
		||||
        std::shared_ptr<Processor>
 | 
			
		||||
        clone() override;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        // process the request. Called inside the coroutine passed to JobQueue
 | 
			
		||||
        void
 | 
			
		||||
        process(std::shared_ptr<JobQueue::Coro> coro);
 | 
			
		||||
 | 
			
		||||
        // return load type of this RPC
 | 
			
		||||
        Resource::Charge
 | 
			
		||||
        getLoadType();
 | 
			
		||||
 | 
			
		||||
        // return the Role required for this RPC
 | 
			
		||||
        // for now, we are only supporting RPC's that require Role::USER for
 | 
			
		||||
        // gRPC
 | 
			
		||||
        Role
 | 
			
		||||
        getRole();
 | 
			
		||||
 | 
			
		||||
        // register endpoint with ResourceManager and return usage
 | 
			
		||||
        Resource::Consumer
 | 
			
		||||
        getUsage();
 | 
			
		||||
 | 
			
		||||
    };  // CallData
 | 
			
		||||
 | 
			
		||||
};  // GRPCServerImpl
 | 
			
		||||
 | 
			
		||||
class GRPCServer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit GRPCServer(Application& app) : impl_(app){};
 | 
			
		||||
 | 
			
		||||
    GRPCServer(const GRPCServer&) = delete;
 | 
			
		||||
 | 
			
		||||
    GRPCServer&
 | 
			
		||||
    operator=(const GRPCServer&) = delete;
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    run();
 | 
			
		||||
 | 
			
		||||
    ~GRPCServer();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    GRPCServerImpl impl_;
 | 
			
		||||
    std::thread thread_;
 | 
			
		||||
    bool running_;
 | 
			
		||||
};
 | 
			
		||||
}  // namespace ripple
 | 
			
		||||
#endif
 | 
			
		||||
@@ -27,7 +27,8 @@ namespace ripple {
 | 
			
		||||
Message::Message (::google::protobuf::Message const& message, int type)
 | 
			
		||||
    : mCategory(TrafficCount::categorize(message, type, false))
 | 
			
		||||
{
 | 
			
		||||
    unsigned const messageBytes = message.ByteSize ();
 | 
			
		||||
    auto const messageBytes = message.ByteSizeLong();
 | 
			
		||||
 | 
			
		||||
    assert (messageBytes != 0);
 | 
			
		||||
 | 
			
		||||
    /** Number of bytes in a message header. */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										81
									
								
								src/ripple/proto/rpc/v1/account_info.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/ripple/proto/rpc/v1/account_info.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
import "rpc/v1/ledger_objects.proto";
 | 
			
		||||
import "rpc/v1/amount.proto";
 | 
			
		||||
 | 
			
		||||
// A request to get info about an account.
 | 
			
		||||
message GetAccountInfoRequest {
 | 
			
		||||
    // The address to get info about.
 | 
			
		||||
    AccountAddress account = 1;
 | 
			
		||||
 | 
			
		||||
    bool strict = 2;
 | 
			
		||||
 | 
			
		||||
    LedgerSpecifier ledger = 3;
 | 
			
		||||
 | 
			
		||||
    bool queue = 4;
 | 
			
		||||
 | 
			
		||||
    bool signer_lists = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message LedgerSpecifier {
 | 
			
		||||
    enum Shortcut {
 | 
			
		||||
        SHORTCUT_UNSPECIFIED = 0;
 | 
			
		||||
        SHORTCUT_VALIDATED   = 1;
 | 
			
		||||
        SHORTCUT_CLOSED      = 2;
 | 
			
		||||
        SHORTCUT_CURRENT     = 3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    oneof ledger {
 | 
			
		||||
        Shortcut shortcut = 1;
 | 
			
		||||
        uint32 sequence = 2;
 | 
			
		||||
        // 32 bytes
 | 
			
		||||
        bytes hash = 3;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Response to GetAccountInfo RPC
 | 
			
		||||
message GetAccountInfoResponse {
 | 
			
		||||
 | 
			
		||||
    AccountRoot account_data = 1;
 | 
			
		||||
 | 
			
		||||
    SignerList signer_list = 2;
 | 
			
		||||
 | 
			
		||||
    uint32 ledger_index = 3;
 | 
			
		||||
 | 
			
		||||
    QueueData queue_data = 4;
 | 
			
		||||
 | 
			
		||||
    bool validated = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Aggregate data about queued transactions
 | 
			
		||||
message QueueData {
 | 
			
		||||
 | 
			
		||||
    uint32 txn_count = 1;
 | 
			
		||||
 | 
			
		||||
    bool auth_change_queued = 2;
 | 
			
		||||
 | 
			
		||||
    uint32 lowest_sequence = 3;
 | 
			
		||||
 | 
			
		||||
    uint32 highest_sequence = 4;
 | 
			
		||||
 | 
			
		||||
    XRPDropsAmount max_spend_drops_total = 5;
 | 
			
		||||
 | 
			
		||||
    repeated QueuedTransaction transactions = 6;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Data about a single queued transaction
 | 
			
		||||
message QueuedTransaction {
 | 
			
		||||
    bool auth_change = 1;
 | 
			
		||||
 | 
			
		||||
    XRPDropsAmount fee = 2;
 | 
			
		||||
 | 
			
		||||
    uint64 fee_level = 3;
 | 
			
		||||
 | 
			
		||||
    XRPDropsAmount max_spend_drops = 4;
 | 
			
		||||
 | 
			
		||||
    uint32 sequence = 5;
 | 
			
		||||
 | 
			
		||||
    uint32 last_ledger_sequence = 6;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								src/ripple/proto/rpc/v1/amount.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/ripple/proto/rpc/v1/amount.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
message CurrencyAmount {
 | 
			
		||||
    oneof amount {
 | 
			
		||||
        XRPDropsAmount xrp_amount = 1;
 | 
			
		||||
        IssuedCurrencyAmount issued_currency_amount = 2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A representation of an amount of XRP.
 | 
			
		||||
message XRPDropsAmount {
 | 
			
		||||
 | 
			
		||||
    uint64 drops = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A representation of an account address
 | 
			
		||||
message AccountAddress {
 | 
			
		||||
 | 
			
		||||
    //base58 encoding of an account
 | 
			
		||||
    string address = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A representation of an amount of issued currency.
 | 
			
		||||
message IssuedCurrencyAmount {
 | 
			
		||||
    // The currency used to value the amount.
 | 
			
		||||
    Currency currency = 1;
 | 
			
		||||
 | 
			
		||||
    // The value of the amount. 8 bytes
 | 
			
		||||
    string value = 2;
 | 
			
		||||
 | 
			
		||||
    // Unique account address of the entity issuing the currency.
 | 
			
		||||
    AccountAddress issuer = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Currency {
 | 
			
		||||
 | 
			
		||||
    // 3 character ASCII code
 | 
			
		||||
    string name = 1;
 | 
			
		||||
 | 
			
		||||
    // 160 bit currency code. 20 bytes
 | 
			
		||||
    bytes code = 2;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								src/ripple/proto/rpc/v1/fee.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/ripple/proto/rpc/v1/fee.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
import "rpc/v1/amount.proto";
 | 
			
		||||
 | 
			
		||||
// A request for the current transaction fee on the ledger.
 | 
			
		||||
message GetFeeRequest {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Response to a GetFee RPC
 | 
			
		||||
message GetFeeResponse {
 | 
			
		||||
 | 
			
		||||
    uint64 current_ledger_size = 1;
 | 
			
		||||
 | 
			
		||||
    uint64 current_queue_size = 2;
 | 
			
		||||
 | 
			
		||||
    Fee drops = 3;
 | 
			
		||||
 | 
			
		||||
    uint64 expected_ledger_size = 4;
 | 
			
		||||
 | 
			
		||||
    uint32 ledger_current_index = 5;
 | 
			
		||||
 | 
			
		||||
    FeeLevels levels = 6;
 | 
			
		||||
 | 
			
		||||
    uint64 max_queue_size = 7;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Fee {
 | 
			
		||||
 | 
			
		||||
    XRPDropsAmount base_fee = 1;
 | 
			
		||||
 | 
			
		||||
    XRPDropsAmount median_fee = 2;
 | 
			
		||||
 | 
			
		||||
    XRPDropsAmount minimum_fee = 3;
 | 
			
		||||
 | 
			
		||||
    XRPDropsAmount open_ledger_fee = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message FeeLevels {
 | 
			
		||||
 | 
			
		||||
    uint64 median_level = 1;
 | 
			
		||||
 | 
			
		||||
    uint64 minimum_level = 2;
 | 
			
		||||
 | 
			
		||||
    uint64 open_ledger_level = 3;
 | 
			
		||||
 | 
			
		||||
    uint64 reference_level = 4;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										175
									
								
								src/ripple/proto/rpc/v1/ledger_objects.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								src/ripple/proto/rpc/v1/ledger_objects.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
import "rpc/v1/amount.proto";
 | 
			
		||||
 | 
			
		||||
message LedgerObject {
 | 
			
		||||
 | 
			
		||||
    oneof object {
 | 
			
		||||
        AccountRoot account_root = 1;
 | 
			
		||||
        RippleState ripple_state = 2;
 | 
			
		||||
        Offer offer = 3;
 | 
			
		||||
        SignerList signer_list = 4;
 | 
			
		||||
        DirectoryNode directory_node = 5;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum LedgerEntryType {
 | 
			
		||||
    LEDGER_ENTRY_TYPE_UNSPECIFIED     = 0;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_ACCOUNT_ROOT    = 1;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_AMENDMENTS      = 2;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_CHECK           = 3;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_DEPOSIT_PREAUTH = 4;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_DIRECTORY_NODE  = 5;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_ESCROW          = 6;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_FEE_SETTINGS    = 7;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_LEDGER_HASHES   = 8;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_OFFER           = 9;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_PAY_CHANNEL     = 10;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_RIPPLE_STATE    = 11;
 | 
			
		||||
    LEDGER_ENTRY_TYPE_SIGNER_LIST     = 12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message DirectoryNode {
 | 
			
		||||
 | 
			
		||||
    uint32 flags = 1;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes root_index = 2;
 | 
			
		||||
 | 
			
		||||
    repeated bytes indexes = 3;
 | 
			
		||||
 | 
			
		||||
    uint64 index_next = 4;
 | 
			
		||||
 | 
			
		||||
    uint64 index_previous = 5;
 | 
			
		||||
 | 
			
		||||
    string owner = 6;
 | 
			
		||||
 | 
			
		||||
    Currency taker_pays_currency = 7;
 | 
			
		||||
 | 
			
		||||
    // 20 bytes
 | 
			
		||||
    bytes taker_pays_issuer = 8;
 | 
			
		||||
 | 
			
		||||
    Currency taker_gets_currency = 9;
 | 
			
		||||
 | 
			
		||||
    // 20 bytes
 | 
			
		||||
    bytes taker_gets_issuer = 10;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message SignerList {
 | 
			
		||||
 | 
			
		||||
    uint32 flags = 1;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes previous_txn_id = 2;
 | 
			
		||||
 | 
			
		||||
    uint32 previous_transaction_ledger_sequence = 3;
 | 
			
		||||
 | 
			
		||||
    uint64 owner_node = 4;
 | 
			
		||||
 | 
			
		||||
    repeated SignerEntry signer_entries = 5;
 | 
			
		||||
 | 
			
		||||
    uint32 signer_list_id = 6;
 | 
			
		||||
 | 
			
		||||
    uint32 signer_quorum = 7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message SignerEntry {
 | 
			
		||||
 | 
			
		||||
    AccountAddress account = 1;
 | 
			
		||||
 | 
			
		||||
    // this is actually uint16, but protobuf can't express uint16
 | 
			
		||||
    uint32 signer_weight = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message AccountRoot {
 | 
			
		||||
 | 
			
		||||
    AccountAddress account = 1;
 | 
			
		||||
 | 
			
		||||
    XRPDropsAmount balance = 2;
 | 
			
		||||
 | 
			
		||||
    uint32 sequence = 3;
 | 
			
		||||
 | 
			
		||||
    uint32 flags = 4;
 | 
			
		||||
 | 
			
		||||
    uint32 owner_count = 5;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes previous_transaction_id = 6;
 | 
			
		||||
 | 
			
		||||
    uint32 previous_transaction_ledger_sequence = 7;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes account_transaction_id = 8;
 | 
			
		||||
 | 
			
		||||
    // Variable length
 | 
			
		||||
    bytes domain = 9;
 | 
			
		||||
 | 
			
		||||
    // 16 bytes
 | 
			
		||||
    bytes email_hash = 10;
 | 
			
		||||
 | 
			
		||||
    // Variable length
 | 
			
		||||
    bytes message_key = 11;
 | 
			
		||||
 | 
			
		||||
    // base58 encoding
 | 
			
		||||
    string regular_key = 12;
 | 
			
		||||
 | 
			
		||||
    uint32 tick_size = 13;
 | 
			
		||||
 | 
			
		||||
    uint32 transfer_rate = 14;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message RippleState {
 | 
			
		||||
 | 
			
		||||
    CurrencyAmount balance = 1;
 | 
			
		||||
 | 
			
		||||
    uint32 flags = 2;
 | 
			
		||||
 | 
			
		||||
    CurrencyAmount low_limit = 3;
 | 
			
		||||
 | 
			
		||||
    CurrencyAmount high_limit = 4;
 | 
			
		||||
 | 
			
		||||
    uint64 low_node = 5;
 | 
			
		||||
 | 
			
		||||
    uint64 high_node = 6;
 | 
			
		||||
 | 
			
		||||
    uint32 low_quality_in = 7;
 | 
			
		||||
 | 
			
		||||
    uint32 low_quality_out = 8;
 | 
			
		||||
 | 
			
		||||
    uint32 high_quality_in = 9;
 | 
			
		||||
 | 
			
		||||
    uint32 high_quality_out = 10;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes previous_transaction_id = 11;
 | 
			
		||||
 | 
			
		||||
    uint32 previous_transaction_ledger_sequence = 12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Offer {
 | 
			
		||||
 | 
			
		||||
    string account = 1;
 | 
			
		||||
 | 
			
		||||
    uint32 sequence = 2;
 | 
			
		||||
 | 
			
		||||
    uint32 flags = 3;
 | 
			
		||||
 | 
			
		||||
    CurrencyAmount taker_pays = 4;
 | 
			
		||||
 | 
			
		||||
    CurrencyAmount taker_gets = 5;
 | 
			
		||||
 | 
			
		||||
    bytes book_directory = 6;
 | 
			
		||||
 | 
			
		||||
    uint64 book_node = 7;
 | 
			
		||||
 | 
			
		||||
    uint64 owner_node = 8;
 | 
			
		||||
 | 
			
		||||
    uint32 expiration = 9;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes previous_transaction_id = 10;
 | 
			
		||||
 | 
			
		||||
    uint32 previous_transaction_ledger_sequence = 11;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								src/ripple/proto/rpc/v1/meta.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/ripple/proto/rpc/v1/meta.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
import "rpc/v1/amount.proto";
 | 
			
		||||
import "rpc/v1/ledger_objects.proto";
 | 
			
		||||
 | 
			
		||||
message Meta {
 | 
			
		||||
    // index in ledger
 | 
			
		||||
    uint64 transaction_index = 1;
 | 
			
		||||
 | 
			
		||||
    // result code indicating whether the transaction succeeded or failed
 | 
			
		||||
    TransactionResult transaction_result = 2;
 | 
			
		||||
 | 
			
		||||
   repeated AffectedNode affected_nodes = 3;
 | 
			
		||||
 | 
			
		||||
   CurrencyAmount delivered_amount = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message TransactionResult {
 | 
			
		||||
 | 
			
		||||
    enum ResultType {
 | 
			
		||||
        RESULT_TYPE_UNSPECIFIED = 0;
 | 
			
		||||
        // Claimed cost only
 | 
			
		||||
        RESULT_TYPE_TEC         = 1;
 | 
			
		||||
        // Failure
 | 
			
		||||
        RESULT_TYPE_TEF         = 2;
 | 
			
		||||
        // Local error
 | 
			
		||||
        RESULT_TYPE_TEL         = 3;
 | 
			
		||||
        // Malformed transaction
 | 
			
		||||
        RESULT_TYPE_TEM         = 4;
 | 
			
		||||
        // Retry
 | 
			
		||||
        RESULT_TYPE_TER         = 5;
 | 
			
		||||
        // Success
 | 
			
		||||
        RESULT_TYPE_TES         = 6;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // category of the transaction result
 | 
			
		||||
    ResultType result_type = 1;
 | 
			
		||||
 | 
			
		||||
    // full result string, i.e. tesSUCCESS
 | 
			
		||||
    string result = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message AffectedNode {
 | 
			
		||||
 | 
			
		||||
    LedgerEntryType ledger_entry_type = 1;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes ledger_index = 2;
 | 
			
		||||
 | 
			
		||||
    oneof node {
 | 
			
		||||
        CreatedNode created_node = 3;
 | 
			
		||||
        DeletedNode deleted_node = 4;
 | 
			
		||||
        ModifiedNode modified_node = 5;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message CreatedNode {
 | 
			
		||||
 | 
			
		||||
    LedgerObject new_fields = 1;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message DeletedNode {
 | 
			
		||||
 | 
			
		||||
    LedgerObject final_fields = 1;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ModifiedNode {
 | 
			
		||||
 | 
			
		||||
    LedgerObject final_fields = 1;
 | 
			
		||||
 | 
			
		||||
    LedgerObject previous_fields = 2;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes previous_transaction_id = 3;
 | 
			
		||||
 | 
			
		||||
    uint32 previous_transaction_ledger_sequence = 4;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								src/ripple/proto/rpc/v1/submit.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/ripple/proto/rpc/v1/submit.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
import "rpc/v1/meta.proto";
 | 
			
		||||
 | 
			
		||||
// A request to submit the signed transaction to the ledger.
 | 
			
		||||
message SubmitTransactionRequest {
 | 
			
		||||
    // The signed transaction to submit.
 | 
			
		||||
    bytes signed_transaction = 1;
 | 
			
		||||
 | 
			
		||||
    bool fail_hard = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A response when a signed transaction is submitted to the ledger.
 | 
			
		||||
message SubmitTransactionResponse {
 | 
			
		||||
    // Code indicating the preliminary result of the transaction.
 | 
			
		||||
    TransactionResult engine_result = 1;
 | 
			
		||||
 | 
			
		||||
    // Numeric code indicating the preliminary result of the transaction, directly correlated to engine_result.
 | 
			
		||||
    int64 engine_result_code = 2;
 | 
			
		||||
 | 
			
		||||
    // Human-readable explanation of the transaction's preliminary result.
 | 
			
		||||
    string engine_result_message = 3;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes hash = 4;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								src/ripple/proto/rpc/v1/transaction.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/ripple/proto/rpc/v1/transaction.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
import "rpc/v1/amount.proto";
 | 
			
		||||
 | 
			
		||||
// A class encompassing all transactions.
 | 
			
		||||
message Transaction {
 | 
			
		||||
    // The account originating the transaction.
 | 
			
		||||
    AccountAddress account = 1;
 | 
			
		||||
 | 
			
		||||
    // The fee attached to the transaction.
 | 
			
		||||
    XRPDropsAmount fee = 2;
 | 
			
		||||
 | 
			
		||||
    // The sequence number for the transaction.
 | 
			
		||||
    uint32 sequence = 3;
 | 
			
		||||
 | 
			
		||||
    // Data specific to a the type of transaction being submitted.
 | 
			
		||||
    oneof transaction_data {
 | 
			
		||||
        Payment payment = 4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Public key of the account which signed the transaction. Variable length
 | 
			
		||||
    bytes signing_public_key = 5;
 | 
			
		||||
 | 
			
		||||
    // Variable length
 | 
			
		||||
    bytes signature = 6;
 | 
			
		||||
 | 
			
		||||
    uint32 flags = 7;
 | 
			
		||||
 | 
			
		||||
    uint32 last_ledger_sequence = 8;
 | 
			
		||||
 | 
			
		||||
    uint32 source_tag = 9;
 | 
			
		||||
 | 
			
		||||
    repeated Memo memos = 10;
 | 
			
		||||
 | 
			
		||||
    repeated Signer signers = 11;
 | 
			
		||||
 | 
			
		||||
    bytes account_transaction_id = 12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Memo {
 | 
			
		||||
 | 
			
		||||
    // Variable length
 | 
			
		||||
    bytes memo_data = 1;
 | 
			
		||||
 | 
			
		||||
    // Variable length
 | 
			
		||||
    bytes memo_format = 2;
 | 
			
		||||
 | 
			
		||||
    // Variable length
 | 
			
		||||
    bytes memo_type = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Signer  {
 | 
			
		||||
 | 
			
		||||
    AccountAddress account = 1;
 | 
			
		||||
 | 
			
		||||
    // Variable length
 | 
			
		||||
    bytes transaction_signature = 2;
 | 
			
		||||
 | 
			
		||||
    // Variable length
 | 
			
		||||
    bytes signing_public_key = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Payment {
 | 
			
		||||
    // The amount of currency to pay, in either issued currency or XRP.
 | 
			
		||||
    CurrencyAmount amount = 1;
 | 
			
		||||
 | 
			
		||||
    // The destination of the payment.
 | 
			
		||||
    AccountAddress destination = 2;
 | 
			
		||||
 | 
			
		||||
    uint32 destination_tag = 3;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes invoice_id = 4;
 | 
			
		||||
 | 
			
		||||
    repeated Path paths = 5;
 | 
			
		||||
 | 
			
		||||
    CurrencyAmount send_max = 6;
 | 
			
		||||
 | 
			
		||||
    CurrencyAmount deliver_min = 7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Path {
 | 
			
		||||
 | 
			
		||||
    repeated PathElement elements = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message PathElement {
 | 
			
		||||
 | 
			
		||||
    AccountAddress account = 1;
 | 
			
		||||
 | 
			
		||||
    Currency currency = 2;
 | 
			
		||||
 | 
			
		||||
    AccountAddress issuer = 3;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								src/ripple/proto/rpc/v1/tx.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/ripple/proto/rpc/v1/tx.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
import "rpc/v1/transaction.proto";
 | 
			
		||||
import "rpc/v1/meta.proto";
 | 
			
		||||
 | 
			
		||||
message GetTxRequest {
 | 
			
		||||
    // hash of the transaction. 32 bytes
 | 
			
		||||
    bytes hash = 1;
 | 
			
		||||
 | 
			
		||||
    // if true, return data in binary format
 | 
			
		||||
    bool binary = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message GetTxResponse {
 | 
			
		||||
 | 
			
		||||
    // The actual transaction
 | 
			
		||||
    oneof serialized_transaction {
 | 
			
		||||
        Transaction transaction = 1;
 | 
			
		||||
        // Variable length
 | 
			
		||||
        bytes transaction_binary = 2;
 | 
			
		||||
    };
 | 
			
		||||
    // Sequence number of ledger that contains this transaction
 | 
			
		||||
    uint32 ledger_index = 3;
 | 
			
		||||
 | 
			
		||||
    // 32 bytes
 | 
			
		||||
    bytes hash = 4;
 | 
			
		||||
 | 
			
		||||
    // whether the ledger has been validated
 | 
			
		||||
    bool validated = 5;
 | 
			
		||||
 | 
			
		||||
    // metadata about the transaction
 | 
			
		||||
    oneof serialized_meta {
 | 
			
		||||
        Meta meta = 6;
 | 
			
		||||
        // Variable length
 | 
			
		||||
        bytes meta_binary = 7;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								src/ripple/proto/rpc/v1/xrp_ledger.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/ripple/proto/rpc/v1/xrp_ledger.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package rpc.v1;
 | 
			
		||||
 | 
			
		||||
import "rpc/v1/account_info.proto";
 | 
			
		||||
import "rpc/v1/fee.proto";
 | 
			
		||||
import "rpc/v1/submit.proto";
 | 
			
		||||
import "rpc/v1/tx.proto";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// RPCs available to interact with the XRP Ledger.
 | 
			
		||||
service XRPLedgerAPIService {
 | 
			
		||||
 | 
			
		||||
  // Get account info for an account on the XRP Ledger.
 | 
			
		||||
  rpc GetAccountInfo (GetAccountInfoRequest) returns (GetAccountInfoResponse);
 | 
			
		||||
 | 
			
		||||
  // Get the fee for a transaction on the XRP Ledger.
 | 
			
		||||
  rpc GetFee (GetFeeRequest) returns (GetFeeResponse);
 | 
			
		||||
 | 
			
		||||
  // Submit a signed transaction to the XRP Ledger.
 | 
			
		||||
  rpc SubmitTransaction (SubmitTransactionRequest) returns (SubmitTransactionResponse);
 | 
			
		||||
 | 
			
		||||
  // Get the status of a transaction
 | 
			
		||||
  rpc GetTx(GetTxRequest) returns (GetTxResponse);
 | 
			
		||||
}
 | 
			
		||||
@@ -37,6 +37,19 @@ namespace RPC {
 | 
			
		||||
 | 
			
		||||
/** The context of information needed to call an RPC. */
 | 
			
		||||
struct Context
 | 
			
		||||
{
 | 
			
		||||
    beast::Journal const j;
 | 
			
		||||
    Application& app;
 | 
			
		||||
    Resource::Charge& loadType;
 | 
			
		||||
    NetworkOPs& netOps;
 | 
			
		||||
    LedgerMaster& ledgerMaster;
 | 
			
		||||
    Resource::Consumer& consumer;
 | 
			
		||||
    Role role;
 | 
			
		||||
    std::shared_ptr<JobQueue::Coro> coro{};
 | 
			
		||||
    InfoSub::pointer infoSub{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct JsonContext : public Context
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Data passed in from HTTP headers.
 | 
			
		||||
@@ -47,20 +60,18 @@ struct Context
 | 
			
		||||
        boost::string_view forwardedFor;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    beast::Journal const j;
 | 
			
		||||
    Json::Value params;
 | 
			
		||||
    Application& app;
 | 
			
		||||
    Resource::Charge& loadType;
 | 
			
		||||
    NetworkOPs& netOps;
 | 
			
		||||
    LedgerMaster& ledgerMaster;
 | 
			
		||||
    Resource::Consumer& consumer;
 | 
			
		||||
    Role role;
 | 
			
		||||
 | 
			
		||||
    unsigned int apiVersion;
 | 
			
		||||
    std::shared_ptr<JobQueue::Coro> coro {};
 | 
			
		||||
    InfoSub::pointer infoSub {};
 | 
			
		||||
    Headers headers {};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class RequestType>
 | 
			
		||||
struct GRPCContext : public Context
 | 
			
		||||
{
 | 
			
		||||
    RequestType params;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // RPC
 | 
			
		||||
} // ripple
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
#define RIPPLE_RPC_DELIVEREDAMOUNT_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <rpc/v1/amount.pb.h>
 | 
			
		||||
 | 
			
		||||
namespace Json {
 | 
			
		||||
class Value;
 | 
			
		||||
@@ -35,6 +36,8 @@ class STTx;
 | 
			
		||||
 | 
			
		||||
namespace RPC {
 | 
			
		||||
 | 
			
		||||
struct JsonContext;
 | 
			
		||||
 | 
			
		||||
struct Context;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -56,6 +59,13 @@ insertDeliveredAmount(
 | 
			
		||||
void
 | 
			
		||||
insertDeliveredAmount(
 | 
			
		||||
    Json::Value& meta,
 | 
			
		||||
    JsonContext&,
 | 
			
		||||
    std::shared_ptr<Transaction>,
 | 
			
		||||
    TxMeta const&);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
insertDeliveredAmount(
 | 
			
		||||
    rpc::v1::CurrencyAmount& proto,
 | 
			
		||||
    Context&,
 | 
			
		||||
    std::shared_ptr<Transaction>,
 | 
			
		||||
    TxMeta const&);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								src/ripple/rpc/GRPCHandlers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/ripple/rpc/GRPCHandlers.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    This file is part of rippled: https://github.com/ripple/rippled
 | 
			
		||||
    Copyright (c) 2020 Ripple Labs Inc.
 | 
			
		||||
 | 
			
		||||
    Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
    purpose  with  or without fee is hereby granted, provided that the above
 | 
			
		||||
    copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
    THE  SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
    WITH  REGARD  TO  THIS  SOFTWARE  INCLUDING  ALL  IMPLIED  WARRANTIES  OF
 | 
			
		||||
    MERCHANTABILITY  AND  FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
			
		||||
    ANY  SPECIAL ,  DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
    WHATSOEVER  RESULTING  FROM  LOSS  OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
			
		||||
    ACTION  OF  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
			
		||||
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#ifndef RIPPLE_RPC_GRPCHANDLER_H_INCLUDED
 | 
			
		||||
#define RIPPLE_RPC_GRPCHANDLER_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <ripple/rpc/Context.h>
 | 
			
		||||
#include <grpcpp/grpcpp.h>
 | 
			
		||||
#include <rpc/v1/xrp_ledger.pb.h>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * These handlers are for gRPC. They each take in a protobuf message that is
 | 
			
		||||
 * nested inside RPC::GRPCContext<T>, where T is the request type
 | 
			
		||||
 * The return value is the response type, as well as a status
 | 
			
		||||
 * If the status is not Status::OK (meaning an error occurred), then only
 | 
			
		||||
 * the status will be sent to the client, and the response will be ommitted
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
std::pair<rpc::v1::GetAccountInfoResponse, grpc::Status>
 | 
			
		||||
doAccountInfoGrpc(RPC::GRPCContext<rpc::v1::GetAccountInfoRequest>& context);
 | 
			
		||||
 | 
			
		||||
std::pair<rpc::v1::GetFeeResponse, grpc::Status>
 | 
			
		||||
doFeeGrpc(RPC::GRPCContext<rpc::v1::GetFeeRequest>& context);
 | 
			
		||||
 | 
			
		||||
std::pair<rpc::v1::SubmitTransactionResponse, grpc::Status>
 | 
			
		||||
doSubmitGrpc(RPC::GRPCContext<rpc::v1::SubmitTransactionRequest>& context);
 | 
			
		||||
 | 
			
		||||
// NOTE, this only supports Payment transactions at this time
 | 
			
		||||
std::pair<rpc::v1::GetTxResponse, grpc::Status>
 | 
			
		||||
doTxGrpc(RPC::GRPCContext<rpc::v1::GetTxRequest>& context);
 | 
			
		||||
 | 
			
		||||
}  // namespace ripple
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -28,10 +28,10 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
namespace RPC {
 | 
			
		||||
 | 
			
		||||
struct Context;
 | 
			
		||||
struct JsonContext;
 | 
			
		||||
 | 
			
		||||
/** Execute an RPC command and store the results in a Json::Value. */
 | 
			
		||||
Status doCommand (RPC::Context&, Json::Value&);
 | 
			
		||||
Status doCommand (RPC::JsonContext&, Json::Value&);
 | 
			
		||||
 | 
			
		||||
Role roleRequired (unsigned int version, std::string const& method );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ void addChannel (Json::Value& jsonLines, SLE const& line)
 | 
			
		||||
//   limit: integer                 // optional
 | 
			
		||||
//   marker: opaque                 // optional, resume previous query
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doAccountChannels (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountChannels (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params (context.params);
 | 
			
		||||
    if (! params.isMember (jss::account))
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doAccountCurrencies (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountCurrencies (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto& params = context.params;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <ripple/app/main/Application.h>
 | 
			
		||||
#include <ripple/app/misc/TxQ.h>
 | 
			
		||||
#include <ripple/json/json_value.h>
 | 
			
		||||
@@ -27,7 +26,9 @@
 | 
			
		||||
#include <ripple/protocol/jss.h>
 | 
			
		||||
#include <ripple/protocol/UintTypes.h>
 | 
			
		||||
#include <ripple/rpc/Context.h>
 | 
			
		||||
#include <ripple/rpc/GRPCHandlers.h>
 | 
			
		||||
#include <ripple/rpc/impl/RPCHelpers.h>
 | 
			
		||||
#include <grpc/status.h>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
@@ -47,7 +48,7 @@ namespace ripple {
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// TODO(tom): what is that "default"?
 | 
			
		||||
Json::Value doAccountInfo (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountInfo (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto& params = context.params;
 | 
			
		||||
 | 
			
		||||
@@ -183,4 +184,93 @@ Json::Value doAccountInfo (RPC::Context& context)
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // ripple
 | 
			
		||||
std::pair<rpc::v1::GetAccountInfoResponse, grpc::Status>
 | 
			
		||||
doAccountInfoGrpc(RPC::GRPCContext<rpc::v1::GetAccountInfoRequest>& context)
 | 
			
		||||
{
 | 
			
		||||
    // Return values
 | 
			
		||||
    rpc::v1::GetAccountInfoResponse result;
 | 
			
		||||
    grpc::Status status = grpc::Status::OK;
 | 
			
		||||
 | 
			
		||||
    // input
 | 
			
		||||
    rpc::v1::GetAccountInfoRequest& params = context.params;
 | 
			
		||||
 | 
			
		||||
    // get ledger
 | 
			
		||||
    std::shared_ptr<ReadView const> ledger;
 | 
			
		||||
    auto lgrStatus = RPC::ledgerFromRequest(ledger, context);
 | 
			
		||||
    if (lgrStatus || !ledger)
 | 
			
		||||
    {
 | 
			
		||||
        grpc::Status errorStatus;
 | 
			
		||||
        if (lgrStatus.toErrorCode() == rpcINVALID_PARAMS)
 | 
			
		||||
        {
 | 
			
		||||
            errorStatus = grpc::Status(
 | 
			
		||||
                grpc::StatusCode::INVALID_ARGUMENT, lgrStatus.message());
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            errorStatus =
 | 
			
		||||
                grpc::Status(grpc::StatusCode::NOT_FOUND, lgrStatus.message());
 | 
			
		||||
        }
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result.set_ledger_index(ledger->info().seq);
 | 
			
		||||
    result.set_validated(
 | 
			
		||||
        RPC::isValidated(context.ledgerMaster, *ledger, context.app));
 | 
			
		||||
 | 
			
		||||
    // decode account
 | 
			
		||||
    AccountID accountID;
 | 
			
		||||
    std::string strIdent = params.account().address();
 | 
			
		||||
    error_code_i code =
 | 
			
		||||
        RPC::accountFromStringWithCode(accountID, strIdent, params.strict());
 | 
			
		||||
    if (code != rpcSUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        grpc::Status errorStatus{grpc::StatusCode::INVALID_ARGUMENT,
 | 
			
		||||
                                 "invalid account"};
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // get account data
 | 
			
		||||
    auto const sleAccepted = ledger->read(keylet::account(accountID));
 | 
			
		||||
    if (sleAccepted)
 | 
			
		||||
    {
 | 
			
		||||
        RPC::populateAccountRoot(*result.mutable_account_data(), *sleAccepted);
 | 
			
		||||
 | 
			
		||||
        // signer lists
 | 
			
		||||
        if (params.signer_lists())
 | 
			
		||||
        {
 | 
			
		||||
            auto const sleSigners = ledger->read(keylet::signers(accountID));
 | 
			
		||||
            if (sleSigners)
 | 
			
		||||
            {
 | 
			
		||||
                rpc::v1::SignerList& signerListProto =
 | 
			
		||||
                    *result.mutable_signer_list();
 | 
			
		||||
                RPC::populateSignerList(signerListProto, *sleSigners);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // queued transactions
 | 
			
		||||
        if (params.queue())
 | 
			
		||||
        {
 | 
			
		||||
            if (!ledger->open())
 | 
			
		||||
            {
 | 
			
		||||
                grpc::Status errorStatus{
 | 
			
		||||
                    grpc::StatusCode::INVALID_ARGUMENT,
 | 
			
		||||
                    "requested queue but ledger is not open"};
 | 
			
		||||
                return {result, errorStatus};
 | 
			
		||||
            }
 | 
			
		||||
            auto const txs =
 | 
			
		||||
                context.app.getTxQ().getAccountTxs(accountID, *ledger);
 | 
			
		||||
            rpc::v1::QueueData& queueData = *result.mutable_queue_data();
 | 
			
		||||
            RPC::populateQueueData(queueData, txs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        grpc::Status errorStatus{grpc::StatusCode::NOT_FOUND,
 | 
			
		||||
                                 "account not found"};
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {result, status};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace ripple
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ void addLine (Json::Value& jsonLines, RippleState const& line)
 | 
			
		||||
//   limit: integer                 // optional
 | 
			
		||||
//   marker: opaque                 // optional, resume previous query
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doAccountLines (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountLines (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params (context.params);
 | 
			
		||||
    if (! params.isMember (jss::account))
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ namespace ripple {
 | 
			
		||||
    }
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
Json::Value doAccountObjects (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountObjects (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params = context.params;
 | 
			
		||||
    if (! params.isMember (jss::account))
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ void appendOfferJson (std::shared_ptr<SLE const> const& offer,
 | 
			
		||||
//   limit: integer                 // optional
 | 
			
		||||
//   marker: opaque                 // optional, resume previous query
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doAccountOffers (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountOffers (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params (context.params);
 | 
			
		||||
    if (! params.isMember (jss::account))
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ namespace ripple {
 | 
			
		||||
//   limit: integer,                 // optional
 | 
			
		||||
//   marker: opaque                  // optional, resume previous query
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doAccountTx (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountTx (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto& params = context.params;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ namespace ripple {
 | 
			
		||||
//   offset: integer,              // optional, defaults to 0
 | 
			
		||||
//   limit: integer                // optional
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doAccountTxOld (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountTxOld (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    std::uint32_t offset
 | 
			
		||||
            = context.params.isMember (jss::offset)
 | 
			
		||||
 
 | 
			
		||||
@@ -25,11 +25,11 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doAccountTxOld (RPC::Context& context);
 | 
			
		||||
        Json::Value doAccountTx (RPC::Context& context);
 | 
			
		||||
Json::Value doAccountTxOld (RPC::JsonContext& context);
 | 
			
		||||
        Json::Value doAccountTx (RPC::JsonContext& context);
 | 
			
		||||
 | 
			
		||||
// Temporary switching code until the old account_tx is removed
 | 
			
		||||
Json::Value doAccountTxSwitch (RPC::Context& context)
 | 
			
		||||
Json::Value doAccountTxSwitch (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (context.params.isMember(jss::offset) ||
 | 
			
		||||
        context.params.isMember(jss::count) ||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doBlackList (RPC::Context& context)
 | 
			
		||||
Json::Value doBlackList (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto& rm = context.app.getResourceManager();
 | 
			
		||||
    if (context.params.isMember(jss::threshold))
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doBookOffers (RPC::Context& context)
 | 
			
		||||
Json::Value doBookOffers (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    // VFALCO TODO Here is a terrible place for this kind of business
 | 
			
		||||
    //             logic. It needs to be moved elsewhere and documented,
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
// can_delete [<ledgerid>|<ledgerhash>|now|always|never]
 | 
			
		||||
Json::Value doCanDelete (RPC::Context& context)
 | 
			
		||||
Json::Value doCanDelete (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (! context.app.getSHAMapStore().advisoryDelete())
 | 
			
		||||
        return RPC::make_error(rpcNOT_ENABLED);
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ namespace ripple {
 | 
			
		||||
//   port: <number>
 | 
			
		||||
// }
 | 
			
		||||
// XXX Might allow domain for manual connections.
 | 
			
		||||
Json::Value doConnect (RPC::Context& context)
 | 
			
		||||
Json::Value doConnect (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (context.app.config().standalone())
 | 
			
		||||
        return "cannot connect in standalone mode";
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doConsensusInfo (RPC::Context& context)
 | 
			
		||||
Json::Value doConsensusInfo (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value ret (Json::objectValue);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ namespace ripple {
 | 
			
		||||
    }
 | 
			
		||||
*/
 | 
			
		||||
Json::Value
 | 
			
		||||
doCrawlShards(RPC::Context& context)
 | 
			
		||||
doCrawlShards(RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (context.role != Role::ADMIN)
 | 
			
		||||
        return rpcError(rpcNO_PERMISSION);
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ namespace ripple {
 | 
			
		||||
//   ledger_index : <ledger_index>
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
Json::Value doDepositAuthorized (RPC::Context& context)
 | 
			
		||||
Json::Value doDepositAuthorized (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value const& params = context.params;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ namespace ripple {
 | 
			
		||||
    }
 | 
			
		||||
*/
 | 
			
		||||
Json::Value
 | 
			
		||||
doDownloadShard(RPC::Context& context)
 | 
			
		||||
doDownloadShard(RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (context.role != Role::ADMIN)
 | 
			
		||||
        return rpcError(rpcNO_PERMISSION);
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ namespace ripple {
 | 
			
		||||
//   feature : <feature>
 | 
			
		||||
//   vetoed : true/false
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doFeature (RPC::Context& context)
 | 
			
		||||
Json::Value doFeature (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    // Get majority amendment status
 | 
			
		||||
 
 | 
			
		||||
@@ -21,12 +21,14 @@
 | 
			
		||||
#include <ripple/app/main/Application.h>
 | 
			
		||||
#include <ripple/app/misc/TxQ.h>
 | 
			
		||||
#include <ripple/rpc/Context.h>
 | 
			
		||||
#include <ripple/rpc/GRPCHandlers.h>
 | 
			
		||||
#include <ripple/protocol/ErrorCodes.h>
 | 
			
		||||
#include <ripple/protocol/Feature.h>
 | 
			
		||||
#include <ripple/basics/mulDiv.h>
 | 
			
		||||
 | 
			
		||||
namespace ripple
 | 
			
		||||
{
 | 
			
		||||
    Json::Value doFee(RPC::Context& context)
 | 
			
		||||
    Json::Value doFee(RPC::JsonContext& context)
 | 
			
		||||
    {
 | 
			
		||||
        auto result = context.app.getTxQ().doRPC(context.app);
 | 
			
		||||
        if (result.type() == Json::objectValue)
 | 
			
		||||
@@ -35,4 +37,51 @@ namespace ripple
 | 
			
		||||
        RPC::inject_error(rpcINTERNAL, context.params);
 | 
			
		||||
        return context.params;
 | 
			
		||||
    }
 | 
			
		||||
} // ripple
 | 
			
		||||
 | 
			
		||||
std::pair<rpc::v1::GetFeeResponse, grpc::Status>
 | 
			
		||||
doFeeGrpc(RPC::GRPCContext<rpc::v1::GetFeeRequest>& context)
 | 
			
		||||
{
 | 
			
		||||
    rpc::v1::GetFeeResponse reply;
 | 
			
		||||
    grpc::Status status = grpc::Status::OK;
 | 
			
		||||
 | 
			
		||||
    Application& app = context.app;
 | 
			
		||||
    auto const view = app.openLedger().current();
 | 
			
		||||
    if (!view)
 | 
			
		||||
    {
 | 
			
		||||
        BOOST_ASSERT(false);
 | 
			
		||||
        return {reply, status};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto const metrics = app.getTxQ().getMetrics(*view);
 | 
			
		||||
 | 
			
		||||
    // current ledger data
 | 
			
		||||
    reply.set_current_ledger_size(metrics.txInLedger);
 | 
			
		||||
    reply.set_current_queue_size(metrics.txCount);
 | 
			
		||||
    reply.set_expected_ledger_size(metrics.txPerLedger);
 | 
			
		||||
    reply.set_ledger_current_index(view->info().seq);
 | 
			
		||||
    reply.set_max_queue_size(*metrics.txQMaxSize);
 | 
			
		||||
 | 
			
		||||
    // fee levels data
 | 
			
		||||
    rpc::v1::FeeLevels& levels = *reply.mutable_levels();
 | 
			
		||||
    levels.set_median_level(metrics.medFeeLevel.fee());
 | 
			
		||||
    levels.set_minimum_level(metrics.minProcessingFeeLevel.fee());
 | 
			
		||||
    levels.set_open_ledger_level(metrics.openLedgerFeeLevel.fee());
 | 
			
		||||
    levels.set_reference_level(metrics.referenceFeeLevel.fee());
 | 
			
		||||
 | 
			
		||||
    // fee data
 | 
			
		||||
    rpc::v1::Fee& drops = *reply.mutable_drops();
 | 
			
		||||
    auto const baseFee = view->fees().base;
 | 
			
		||||
    drops.mutable_base_fee()->set_drops(
 | 
			
		||||
        toDrops(metrics.referenceFeeLevel, baseFee).second.drops());
 | 
			
		||||
    drops.mutable_minimum_fee()->set_drops(
 | 
			
		||||
        toDrops(metrics.minProcessingFeeLevel, baseFee).second.drops());
 | 
			
		||||
    drops.mutable_median_fee()->set_drops(
 | 
			
		||||
        toDrops(metrics.medFeeLevel, baseFee).second.drops());
 | 
			
		||||
 | 
			
		||||
    drops.mutable_open_ledger_fee()->set_drops(
 | 
			
		||||
        (toDrops(metrics.openLedgerFeeLevel - FeeLevel64{1}, baseFee).second +
 | 
			
		||||
         1)
 | 
			
		||||
            .drops());
 | 
			
		||||
    return {reply, status};
 | 
			
		||||
}
 | 
			
		||||
}  // namespace ripple
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doFetchInfo (RPC::Context& context)
 | 
			
		||||
Json::Value doFetchInfo (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value ret (Json::objectValue);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ namespace ripple {
 | 
			
		||||
 | 
			
		||||
// gateway_balances [<ledger>] <account> [<howallet> [<hotwallet [...
 | 
			
		||||
 | 
			
		||||
Json::Value doGatewayBalances (RPC::Context& context)
 | 
			
		||||
Json::Value doGatewayBalances (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto& params = context.params;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -143,7 +143,7 @@ Json::Value getCountsJson(Application& app, int minObjectCount)
 | 
			
		||||
// {
 | 
			
		||||
//   min_count: <number>  // optional, defaults to 10
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doGetCounts (RPC::Context& context)
 | 
			
		||||
Json::Value doGetCounts (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    int minCount = 10;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,68 +24,68 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doAccountCurrencies     (RPC::Context&);
 | 
			
		||||
Json::Value doAccountInfo           (RPC::Context&);
 | 
			
		||||
Json::Value doAccountLines          (RPC::Context&);
 | 
			
		||||
Json::Value doAccountChannels       (RPC::Context&);
 | 
			
		||||
Json::Value doAccountObjects        (RPC::Context&);
 | 
			
		||||
Json::Value doAccountOffers         (RPC::Context&);
 | 
			
		||||
Json::Value doAccountTx             (RPC::Context&);
 | 
			
		||||
Json::Value doAccountTxSwitch       (RPC::Context&);
 | 
			
		||||
Json::Value doAccountTxOld          (RPC::Context&);
 | 
			
		||||
Json::Value doBookOffers            (RPC::Context&);
 | 
			
		||||
Json::Value doBlackList             (RPC::Context&);
 | 
			
		||||
Json::Value doCanDelete             (RPC::Context&);
 | 
			
		||||
Json::Value doChannelAuthorize      (RPC::Context&);
 | 
			
		||||
Json::Value doChannelVerify         (RPC::Context&);
 | 
			
		||||
Json::Value doConnect               (RPC::Context&);
 | 
			
		||||
Json::Value doConsensusInfo         (RPC::Context&);
 | 
			
		||||
Json::Value doDepositAuthorized     (RPC::Context&);
 | 
			
		||||
Json::Value doDownloadShard         (RPC::Context&);
 | 
			
		||||
Json::Value doFeature               (RPC::Context&);
 | 
			
		||||
Json::Value doFee                   (RPC::Context&);
 | 
			
		||||
Json::Value doFetchInfo             (RPC::Context&);
 | 
			
		||||
Json::Value doGatewayBalances       (RPC::Context&);
 | 
			
		||||
Json::Value doGetCounts             (RPC::Context&);
 | 
			
		||||
Json::Value doLedgerAccept          (RPC::Context&);
 | 
			
		||||
Json::Value doLedgerCleaner         (RPC::Context&);
 | 
			
		||||
Json::Value doLedgerClosed          (RPC::Context&);
 | 
			
		||||
Json::Value doLedgerCurrent         (RPC::Context&);
 | 
			
		||||
Json::Value doLedgerData            (RPC::Context&);
 | 
			
		||||
Json::Value doLedgerEntry           (RPC::Context&);
 | 
			
		||||
Json::Value doLedgerHeader          (RPC::Context&);
 | 
			
		||||
Json::Value doLedgerRequest         (RPC::Context&);
 | 
			
		||||
Json::Value doLogLevel              (RPC::Context&);
 | 
			
		||||
Json::Value doLogRotate             (RPC::Context&);
 | 
			
		||||
Json::Value doNoRippleCheck         (RPC::Context&);
 | 
			
		||||
Json::Value doOwnerInfo             (RPC::Context&);
 | 
			
		||||
Json::Value doPathFind              (RPC::Context&);
 | 
			
		||||
Json::Value doPeers                 (RPC::Context&);
 | 
			
		||||
Json::Value doPing                  (RPC::Context&);
 | 
			
		||||
Json::Value doPrint                 (RPC::Context&);
 | 
			
		||||
Json::Value doRandom                (RPC::Context&);
 | 
			
		||||
Json::Value doPeerReservationsAdd   (RPC::Context&);
 | 
			
		||||
Json::Value doPeerReservationsDel   (RPC::Context&);
 | 
			
		||||
Json::Value doPeerReservationsList  (RPC::Context&);
 | 
			
		||||
Json::Value doRipplePathFind        (RPC::Context&);
 | 
			
		||||
Json::Value doServerInfo            (RPC::Context&); // for humans
 | 
			
		||||
Json::Value doServerState           (RPC::Context&); // for machines
 | 
			
		||||
Json::Value doSign                  (RPC::Context&);
 | 
			
		||||
Json::Value doSignFor               (RPC::Context&);
 | 
			
		||||
Json::Value doCrawlShards           (RPC::Context&);
 | 
			
		||||
Json::Value doStop                  (RPC::Context&);
 | 
			
		||||
Json::Value doSubmit                (RPC::Context&);
 | 
			
		||||
Json::Value doSubmitMultiSigned     (RPC::Context&);
 | 
			
		||||
Json::Value doSubscribe             (RPC::Context&);
 | 
			
		||||
Json::Value doTransactionEntry      (RPC::Context&);
 | 
			
		||||
Json::Value doTx                    (RPC::Context&);
 | 
			
		||||
Json::Value doTxHistory             (RPC::Context&);
 | 
			
		||||
Json::Value doUnlList               (RPC::Context&);
 | 
			
		||||
Json::Value doUnsubscribe           (RPC::Context&);
 | 
			
		||||
Json::Value doValidationCreate      (RPC::Context&);
 | 
			
		||||
Json::Value doWalletPropose         (RPC::Context&);
 | 
			
		||||
Json::Value doValidators            (RPC::Context&);
 | 
			
		||||
Json::Value doValidatorListSites    (RPC::Context&);
 | 
			
		||||
Json::Value doAccountCurrencies     (RPC::JsonContext&);
 | 
			
		||||
Json::Value doAccountInfo           (RPC::JsonContext&);
 | 
			
		||||
Json::Value doAccountLines          (RPC::JsonContext&);
 | 
			
		||||
Json::Value doAccountChannels       (RPC::JsonContext&);
 | 
			
		||||
Json::Value doAccountObjects        (RPC::JsonContext&);
 | 
			
		||||
Json::Value doAccountOffers         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doAccountTx             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doAccountTxSwitch       (RPC::JsonContext&);
 | 
			
		||||
Json::Value doAccountTxOld          (RPC::JsonContext&);
 | 
			
		||||
Json::Value doBookOffers            (RPC::JsonContext&);
 | 
			
		||||
Json::Value doBlackList             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doCanDelete             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doChannelAuthorize      (RPC::JsonContext&);
 | 
			
		||||
Json::Value doChannelVerify         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doConnect               (RPC::JsonContext&);
 | 
			
		||||
Json::Value doConsensusInfo         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doDepositAuthorized     (RPC::JsonContext&);
 | 
			
		||||
Json::Value doDownloadShard         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doFeature               (RPC::JsonContext&);
 | 
			
		||||
Json::Value doFee                   (RPC::JsonContext&);
 | 
			
		||||
Json::Value doFetchInfo             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doGatewayBalances       (RPC::JsonContext&);
 | 
			
		||||
Json::Value doGetCounts             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLedgerAccept          (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLedgerCleaner         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLedgerClosed          (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLedgerCurrent         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLedgerData            (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLedgerEntry           (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLedgerHeader          (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLedgerRequest         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLogLevel              (RPC::JsonContext&);
 | 
			
		||||
Json::Value doLogRotate             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doNoRippleCheck         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doOwnerInfo             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doPathFind              (RPC::JsonContext&);
 | 
			
		||||
Json::Value doPeers                 (RPC::JsonContext&);
 | 
			
		||||
Json::Value doPing                  (RPC::JsonContext&);
 | 
			
		||||
Json::Value doPrint                 (RPC::JsonContext&);
 | 
			
		||||
Json::Value doRandom                (RPC::JsonContext&);
 | 
			
		||||
Json::Value doPeerReservationsAdd   (RPC::JsonContext&);
 | 
			
		||||
Json::Value doPeerReservationsDel   (RPC::JsonContext&);
 | 
			
		||||
Json::Value doPeerReservationsList  (RPC::JsonContext&);
 | 
			
		||||
Json::Value doRipplePathFind        (RPC::JsonContext&);
 | 
			
		||||
Json::Value doServerInfo            (RPC::JsonContext&); // for humans
 | 
			
		||||
Json::Value doServerState           (RPC::JsonContext&); // for machines
 | 
			
		||||
Json::Value doSign                  (RPC::JsonContext&);
 | 
			
		||||
Json::Value doSignFor               (RPC::JsonContext&);
 | 
			
		||||
Json::Value doCrawlShards           (RPC::JsonContext&);
 | 
			
		||||
Json::Value doStop                  (RPC::JsonContext&);
 | 
			
		||||
Json::Value doSubmit                (RPC::JsonContext&);
 | 
			
		||||
Json::Value doSubmitMultiSigned     (RPC::JsonContext&);
 | 
			
		||||
Json::Value doSubscribe             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doTransactionEntry      (RPC::JsonContext&);
 | 
			
		||||
Json::Value doTx                    (RPC::JsonContext&);
 | 
			
		||||
Json::Value doTxHistory             (RPC::JsonContext&);
 | 
			
		||||
Json::Value doUnlList               (RPC::JsonContext&);
 | 
			
		||||
Json::Value doUnsubscribe           (RPC::JsonContext&);
 | 
			
		||||
Json::Value doValidationCreate      (RPC::JsonContext&);
 | 
			
		||||
Json::Value doWalletPropose         (RPC::JsonContext&);
 | 
			
		||||
Json::Value doValidators            (RPC::JsonContext&);
 | 
			
		||||
Json::Value doValidatorListSites    (RPC::JsonContext&);
 | 
			
		||||
} // ripple
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doLedgerAccept (RPC::Context& context)
 | 
			
		||||
Json::Value doLedgerAccept (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_lock lock{context.app.getMasterMutex()};
 | 
			
		||||
    Json::Value jvResult;
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doLedgerCleaner (RPC::Context& context)
 | 
			
		||||
Json::Value doLedgerCleaner (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    context.app.getLedgerMaster().doLedgerCleaner (context.params);
 | 
			
		||||
    return RPC::makeObjectValue ("Cleaner configured");
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doLedgerClosed (RPC::Context& context)
 | 
			
		||||
Json::Value doLedgerClosed (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto ledger = context.ledgerMaster.getClosedLedger ();
 | 
			
		||||
    assert (ledger);
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doLedgerCurrent (RPC::Context& context)
 | 
			
		||||
Json::Value doLedgerCurrent (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value jvResult;
 | 
			
		||||
    jvResult[jss::ledger_current_index] =
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ namespace ripple {
 | 
			
		||||
//     ledger_index: chosen ledger's index
 | 
			
		||||
//     state:        array of state nodes
 | 
			
		||||
//     marker:       resume point, if any
 | 
			
		||||
Json::Value doLedgerData (RPC::Context& context)
 | 
			
		||||
Json::Value doLedgerData (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    std::shared_ptr<ReadView const> lpLedger;
 | 
			
		||||
    auto const& params = context.params;
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ namespace ripple {
 | 
			
		||||
//   ledger_index : <ledger_index>
 | 
			
		||||
//   ...
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doLedgerEntry (RPC::Context& context)
 | 
			
		||||
Json::Value doLedgerEntry (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    std::shared_ptr<ReadView const> lpLedger;
 | 
			
		||||
    auto jvResult = RPC::lookupLedger (lpLedger, context);
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
namespace RPC {
 | 
			
		||||
 | 
			
		||||
LedgerHandler::LedgerHandler (Context& context) : context_ (context)
 | 
			
		||||
LedgerHandler::LedgerHandler (JsonContext& context) : context_ (context)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ class Object;
 | 
			
		||||
namespace ripple {
 | 
			
		||||
namespace RPC {
 | 
			
		||||
 | 
			
		||||
struct Context;
 | 
			
		||||
struct JsonContext;
 | 
			
		||||
 | 
			
		||||
// ledger [id|index|current|closed] [full]
 | 
			
		||||
// {
 | 
			
		||||
@@ -48,7 +48,7 @@ struct Context;
 | 
			
		||||
 | 
			
		||||
class LedgerHandler {
 | 
			
		||||
public:
 | 
			
		||||
    explicit LedgerHandler (Context&);
 | 
			
		||||
    explicit LedgerHandler (JsonContext&);
 | 
			
		||||
 | 
			
		||||
    Status check ();
 | 
			
		||||
 | 
			
		||||
@@ -71,7 +71,7 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Context& context_;
 | 
			
		||||
    JsonContext& context_;
 | 
			
		||||
    std::shared_ptr<ReadView const> ledger_;
 | 
			
		||||
    std::vector<TxQ::TxDetails> queueTxs_;
 | 
			
		||||
    Json::Value result_;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ namespace ripple {
 | 
			
		||||
//   ledger_hash : <ledger>
 | 
			
		||||
//   ledger_index : <ledger_index>
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doLedgerHeader (RPC::Context& context)
 | 
			
		||||
Json::Value doLedgerHeader (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    std::shared_ptr<ReadView const> lpLedger;
 | 
			
		||||
    auto jvResult = RPC::lookupLedger (lpLedger, context);
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ namespace ripple {
 | 
			
		||||
//   ledger_hash : <ledger>
 | 
			
		||||
//   ledger_index : <ledger_index>
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doLedgerRequest (RPC::Context& context)
 | 
			
		||||
Json::Value doLedgerRequest (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const hasHash = context.params.isMember (jss::ledger_hash);
 | 
			
		||||
    auto const hasIndex = context.params.isMember (jss::ledger_index);
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doLogLevel (RPC::Context& context)
 | 
			
		||||
Json::Value doLogLevel (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    // log_level
 | 
			
		||||
    if (!context.params.isMember (jss::severity))
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doLogRotate (RPC::Context& context)
 | 
			
		||||
Json::Value doLogRotate (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    context.app.getPerfLog().rotate();
 | 
			
		||||
    return RPC::makeObjectValue (context.app.logs().rotate());
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
static void fillTransaction (
 | 
			
		||||
    RPC::Context& context,
 | 
			
		||||
    RPC::JsonContext& context,
 | 
			
		||||
    Json::Value& txArray,
 | 
			
		||||
    AccountID const& accountID,
 | 
			
		||||
    std::uint32_t& sequence,
 | 
			
		||||
@@ -55,7 +55,7 @@ static void fillTransaction (
 | 
			
		||||
//   role: gateway|user             // account role to assume
 | 
			
		||||
//   transactions: true             // optional, reccommend transactions
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doNoRippleCheck (RPC::Context& context)
 | 
			
		||||
Json::Value doNoRippleCheck (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params (context.params);
 | 
			
		||||
    if (! params.isMember (jss::account))
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ namespace ripple {
 | 
			
		||||
// {
 | 
			
		||||
//   'ident' : <indent>,
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doOwnerInfo (RPC::Context& context)
 | 
			
		||||
Json::Value doOwnerInfo (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (!context.params.isMember (jss::account) &&
 | 
			
		||||
        !context.params.isMember (jss::ident))
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doPathFind (RPC::Context& context)
 | 
			
		||||
Json::Value doPathFind (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (context.app.config().PATH_SEARCH_MAX == 0)
 | 
			
		||||
        return rpcError (rpcNOT_SUPPORTED);
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ namespace ripple {
 | 
			
		||||
//   channel_id: 256-bit channel id
 | 
			
		||||
//   drops: 64-bit uint (as string)
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doChannelAuthorize (RPC::Context& context)
 | 
			
		||||
Json::Value doChannelAuthorize (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params (context.params);
 | 
			
		||||
    for (auto const& p : {jss::channel_id, jss::amount})
 | 
			
		||||
@@ -94,7 +94,7 @@ Json::Value doChannelAuthorize (RPC::Context& context)
 | 
			
		||||
//   drops: 64-bit uint (as string)
 | 
			
		||||
//   signature: signature to verify
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doChannelVerify (RPC::Context& context)
 | 
			
		||||
Json::Value doChannelVerify (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params (context.params);
 | 
			
		||||
    for (auto const& p :
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doPeers (RPC::Context& context)
 | 
			
		||||
Json::Value doPeers (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value jvResult (Json::objectValue);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,10 +25,10 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
namespace RPC {
 | 
			
		||||
struct Context;
 | 
			
		||||
struct JsonContext;
 | 
			
		||||
} // RPC
 | 
			
		||||
 | 
			
		||||
Json::Value doPing (RPC::Context& context)
 | 
			
		||||
Json::Value doPing (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value ret(Json::objectValue);
 | 
			
		||||
    switch (context.role)
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doPrint (RPC::Context& context)
 | 
			
		||||
Json::Value doPrint (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    JsonPropertyStream stream;
 | 
			
		||||
    if (context.params.isObject()
 | 
			
		||||
 
 | 
			
		||||
@@ -28,14 +28,14 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
namespace RPC {
 | 
			
		||||
struct Context;
 | 
			
		||||
struct JsonContext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Result:
 | 
			
		||||
// {
 | 
			
		||||
//   random: <uint256>
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doRandom (RPC::Context& context)
 | 
			
		||||
Json::Value doRandom (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    // TODO(tom): the try/catch is almost certainly redundant, we catch at the
 | 
			
		||||
    // top level too.
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value
 | 
			
		||||
doPeerReservationsAdd(RPC::Context& context)
 | 
			
		||||
doPeerReservationsAdd(RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params = context.params;
 | 
			
		||||
 | 
			
		||||
@@ -86,7 +86,7 @@ doPeerReservationsAdd(RPC::Context& context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value
 | 
			
		||||
doPeerReservationsDel(RPC::Context& context)
 | 
			
		||||
doPeerReservationsDel(RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& params = context.params;
 | 
			
		||||
 | 
			
		||||
@@ -113,7 +113,7 @@ doPeerReservationsDel(RPC::Context& context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value
 | 
			
		||||
doPeerReservationsList(RPC::Context& context)
 | 
			
		||||
doPeerReservationsList(RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    auto const& reservations = context.app.peerReservations().list();
 | 
			
		||||
    // Enumerate the reservations in context.app.peerReservations()
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
// This interface is deprecated.
 | 
			
		||||
Json::Value doRipplePathFind (RPC::Context& context)
 | 
			
		||||
Json::Value doRipplePathFind (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (context.app.config().PATH_SEARCH_MAX == 0)
 | 
			
		||||
        return rpcError (rpcNOT_SUPPORTED);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doServerInfo (RPC::Context& context)
 | 
			
		||||
Json::Value doServerInfo (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value ret (Json::objectValue);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doServerState (RPC::Context& context)
 | 
			
		||||
Json::Value doServerState (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value ret (Json::objectValue);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ namespace ripple {
 | 
			
		||||
//   account: <signing account>
 | 
			
		||||
//   secret: <secret of signing account>
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doSignFor (RPC::Context& context)
 | 
			
		||||
Json::Value doSignFor (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (context.role != Role::ADMIN && !context.app.config().canSign())
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ namespace ripple {
 | 
			
		||||
//   tx_json: <object>,
 | 
			
		||||
//   secret: <secret>
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doSign (RPC::Context& context)
 | 
			
		||||
Json::Value doSign (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (context.role != Role::ADMIN && !context.app.config().canSign())
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,10 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
namespace RPC {
 | 
			
		||||
struct Context;
 | 
			
		||||
struct JsonContext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value doStop (RPC::Context& context)
 | 
			
		||||
Json::Value doStop (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_lock lock{context.app.getMasterMutex()};
 | 
			
		||||
    context.app.signalStop ();
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,12 @@
 | 
			
		||||
#include <ripple/resource/Fees.h>
 | 
			
		||||
#include <ripple/rpc/Context.h>
 | 
			
		||||
#include <ripple/rpc/impl/TransactionSign.h>
 | 
			
		||||
#include <ripple/rpc/GRPCHandlers.h>
 | 
			
		||||
#include <ripple/rpc/impl/RPCHelpers.h>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
static NetworkOPs::FailHard getFailHard (RPC::Context const& context)
 | 
			
		||||
static NetworkOPs::FailHard getFailHard (RPC::JsonContext const& context)
 | 
			
		||||
{
 | 
			
		||||
    return NetworkOPs::doFailHard (
 | 
			
		||||
        context.params.isMember ("fail_hard")
 | 
			
		||||
@@ -40,7 +42,7 @@ static NetworkOPs::FailHard getFailHard (RPC::Context const& context)
 | 
			
		||||
//   tx_json: <object>,
 | 
			
		||||
//   secret: <secret>
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doSubmit (RPC::Context& context)
 | 
			
		||||
Json::Value doSubmit (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    context.loadType = Resource::feeMediumBurdenRPC;
 | 
			
		||||
 | 
			
		||||
@@ -181,4 +183,100 @@ Json::Value doSubmit (RPC::Context& context)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // ripple
 | 
			
		||||
std::pair<rpc::v1::SubmitTransactionResponse, grpc::Status>
 | 
			
		||||
doSubmitGrpc(RPC::GRPCContext<rpc::v1::SubmitTransactionRequest>& context)
 | 
			
		||||
{
 | 
			
		||||
    // return values
 | 
			
		||||
    rpc::v1::SubmitTransactionResponse result;
 | 
			
		||||
    grpc::Status status = grpc::Status::OK;
 | 
			
		||||
 | 
			
		||||
    // input
 | 
			
		||||
    auto request = context.params;
 | 
			
		||||
 | 
			
		||||
    std::string const& tx = request.signed_transaction();
 | 
			
		||||
 | 
			
		||||
    // convert to blob
 | 
			
		||||
    Blob blob{tx.begin(), tx.end()};
 | 
			
		||||
 | 
			
		||||
    // serialize
 | 
			
		||||
    SerialIter sitTrans(makeSlice(blob));
 | 
			
		||||
    std::shared_ptr<STTx const> stpTrans;
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        stpTrans = std::make_shared<STTx const>(std::ref(sitTrans));
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception& e)
 | 
			
		||||
    {
 | 
			
		||||
        grpc::Status errorStatus{
 | 
			
		||||
            grpc::StatusCode::INVALID_ARGUMENT,
 | 
			
		||||
            "invalid transaction: " + std::string(e.what())};
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // check validity
 | 
			
		||||
    {
 | 
			
		||||
        if (!context.app.checkSigs())
 | 
			
		||||
            forceValidity(
 | 
			
		||||
                context.app.getHashRouter(),
 | 
			
		||||
                stpTrans->getTransactionID(),
 | 
			
		||||
                Validity::SigGoodOnly);
 | 
			
		||||
        auto [validity, reason] = checkValidity(
 | 
			
		||||
            context.app.getHashRouter(),
 | 
			
		||||
            *stpTrans,
 | 
			
		||||
            context.ledgerMaster.getCurrentLedger()->rules(),
 | 
			
		||||
            context.app.config());
 | 
			
		||||
        if (validity != Validity::Valid)
 | 
			
		||||
        {
 | 
			
		||||
            grpc::Status errorStatus{grpc::StatusCode::INVALID_ARGUMENT,
 | 
			
		||||
                                     "invalid transaction: " + reason};
 | 
			
		||||
            return {result, errorStatus};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string reason;
 | 
			
		||||
    auto tpTrans = std::make_shared<Transaction>(stpTrans, reason, context.app);
 | 
			
		||||
    if (tpTrans->getStatus() != NEW)
 | 
			
		||||
    {
 | 
			
		||||
        grpc::Status errorStatus{grpc::StatusCode::INVALID_ARGUMENT,
 | 
			
		||||
                                 "invalid transaction: " + reason};
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        auto const failType = NetworkOPs::doFailHard(request.fail_hard());
 | 
			
		||||
 | 
			
		||||
        // submit to network
 | 
			
		||||
        context.netOps.processTransaction(
 | 
			
		||||
            tpTrans, isUnlimited(context.role), true, failType);
 | 
			
		||||
    }
 | 
			
		||||
    catch (std::exception& e)
 | 
			
		||||
    {
 | 
			
		||||
        grpc::Status errorStatus{
 | 
			
		||||
            grpc::StatusCode::INVALID_ARGUMENT,
 | 
			
		||||
            "invalid transaction : " + std::string(e.what())};
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // return preliminary result
 | 
			
		||||
    if (temUNCERTAIN != tpTrans->getResult())
 | 
			
		||||
    {
 | 
			
		||||
        RPC::populateTransactionResultType(
 | 
			
		||||
            *result.mutable_engine_result(), tpTrans->getResult());
 | 
			
		||||
 | 
			
		||||
        std::string sToken;
 | 
			
		||||
        std::string sHuman;
 | 
			
		||||
 | 
			
		||||
        transResultInfo(tpTrans->getResult(), sToken, sHuman);
 | 
			
		||||
 | 
			
		||||
        result.mutable_engine_result()->set_result(sToken);
 | 
			
		||||
        result.set_engine_result_code(TERtoInt(tpTrans->getResult()));
 | 
			
		||||
        result.set_engine_result_message(sHuman);
 | 
			
		||||
 | 
			
		||||
        uint256 hash = tpTrans->getID();
 | 
			
		||||
        result.set_hash(hash.data(), hash.size());
 | 
			
		||||
    }
 | 
			
		||||
    return {result, status};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace ripple
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ namespace ripple {
 | 
			
		||||
//   SigningAccounts <array>,
 | 
			
		||||
//   tx_json: <object>,
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doSubmitMultiSigned (RPC::Context& context)
 | 
			
		||||
Json::Value doSubmitMultiSigned (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    // Bail if multisign is not enabled.
 | 
			
		||||
    if (! context.app.getLedgerMaster().getValidatedRules().
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doSubscribe (RPC::Context& context)
 | 
			
		||||
Json::Value doSubscribe (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    InfoSub::pointer ispSub;
 | 
			
		||||
    Json::Value jvResult (Json::objectValue);
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@ namespace ripple {
 | 
			
		||||
//
 | 
			
		||||
// XXX In this case, not specify either ledger does not mean ledger current. It
 | 
			
		||||
// means any ledger.
 | 
			
		||||
Json::Value doTransactionEntry (RPC::Context& context)
 | 
			
		||||
Json::Value doTransactionEntry (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    std::shared_ptr<ReadView const> lpLedger;
 | 
			
		||||
    Json::Value jvResult = RPC::lookupLedger (lpLedger, context);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@
 | 
			
		||||
#include <ripple/rpc/Context.h>
 | 
			
		||||
#include <ripple/rpc/DeliveredAmount.h>
 | 
			
		||||
#include <ripple/rpc/impl/RPCHelpers.h>
 | 
			
		||||
#include <ripple/rpc/GRPCHandlers.h>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
@@ -52,15 +53,22 @@ isHexTxID (std::string const& txid)
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
bool
 | 
			
		||||
isValidated (RPC::Context& context, std::uint32_t seq, uint256 const& hash)
 | 
			
		||||
isValidated(LedgerMaster& ledgerMaster, std::uint32_t seq, uint256 const& hash)
 | 
			
		||||
{
 | 
			
		||||
    if (!context.ledgerMaster.haveLedger (seq))
 | 
			
		||||
    if (!ledgerMaster.haveLedger (seq))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (seq > context.ledgerMaster.getValidatedLedger ()->info().seq)
 | 
			
		||||
    if (seq > ledgerMaster.getValidatedLedger ()->info().seq)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    return context.ledgerMaster.getHashBySeq (seq) == hash;
 | 
			
		||||
    return ledgerMaster.getHashBySeq (seq) == hash;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
bool
 | 
			
		||||
isValidated (RPC::JsonContext& context, std::uint32_t seq, uint256 const& hash)
 | 
			
		||||
{
 | 
			
		||||
    return isValidated(context.ledgerMaster, seq, hash);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
@@ -83,7 +91,7 @@ getMetaHex (Ledger const& ledger,
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value doTx (RPC::Context& context)
 | 
			
		||||
Json::Value doTx (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    if (!context.params.isMember (jss::transaction))
 | 
			
		||||
        return rpcError (rpcINVALID_PARAMS);
 | 
			
		||||
@@ -198,4 +206,117 @@ Json::Value doTx (RPC::Context& context)
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // ripple
 | 
			
		||||
std::pair<rpc::v1::GetTxResponse, grpc::Status>
 | 
			
		||||
doTxGrpc(RPC::GRPCContext<rpc::v1::GetTxRequest>& context)
 | 
			
		||||
{
 | 
			
		||||
    // return values
 | 
			
		||||
    rpc::v1::GetTxResponse result;
 | 
			
		||||
    grpc::Status status = grpc::Status::OK;
 | 
			
		||||
 | 
			
		||||
    // input
 | 
			
		||||
    rpc::v1::GetTxRequest& request = context.params;
 | 
			
		||||
 | 
			
		||||
    std::string const& hashBytes = request.hash();
 | 
			
		||||
    uint256 hash = uint256::fromVoid(hashBytes.data());
 | 
			
		||||
 | 
			
		||||
    // hash is included in the response
 | 
			
		||||
    result.set_hash(request.hash());
 | 
			
		||||
 | 
			
		||||
    auto ec{rpcSUCCESS};
 | 
			
		||||
 | 
			
		||||
    // get the transaction
 | 
			
		||||
    std::shared_ptr<Transaction> txn =
 | 
			
		||||
        context.app.getMasterTransaction().fetch(hash, ec);
 | 
			
		||||
 | 
			
		||||
    if (ec == rpcDB_DESERIALIZATION)
 | 
			
		||||
    {
 | 
			
		||||
        auto errorInfo = RPC::get_error_info(ec);
 | 
			
		||||
        grpc::Status errorStatus{grpc::StatusCode::INTERNAL,
 | 
			
		||||
                                 errorInfo.message.c_str()};
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
    if (!txn)
 | 
			
		||||
    {
 | 
			
		||||
        grpc::Status errorStatus{grpc::StatusCode::NOT_FOUND, "txn not found"};
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<STTx const> stTxn = txn->getSTransaction();
 | 
			
		||||
    if (stTxn->getTxnType() != ttPAYMENT)
 | 
			
		||||
    {
 | 
			
		||||
        auto getTypeStr = [&stTxn]() {
 | 
			
		||||
            return TxFormats::getInstance()
 | 
			
		||||
                .findByType(stTxn->getTxnType())
 | 
			
		||||
                ->getName();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        grpc::Status errorStatus{grpc::StatusCode::UNIMPLEMENTED,
 | 
			
		||||
                                 "txn type not supported: " + getTypeStr()};
 | 
			
		||||
        return {result, errorStatus};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // populate transaction data
 | 
			
		||||
    if (request.binary())
 | 
			
		||||
    {
 | 
			
		||||
        Serializer s = stTxn->getSerializer();
 | 
			
		||||
        result.set_transaction_binary(s.data(), s.size());
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        RPC::populateTransaction(*result.mutable_transaction(), stTxn);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result.set_ledger_index(txn->getLedger());
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Ledger const> ledger =
 | 
			
		||||
        context.ledgerMaster.getLedgerBySeq(txn->getLedger());
 | 
			
		||||
    // get meta data
 | 
			
		||||
    if (ledger)
 | 
			
		||||
    {
 | 
			
		||||
        if (request.binary())
 | 
			
		||||
        {
 | 
			
		||||
            SHAMapTreeNode::TNType type;
 | 
			
		||||
            auto const item = ledger->txMap().peekItem(txn->getID(), type);
 | 
			
		||||
 | 
			
		||||
            if (item && type == SHAMapTreeNode::tnTRANSACTION_MD)
 | 
			
		||||
            {
 | 
			
		||||
                SerialIter it(item->slice());
 | 
			
		||||
                it.skip(it.getVLDataLength());  // skip transaction
 | 
			
		||||
                Blob blob = it.getVL();
 | 
			
		||||
                Slice slice = makeSlice(blob);
 | 
			
		||||
                result.set_meta_binary(slice.data(), slice.size());
 | 
			
		||||
 | 
			
		||||
                bool validated = isValidated(
 | 
			
		||||
                    context.ledgerMaster,
 | 
			
		||||
                    ledger->info().seq,
 | 
			
		||||
                    ledger->info().hash);
 | 
			
		||||
                result.set_validated(validated);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            auto rawMeta = ledger->txRead(txn->getID()).second;
 | 
			
		||||
            if (rawMeta)
 | 
			
		||||
            {
 | 
			
		||||
                auto txMeta = std::make_shared<TxMeta>(
 | 
			
		||||
                    txn->getID(), ledger->seq(), *rawMeta);
 | 
			
		||||
 | 
			
		||||
                bool validated = isValidated(
 | 
			
		||||
                    context.ledgerMaster,
 | 
			
		||||
                    ledger->info().seq,
 | 
			
		||||
                    ledger->info().hash);
 | 
			
		||||
                result.set_validated(validated);
 | 
			
		||||
 | 
			
		||||
                RPC::populateMeta(*result.mutable_meta(), txMeta);
 | 
			
		||||
                insertDeliveredAmount(
 | 
			
		||||
                    *result.mutable_meta()->mutable_delivered_amount(),
 | 
			
		||||
                    context,
 | 
			
		||||
                    txn,
 | 
			
		||||
                    *txMeta);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return {result, status};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace ripple
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ namespace ripple {
 | 
			
		||||
// {
 | 
			
		||||
//   start: <index>
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doTxHistory (RPC::Context& context)
 | 
			
		||||
Json::Value doTxHistory (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    context.loadType = Resource::feeMediumBurdenRPC;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doUnlList (RPC::Context& context)
 | 
			
		||||
Json::Value doUnlList (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value obj (Json::objectValue);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value doUnsubscribe (RPC::Context& context)
 | 
			
		||||
Json::Value doUnsubscribe (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    InfoSub::pointer ispSub;
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ validationSeed (Json::Value const& params)
 | 
			
		||||
//
 | 
			
		||||
// This command requires Role::ADMIN access because it makes
 | 
			
		||||
// no sense to ask an untrusted server for this.
 | 
			
		||||
Json::Value doValidationCreate (RPC::Context& context)
 | 
			
		||||
Json::Value doValidationCreate (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value     obj (Json::objectValue);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value
 | 
			
		||||
doValidatorListSites(RPC::Context& context)
 | 
			
		||||
doValidatorListSites(RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    return context.app.validatorSites().getJson();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
Json::Value
 | 
			
		||||
doValidators(RPC::Context& context)
 | 
			
		||||
doValidators(RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    return context.app.validators().getJson();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ namespace RPC {
 | 
			
		||||
class VersionHandler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit VersionHandler (Context&) {}
 | 
			
		||||
    explicit VersionHandler (JsonContext&) {}
 | 
			
		||||
 | 
			
		||||
    Status check()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ estimate_entropy (std::string const& input)
 | 
			
		||||
// {
 | 
			
		||||
//  passphrase: <string>
 | 
			
		||||
// }
 | 
			
		||||
Json::Value doWalletPropose (RPC::Context& context)
 | 
			
		||||
Json::Value doWalletPropose (RPC::JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    return walletPropose (context.params);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -137,7 +137,7 @@ insertDeliveredAmount(
 | 
			
		||||
void
 | 
			
		||||
insertDeliveredAmount(
 | 
			
		||||
    Json::Value& meta,
 | 
			
		||||
    RPC::Context& context,
 | 
			
		||||
    RPC::JsonContext& context,
 | 
			
		||||
    std::shared_ptr<Transaction> transaction,
 | 
			
		||||
    TxMeta const& transactionMeta)
 | 
			
		||||
{
 | 
			
		||||
@@ -172,5 +172,80 @@ insertDeliveredAmount(
 | 
			
		||||
        std::move(serializedTx),
 | 
			
		||||
        transactionMeta);
 | 
			
		||||
}
 | 
			
		||||
} // RPC
 | 
			
		||||
} // ripple
 | 
			
		||||
 | 
			
		||||
// TODO get rid of the code duplication between this function and the preceding
 | 
			
		||||
// function
 | 
			
		||||
void
 | 
			
		||||
insertDeliveredAmount(
 | 
			
		||||
    rpc::v1::CurrencyAmount& proto,
 | 
			
		||||
    RPC::Context& context,
 | 
			
		||||
    std::shared_ptr<Transaction> transaction,
 | 
			
		||||
    TxMeta const& transactionMeta)
 | 
			
		||||
{
 | 
			
		||||
    if (!transaction)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    auto const serializedTx = transaction->getSTransaction();
 | 
			
		||||
    if (!serializedTx)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // These lambdas are used to compute the values lazily
 | 
			
		||||
    auto const getFix1623Enabled = [&context]() -> bool {
 | 
			
		||||
        auto const view = context.app.openLedger().current();
 | 
			
		||||
        if (!view)
 | 
			
		||||
            return false;
 | 
			
		||||
        return view->rules().enabled(fix1623);
 | 
			
		||||
    };
 | 
			
		||||
    auto const getLedgerIndex = [&transaction]() -> LedgerIndex {
 | 
			
		||||
        return transaction->getLedger();
 | 
			
		||||
    };
 | 
			
		||||
    auto const getCloseTime =
 | 
			
		||||
        [&context, &transaction]() -> boost::optional<NetClock::time_point> {
 | 
			
		||||
        return context.ledgerMaster.getCloseTimeBySeq(transaction->getLedger());
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        TxType const tt{serializedTx->getTxnType()};
 | 
			
		||||
        if (tt != ttPAYMENT &&
 | 
			
		||||
            tt != ttCHECK_CASH &&
 | 
			
		||||
            tt != ttACCOUNT_DELETE)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (tt == ttCHECK_CASH &&
 | 
			
		||||
            !getFix1623Enabled())
 | 
			
		||||
            return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if the transaction failed nothing could have been delivered.
 | 
			
		||||
    if (transactionMeta.getResultTER() != tesSUCCESS)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (transactionMeta.hasDeliveredAmount())
 | 
			
		||||
    {
 | 
			
		||||
        populateAmount(proto, transactionMeta.getDeliveredAmount());
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (serializedTx->isFieldPresent(sfAmount))
 | 
			
		||||
    {
 | 
			
		||||
        using namespace std::chrono_literals;
 | 
			
		||||
 | 
			
		||||
        // Ledger 4594095 is the first ledger in which the DeliveredAmount field
 | 
			
		||||
        // was present when a partial payment was made and its absence indicates
 | 
			
		||||
        // that the amount delivered is listed in the Amount field.
 | 
			
		||||
        //
 | 
			
		||||
        // If the ledger closed long after the DeliveredAmount code was deployed
 | 
			
		||||
        // then its absence indicates that the amount delivered is listed in the
 | 
			
		||||
        // Amount field. DeliveredAmount went live January 24, 2014.
 | 
			
		||||
        // 446000000 is in Feb 2014, well after DeliveredAmount went live
 | 
			
		||||
        if (getLedgerIndex() >= 4594095 ||
 | 
			
		||||
            getCloseTime() > NetClock::time_point{446000000s})
 | 
			
		||||
        {
 | 
			
		||||
            populateAmount(proto, serializedTx->getFieldAmount(sfAmount));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace RPC
 | 
			
		||||
}  // namespace ripple
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ namespace {
 | 
			
		||||
template <typename Function>
 | 
			
		||||
Handler::Method<Json::Value> byRef (Function const& f)
 | 
			
		||||
{
 | 
			
		||||
    return [f] (Context& context, Json::Value& result)
 | 
			
		||||
    return [f] (JsonContext& context, Json::Value& result)
 | 
			
		||||
    {
 | 
			
		||||
        result = f (context);
 | 
			
		||||
        if (result.type() != Json::objectValue)
 | 
			
		||||
@@ -44,7 +44,7 @@ Handler::Method<Json::Value> byRef (Function const& f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Object, class HandlerImpl>
 | 
			
		||||
Status handle (Context& context, Object& object)
 | 
			
		||||
Status handle (JsonContext& context, Object& object)
 | 
			
		||||
{
 | 
			
		||||
    HandlerImpl handler (context);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,9 @@
 | 
			
		||||
#include <ripple/core/Config.h>
 | 
			
		||||
#include <ripple/rpc/RPCHandler.h>
 | 
			
		||||
#include <ripple/rpc/Status.h>
 | 
			
		||||
#include <ripple/rpc/impl/Tuning.h>
 | 
			
		||||
#include <ripple/app/ledger/LedgerMaster.h>
 | 
			
		||||
#include <ripple/app/misc/NetworkOPs.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace Json {
 | 
			
		||||
@@ -43,7 +46,7 @@ enum Condition {
 | 
			
		||||
struct Handler
 | 
			
		||||
{
 | 
			
		||||
    template <class JsonValue>
 | 
			
		||||
    using Method = std::function <Status (Context&, JsonValue&)>;
 | 
			
		||||
    using Method = std::function <Status (JsonContext&, JsonValue&)>;
 | 
			
		||||
 | 
			
		||||
    const char* name_;
 | 
			
		||||
    Method<Json::Value> valueMethod_;
 | 
			
		||||
@@ -66,6 +69,55 @@ Json::Value makeObjectValue (
 | 
			
		||||
/** Return names of all methods. */
 | 
			
		||||
std::vector<char const*> getHandlerNames();
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
error_code_i conditionMet(Condition condition_required, T& context)
 | 
			
		||||
{
 | 
			
		||||
  if ((condition_required & NEEDS_NETWORK_CONNECTION) &&
 | 
			
		||||
      (context.netOps.getOperatingMode () < OperatingMode::SYNCING))
 | 
			
		||||
  {
 | 
			
		||||
      JLOG (context.j.info())
 | 
			
		||||
          << "Insufficient network mode for RPC: "
 | 
			
		||||
          << context.netOps.strOperatingMode ();
 | 
			
		||||
 | 
			
		||||
      return rpcNO_NETWORK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (context.app.getOPs().isAmendmentBlocked() &&
 | 
			
		||||
       (condition_required & NEEDS_CURRENT_LEDGER ||
 | 
			
		||||
        condition_required & NEEDS_CLOSED_LEDGER))
 | 
			
		||||
  {
 | 
			
		||||
      return rpcAMENDMENT_BLOCKED;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!context.app.config().standalone() &&
 | 
			
		||||
      condition_required & NEEDS_CURRENT_LEDGER)
 | 
			
		||||
  {
 | 
			
		||||
      if (context.ledgerMaster.getValidatedLedgerAge () >
 | 
			
		||||
          Tuning::maxValidatedLedgerAge)
 | 
			
		||||
      {
 | 
			
		||||
          return rpcNO_CURRENT;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      auto const cID = context.ledgerMaster.getCurrentLedgerIndex ();
 | 
			
		||||
      auto const vID = context.ledgerMaster.getValidLedgerIndex ();
 | 
			
		||||
 | 
			
		||||
      if (cID + 10 < vID)
 | 
			
		||||
      {
 | 
			
		||||
          JLOG (context.j.debug()) << "Current ledger ID(" << cID <<
 | 
			
		||||
              ") is less than validated ledger ID(" << vID << ")";
 | 
			
		||||
          return rpcNO_CURRENT;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((condition_required & NEEDS_CLOSED_LEDGER) &&
 | 
			
		||||
      !context.ledgerMaster.getClosedLedger ())
 | 
			
		||||
  {
 | 
			
		||||
      return rpcNO_CLOSED;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return rpcSUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // RPC
 | 
			
		||||
} // ripple
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,7 @@ namespace {
 | 
			
		||||
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
error_code_i fillHandler (Context& context,
 | 
			
		||||
error_code_i fillHandler (JsonContext& context,
 | 
			
		||||
                          Handler const * & result)
 | 
			
		||||
{
 | 
			
		||||
    if (! isUnlimited (context.role))
 | 
			
		||||
@@ -149,47 +149,10 @@ error_code_i fillHandler (Context& context,
 | 
			
		||||
    if (handler->role_ == Role::ADMIN && context.role != Role::ADMIN)
 | 
			
		||||
        return rpcNO_PERMISSION;
 | 
			
		||||
 | 
			
		||||
    if ((handler->condition_ & NEEDS_NETWORK_CONNECTION) &&
 | 
			
		||||
        (context.netOps.getOperatingMode () < OperatingMode::SYNCING))
 | 
			
		||||
    error_code_i res = conditionMet(handler->condition_,context);
 | 
			
		||||
    if(res != rpcSUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        JLOG (context.j.info())
 | 
			
		||||
            << "Insufficient network mode for RPC: "
 | 
			
		||||
            << context.netOps.strOperatingMode ();
 | 
			
		||||
 | 
			
		||||
        return rpcNO_NETWORK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (context.app.getOPs().isAmendmentBlocked() &&
 | 
			
		||||
         (handler->condition_ & NEEDS_CURRENT_LEDGER ||
 | 
			
		||||
          handler->condition_ & NEEDS_CLOSED_LEDGER))
 | 
			
		||||
    {
 | 
			
		||||
        return rpcAMENDMENT_BLOCKED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!context.app.config().standalone() &&
 | 
			
		||||
        handler->condition_ & NEEDS_CURRENT_LEDGER)
 | 
			
		||||
    {
 | 
			
		||||
        if (context.ledgerMaster.getValidatedLedgerAge () >
 | 
			
		||||
            Tuning::maxValidatedLedgerAge)
 | 
			
		||||
        {
 | 
			
		||||
            return rpcNO_CURRENT;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto const cID = context.ledgerMaster.getCurrentLedgerIndex ();
 | 
			
		||||
        auto const vID = context.ledgerMaster.getValidLedgerIndex ();
 | 
			
		||||
 | 
			
		||||
        if (cID + 10 < vID)
 | 
			
		||||
        {
 | 
			
		||||
            JLOG (context.j.debug()) << "Current ledger ID(" << cID <<
 | 
			
		||||
                ") is less than validated ledger ID(" << vID << ")";
 | 
			
		||||
            return rpcNO_CURRENT;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((handler->condition_ & NEEDS_CLOSED_LEDGER) &&
 | 
			
		||||
        !context.ledgerMaster.getClosedLedger ())
 | 
			
		||||
    {
 | 
			
		||||
        return rpcNO_CLOSED;
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result = handler;
 | 
			
		||||
@@ -198,7 +161,7 @@ error_code_i fillHandler (Context& context,
 | 
			
		||||
 | 
			
		||||
template <class Object, class Method>
 | 
			
		||||
Status callMethod (
 | 
			
		||||
    Context& context, Method method, std::string const& name, Object& result)
 | 
			
		||||
    JsonContext& context, Method method, std::string const& name, Object& result)
 | 
			
		||||
{
 | 
			
		||||
    static std::atomic<std::uint64_t> requestId {0};
 | 
			
		||||
    auto& perfLog = context.app.getPerfLog();
 | 
			
		||||
@@ -228,7 +191,7 @@ Status callMethod (
 | 
			
		||||
 | 
			
		||||
template <class Method, class Object>
 | 
			
		||||
void getResult (
 | 
			
		||||
    Context& context, Method method, Object& object, std::string const& name)
 | 
			
		||||
    JsonContext& context, Method method, Object& object, std::string const& name)
 | 
			
		||||
{
 | 
			
		||||
    auto&& result = Json::addObject (object, jss::result);
 | 
			
		||||
    if (auto status = callMethod (context, method, name, result))
 | 
			
		||||
@@ -261,7 +224,7 @@ void getResult (
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
Status doCommand (
 | 
			
		||||
    RPC::Context& context, Json::Value& result)
 | 
			
		||||
    RPC::JsonContext& context, Json::Value& result)
 | 
			
		||||
{
 | 
			
		||||
    Handler const * handler = nullptr;
 | 
			
		||||
    if (auto error = fillHandler (context, handler))
 | 
			
		||||
 
 | 
			
		||||
@@ -49,20 +49,20 @@ accountFromStringStrict(std::string const& account)
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value
 | 
			
		||||
accountFromString(
 | 
			
		||||
error_code_i
 | 
			
		||||
accountFromStringWithCode(
 | 
			
		||||
    AccountID& result, std::string const& strIdent, bool bStrict)
 | 
			
		||||
{
 | 
			
		||||
    if (auto accountID = accountFromStringStrict (strIdent))
 | 
			
		||||
    {
 | 
			
		||||
        result = *accountID;
 | 
			
		||||
        return Json::objectValue;
 | 
			
		||||
        return rpcSUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bStrict)
 | 
			
		||||
    {
 | 
			
		||||
        auto id = deprecatedParseBitcoinAccountID (strIdent);
 | 
			
		||||
        return rpcError (id ? rpcACT_BITCOIN : rpcACT_MALFORMED);
 | 
			
		||||
        return id ? rpcACT_BITCOIN : rpcACT_MALFORMED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We allow the use of the seeds which is poor practice
 | 
			
		||||
@@ -70,14 +70,26 @@ accountFromString(
 | 
			
		||||
    auto const seed = parseGenericSeed (strIdent);
 | 
			
		||||
 | 
			
		||||
    if (!seed)
 | 
			
		||||
        return rpcError (rpcBAD_SEED);
 | 
			
		||||
        return rpcBAD_SEED;
 | 
			
		||||
 | 
			
		||||
    auto const keypair = generateKeyPair (
 | 
			
		||||
        KeyType::secp256k1,
 | 
			
		||||
        *seed);
 | 
			
		||||
 | 
			
		||||
    result = calcAccountID (keypair.first);
 | 
			
		||||
    return Json::objectValue;
 | 
			
		||||
    return rpcSUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value
 | 
			
		||||
accountFromString(
 | 
			
		||||
    AccountID& result, std::string const& strIdent, bool bStrict)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    error_code_i code = accountFromStringWithCode(result, strIdent, bStrict);
 | 
			
		||||
    if(code != rpcSUCCESS)
 | 
			
		||||
        return rpcError(code);
 | 
			
		||||
    else
 | 
			
		||||
        return Json::objectValue;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
@@ -185,7 +197,7 @@ isValidatedOld(LedgerMaster& ledgerMaster, bool standalone)
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
Status
 | 
			
		||||
ledgerFromRequest(T& ledger, Context& context)
 | 
			
		||||
ledgerFromRequest(T& ledger, JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    static auto const minSequenceGap = 10;
 | 
			
		||||
 | 
			
		||||
@@ -286,6 +298,106 @@ ledgerFromRequest(T& ledger, Context& context)
 | 
			
		||||
 | 
			
		||||
    return Status::OK;
 | 
			
		||||
}
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
Status
 | 
			
		||||
ledgerFromRequest(
 | 
			
		||||
    T& ledger,
 | 
			
		||||
    GRPCContext<rpc::v1::GetAccountInfoRequest>& context)
 | 
			
		||||
{
 | 
			
		||||
    static auto const minSequenceGap = 10;
 | 
			
		||||
 | 
			
		||||
    ledger.reset();
 | 
			
		||||
 | 
			
		||||
    rpc::v1::GetAccountInfoRequest& request = context.params;
 | 
			
		||||
    auto& ledgerMaster = context.ledgerMaster;
 | 
			
		||||
 | 
			
		||||
    using LedgerCase = rpc::v1::LedgerSpecifier::LedgerCase;
 | 
			
		||||
    LedgerCase ledgerCase = request.ledger().ledger_case();
 | 
			
		||||
 | 
			
		||||
    if (ledgerCase == LedgerCase::kHash)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 ledgerHash = uint256::fromVoid(request.ledger().hash().data());
 | 
			
		||||
        if (ledgerHash.size() != request.ledger().hash().size())
 | 
			
		||||
            return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
 | 
			
		||||
 | 
			
		||||
        ledger = ledgerMaster.getLedgerByHash(ledgerHash);
 | 
			
		||||
        if (ledger == nullptr)
 | 
			
		||||
            return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
 | 
			
		||||
    }
 | 
			
		||||
    else if (ledgerCase == LedgerCase::kSequence)
 | 
			
		||||
    {
 | 
			
		||||
        ledger = ledgerMaster.getLedgerBySeq(request.ledger().sequence());
 | 
			
		||||
 | 
			
		||||
        if (ledger == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto cur = ledgerMaster.getCurrentLedger();
 | 
			
		||||
            if (cur->info().seq == request.ledger().sequence())
 | 
			
		||||
                ledger = cur;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (ledger == nullptr)
 | 
			
		||||
            return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
 | 
			
		||||
 | 
			
		||||
        if (ledger->info().seq > ledgerMaster.getValidLedgerIndex() &&
 | 
			
		||||
            isValidatedOld(ledgerMaster, context.app.config().standalone()))
 | 
			
		||||
        {
 | 
			
		||||
            ledger.reset();
 | 
			
		||||
            return {rpcNO_NETWORK, "InsufficientNetworkMode"};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else if (
 | 
			
		||||
        ledgerCase == LedgerCase::kShortcut ||
 | 
			
		||||
        ledgerCase == LedgerCase::LEDGER_NOT_SET)
 | 
			
		||||
    {
 | 
			
		||||
        if (isValidatedOld(ledgerMaster, context.app.config().standalone()))
 | 
			
		||||
            return {rpcNO_NETWORK, "InsufficientNetworkMode"};
 | 
			
		||||
 | 
			
		||||
        auto const shortcut = request.ledger().shortcut();
 | 
			
		||||
        if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED)
 | 
			
		||||
        {
 | 
			
		||||
            ledger = ledgerMaster.getValidatedLedger();
 | 
			
		||||
            if (ledger == nullptr)
 | 
			
		||||
                return {rpcNO_NETWORK, "InsufficientNetworkMode"};
 | 
			
		||||
 | 
			
		||||
            assert(!ledger->open());
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // note, if unspecified, defaults to current ledger
 | 
			
		||||
            if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED ||
 | 
			
		||||
                shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT)
 | 
			
		||||
            {
 | 
			
		||||
                ledger = ledgerMaster.getCurrentLedger();
 | 
			
		||||
                assert(ledger->open());
 | 
			
		||||
            }
 | 
			
		||||
            else if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
 | 
			
		||||
            {
 | 
			
		||||
                ledger = ledgerMaster.getClosedLedger();
 | 
			
		||||
                assert(!ledger->open());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (ledger == nullptr)
 | 
			
		||||
                return {rpcNO_NETWORK, "InsufficientNetworkMode"};
 | 
			
		||||
 | 
			
		||||
            if (ledger->info().seq + minSequenceGap <
 | 
			
		||||
                ledgerMaster.getValidLedgerIndex())
 | 
			
		||||
            {
 | 
			
		||||
                ledger.reset();
 | 
			
		||||
                return {rpcNO_NETWORK, "InsufficientNetworkMode"};
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return Status::OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// explicit instantiation of above function
 | 
			
		||||
template Status
 | 
			
		||||
ledgerFromRequest<>(
 | 
			
		||||
    std::shared_ptr<ReadView const>&,
 | 
			
		||||
    GRPCContext<rpc::v1::GetAccountInfoRequest>&);
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
 | 
			
		||||
@@ -334,7 +446,6 @@ isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
// The previous version of the lookupLedger command would accept the
 | 
			
		||||
// "ledger_index" argument as a string and silently treat it as a request to
 | 
			
		||||
@@ -356,7 +467,7 @@ isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
 | 
			
		||||
// optionally the fields "ledger_hash", "ledger_index" and
 | 
			
		||||
// "ledger_current_index", if they are defined.
 | 
			
		||||
Status
 | 
			
		||||
lookupLedger(std::shared_ptr<ReadView const>& ledger, Context& context,
 | 
			
		||||
lookupLedger(std::shared_ptr<ReadView const>& ledger, JsonContext& context,
 | 
			
		||||
    Json::Value& result)
 | 
			
		||||
{
 | 
			
		||||
    if (auto status = ledgerFromRequest (ledger, context))
 | 
			
		||||
@@ -379,7 +490,7 @@ lookupLedger(std::shared_ptr<ReadView const>& ledger, Context& context,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value
 | 
			
		||||
lookupLedger(std::shared_ptr<ReadView const>& ledger, Context& context)
 | 
			
		||||
lookupLedger(std::shared_ptr<ReadView const>& ledger, JsonContext& context)
 | 
			
		||||
{
 | 
			
		||||
    Json::Value result;
 | 
			
		||||
    if (auto status = lookupLedger (ledger, context, result))
 | 
			
		||||
@@ -433,7 +544,7 @@ injectSLE(Json::Value& jv, SLE const& sle)
 | 
			
		||||
 | 
			
		||||
boost::optional<Json::Value>
 | 
			
		||||
readLimitField(unsigned int& limit, Tuning::LimitRange const& range,
 | 
			
		||||
    Context const& context)
 | 
			
		||||
    JsonContext const& context)
 | 
			
		||||
{
 | 
			
		||||
    limit = range.rdefault;
 | 
			
		||||
    if (auto const& jvLimit = context.params[jss::limit])
 | 
			
		||||
@@ -712,6 +823,672 @@ chooseLedgerEntryType(Json::Value const& params)
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateAccountRoot(rpc::v1::AccountRoot& proto, STObject const& obj)
 | 
			
		||||
{
 | 
			
		||||
    if (obj.isFieldPresent(sfAccount))
 | 
			
		||||
    {
 | 
			
		||||
        AccountID account = obj.getAccountID(sfAccount);
 | 
			
		||||
        proto.mutable_account()->set_address(toBase58(account));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfBalance))
 | 
			
		||||
    {
 | 
			
		||||
        STAmount amount = obj.getFieldAmount(sfBalance);
 | 
			
		||||
        proto.mutable_balance()->set_drops(amount.xrp().drops());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfSequence))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_sequence(obj.getFieldU32(sfSequence));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfFlags))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_flags(obj.getFieldU32(sfFlags));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfOwnerCount))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_owner_count(obj.getFieldU32(sfOwnerCount));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfPreviousTxnID))
 | 
			
		||||
    {
 | 
			
		||||
        auto field = obj.getFieldH256(sfPreviousTxnID);
 | 
			
		||||
        proto.set_previous_transaction_id(field.data(), field.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfPreviousTxnLgrSeq))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_previous_transaction_ledger_sequence(
 | 
			
		||||
            obj.getFieldU32(sfPreviousTxnLgrSeq));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfAccountTxnID))
 | 
			
		||||
    {
 | 
			
		||||
        auto field = obj.getFieldH256(sfAccountTxnID);
 | 
			
		||||
        proto.set_account_transaction_id(field.data(), field.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfDomain))
 | 
			
		||||
    {
 | 
			
		||||
        auto field = obj.getFieldH256(sfDomain);
 | 
			
		||||
        proto.set_domain(field.data(), field.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfEmailHash))
 | 
			
		||||
    {
 | 
			
		||||
        auto field = obj.getFieldH128(sfEmailHash);
 | 
			
		||||
        proto.set_email_hash(field.data(), field.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfMessageKey))
 | 
			
		||||
    {
 | 
			
		||||
        auto field = obj.getFieldVL(sfMessageKey);
 | 
			
		||||
        proto.set_message_key(field.data(), field.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfRegularKey))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_regular_key(toBase58(obj.getAccountID(sfRegularKey)));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfTickSize))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_tick_size(obj.getFieldU8(sfTickSize));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfTransferRate))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_transfer_rate(obj.getFieldU32(sfTransferRate));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateRippleState(rpc::v1::RippleState& proto, STObject const& obj)
 | 
			
		||||
{
 | 
			
		||||
    if (obj.isFieldPresent(sfBalance))
 | 
			
		||||
    {
 | 
			
		||||
        STAmount amount = obj.getFieldAmount(sfBalance);
 | 
			
		||||
        populateAmount(*proto.mutable_balance(), amount);
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfFlags))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_flags(obj.getFieldU32(sfFlags));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfLowLimit))
 | 
			
		||||
    {
 | 
			
		||||
        STAmount amount = obj.getFieldAmount(sfLowLimit);
 | 
			
		||||
        populateAmount(*proto.mutable_low_limit(), amount);
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfHighLimit))
 | 
			
		||||
    {
 | 
			
		||||
        STAmount amount = obj.getFieldAmount(sfHighLimit);
 | 
			
		||||
        populateAmount(*proto.mutable_high_limit(), amount);
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfLowNode))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_low_node(obj.getFieldU64(sfLowNode));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfHighNode))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_high_node(obj.getFieldU64(sfHighNode));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfLowQualityIn))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_low_quality_in(obj.getFieldU32(sfLowQualityIn));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfLowQualityOut))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_low_quality_out(obj.getFieldU32(sfLowQualityOut));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfHighQualityIn))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_high_quality_in(obj.getFieldU32(sfHighQualityIn));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfHighQualityOut))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_high_quality_out(obj.getFieldU32(sfHighQualityOut));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateOffer(rpc::v1::Offer& proto, STObject const& obj)
 | 
			
		||||
{
 | 
			
		||||
    if (obj.isFieldPresent(sfAccount))
 | 
			
		||||
    {
 | 
			
		||||
        AccountID account = obj.getAccountID(sfAccount);
 | 
			
		||||
        proto.set_account(toBase58(account));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfSequence))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_sequence(obj.getFieldU32(sfSequence));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfFlags))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_flags(obj.getFieldU32(sfFlags));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfTakerPays))
 | 
			
		||||
    {
 | 
			
		||||
        STAmount amount = obj.getFieldAmount(sfTakerPays);
 | 
			
		||||
        populateAmount(*proto.mutable_taker_pays(), amount);
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfTakerGets))
 | 
			
		||||
    {
 | 
			
		||||
        STAmount amount = obj.getFieldAmount(sfTakerGets);
 | 
			
		||||
        populateAmount(*proto.mutable_taker_gets(), amount);
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfBookDirectory))
 | 
			
		||||
    {
 | 
			
		||||
        auto field = obj.getFieldVL(sfBookDirectory);
 | 
			
		||||
        proto.set_book_directory(field.data(), field.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfBookNode))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_book_node(obj.getFieldU64(sfBookNode));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfExpiration))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_expiration(obj.getFieldU32(sfExpiration));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateSignerList(rpc::v1::SignerList& proto, STObject const& obj)
 | 
			
		||||
{
 | 
			
		||||
    proto.set_flags(obj.getFieldU32(sfFlags));
 | 
			
		||||
 | 
			
		||||
    auto prevTxnID = obj.getFieldH256(sfPreviousTxnID);
 | 
			
		||||
    proto.set_previous_txn_id(prevTxnID.data(), prevTxnID.size());
 | 
			
		||||
 | 
			
		||||
    proto.set_previous_transaction_ledger_sequence(
 | 
			
		||||
        obj.getFieldU32(sfPreviousTxnLgrSeq));
 | 
			
		||||
 | 
			
		||||
    proto.set_owner_node(obj.getFieldU64(sfOwnerNode));
 | 
			
		||||
 | 
			
		||||
    proto.set_signer_list_id(obj.getFieldU32(sfSignerListID));
 | 
			
		||||
 | 
			
		||||
    proto.set_signer_quorum(obj.getFieldU32(sfSignerQuorum));
 | 
			
		||||
 | 
			
		||||
    STArray const& signerEntries = obj.getFieldArray(sfSignerEntries);
 | 
			
		||||
 | 
			
		||||
    for (auto it = signerEntries.begin(); it != signerEntries.end(); ++it)
 | 
			
		||||
    {
 | 
			
		||||
        rpc::v1::SignerEntry& signerEntryProto = *proto.add_signer_entries();
 | 
			
		||||
 | 
			
		||||
        signerEntryProto.mutable_account()->set_address(
 | 
			
		||||
            toBase58(it->getAccountID(sfAccount)));
 | 
			
		||||
        signerEntryProto.set_signer_weight(it->getFieldU16(sfSignerWeight));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateQueueData(
 | 
			
		||||
    rpc::v1::QueueData& proto,
 | 
			
		||||
    std::map<TxSeq, TxQ::AccountTxDetails const> const& txs)
 | 
			
		||||
{
 | 
			
		||||
    if (!txs.empty())
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_txn_count(txs.size());
 | 
			
		||||
        proto.set_lowest_sequence(txs.begin()->first);
 | 
			
		||||
        proto.set_highest_sequence(txs.rbegin()->first);
 | 
			
		||||
 | 
			
		||||
        boost::optional<bool> anyAuthChanged(false);
 | 
			
		||||
        boost::optional<XRPAmount> totalSpend(0);
 | 
			
		||||
 | 
			
		||||
        for (auto const& [txSeq, txDetails] : txs)
 | 
			
		||||
        {
 | 
			
		||||
            rpc::v1::QueuedTransaction& qt = *proto.add_transactions();
 | 
			
		||||
 | 
			
		||||
            qt.set_sequence(txSeq);
 | 
			
		||||
            qt.set_fee_level(txDetails.feeLevel.fee());
 | 
			
		||||
            if (txDetails.lastValid)
 | 
			
		||||
                qt.set_last_ledger_sequence(*txDetails.lastValid);
 | 
			
		||||
 | 
			
		||||
            if (txDetails.consequences)
 | 
			
		||||
            {
 | 
			
		||||
                qt.mutable_fee()->set_drops(
 | 
			
		||||
                    txDetails.consequences->fee.drops());
 | 
			
		||||
                auto spend = txDetails.consequences->potentialSpend +
 | 
			
		||||
                    txDetails.consequences->fee;
 | 
			
		||||
                qt.mutable_max_spend_drops()->set_drops(spend.drops());
 | 
			
		||||
                if (totalSpend)
 | 
			
		||||
                    *totalSpend += spend;
 | 
			
		||||
                auto authChanged =
 | 
			
		||||
                    txDetails.consequences->category == TxConsequences::blocker;
 | 
			
		||||
                if (authChanged)
 | 
			
		||||
                    anyAuthChanged.emplace(authChanged);
 | 
			
		||||
                qt.set_auth_change(authChanged);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (anyAuthChanged && !*anyAuthChanged)
 | 
			
		||||
                    anyAuthChanged.reset();
 | 
			
		||||
                totalSpend.reset();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (anyAuthChanged)
 | 
			
		||||
            proto.set_auth_change_queued(*anyAuthChanged);
 | 
			
		||||
        if (totalSpend)
 | 
			
		||||
            proto.mutable_max_spend_drops_total()->set_drops(
 | 
			
		||||
                (*totalSpend).drops());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateDirectoryNode(rpc::v1::DirectoryNode& proto, STObject const& obj)
 | 
			
		||||
{
 | 
			
		||||
    if (obj.isFieldPresent(sfOwner))
 | 
			
		||||
    {
 | 
			
		||||
        AccountID ownerAccount = obj.getAccountID(sfAccount);
 | 
			
		||||
        proto.set_owner(toBase58(ownerAccount));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfTakerPaysCurrency))
 | 
			
		||||
    {
 | 
			
		||||
        uint160 tpCurr = obj.getFieldH160(sfTakerPaysCurrency);
 | 
			
		||||
        proto.mutable_taker_pays_currency()->set_code(
 | 
			
		||||
            tpCurr.data(), tpCurr.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfTakerPaysIssuer))
 | 
			
		||||
    {
 | 
			
		||||
        uint160 tpIss = obj.getFieldH160(sfTakerPaysIssuer);
 | 
			
		||||
        proto.set_taker_pays_issuer(tpIss.data(), tpIss.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfTakerGetsCurrency))
 | 
			
		||||
    {
 | 
			
		||||
        uint160 tgCurr = obj.getFieldH160(sfTakerGetsCurrency);
 | 
			
		||||
        proto.mutable_taker_gets_currency()->set_code(
 | 
			
		||||
            tgCurr.data(), tgCurr.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfTakerGetsIssuer))
 | 
			
		||||
    {
 | 
			
		||||
        uint160 tgIss = obj.getFieldH160(sfTakerGetsIssuer);
 | 
			
		||||
        proto.set_taker_gets_issuer(tgIss.data(), tgIss.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfIndexes))
 | 
			
		||||
    {
 | 
			
		||||
        const STVector256& vec = obj.getFieldV256(sfIndexes);
 | 
			
		||||
        for (size_t i = 0; i < vec.size(); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            uint256 const& elt = vec[i];
 | 
			
		||||
            proto.add_indexes(elt.data(), elt.size());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfRootIndex))
 | 
			
		||||
    {
 | 
			
		||||
        uint256 rootIndex = obj.getFieldH256(sfRootIndex);
 | 
			
		||||
        proto.set_root_index(rootIndex.data(), rootIndex.size());
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfIndexNext))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_index_next(obj.getFieldU64(sfIndexNext));
 | 
			
		||||
    }
 | 
			
		||||
    if (obj.isFieldPresent(sfIndexPrevious))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_index_previous(obj.getFieldU64(sfIndexPrevious));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateLedgerEntryType(rpc::v1::AffectedNode& proto, std::uint16_t lgrType)
 | 
			
		||||
{
 | 
			
		||||
    switch (lgrType)
 | 
			
		||||
    {
 | 
			
		||||
        case ltACCOUNT_ROOT:
 | 
			
		||||
            proto.set_ledger_entry_type(
 | 
			
		||||
                rpc::v1::LEDGER_ENTRY_TYPE_ACCOUNT_ROOT);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltDIR_NODE:
 | 
			
		||||
            proto.set_ledger_entry_type(
 | 
			
		||||
                rpc::v1::LEDGER_ENTRY_TYPE_DIRECTORY_NODE);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltRIPPLE_STATE:
 | 
			
		||||
            proto.set_ledger_entry_type(
 | 
			
		||||
                rpc::v1::LEDGER_ENTRY_TYPE_RIPPLE_STATE);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltSIGNER_LIST:
 | 
			
		||||
            proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_SIGNER_LIST);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltOFFER:
 | 
			
		||||
            proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_OFFER);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltLEDGER_HASHES:
 | 
			
		||||
            proto.set_ledger_entry_type(
 | 
			
		||||
                rpc::v1::LEDGER_ENTRY_TYPE_LEDGER_HASHES);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltAMENDMENTS:
 | 
			
		||||
            proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_AMENDMENTS);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltFEE_SETTINGS:
 | 
			
		||||
            proto.set_ledger_entry_type(
 | 
			
		||||
                rpc::v1::LEDGER_ENTRY_TYPE_FEE_SETTINGS);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltESCROW:
 | 
			
		||||
            proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_ESCROW);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltPAYCHAN:
 | 
			
		||||
            proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_PAY_CHANNEL);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltCHECK:
 | 
			
		||||
            proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_CHECK);
 | 
			
		||||
            break;
 | 
			
		||||
        case ltDEPOSIT_PREAUTH:
 | 
			
		||||
            proto.set_ledger_entry_type(
 | 
			
		||||
                rpc::v1::LEDGER_ENTRY_TYPE_DEPOSIT_PREAUTH);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
void
 | 
			
		||||
populateFields(T& proto, STObject const& obj, std::uint16_t type)
 | 
			
		||||
{
 | 
			
		||||
    if (type == ltACCOUNT_ROOT)
 | 
			
		||||
    {
 | 
			
		||||
        RPC::populateAccountRoot(*proto.mutable_account_root(), obj);
 | 
			
		||||
    }
 | 
			
		||||
    else if (type == ltRIPPLE_STATE)
 | 
			
		||||
    {
 | 
			
		||||
        RPC::populateRippleState(*proto.mutable_ripple_state(), obj);
 | 
			
		||||
    }
 | 
			
		||||
    else if (type == ltOFFER)
 | 
			
		||||
    {
 | 
			
		||||
        RPC::populateOffer(*proto.mutable_offer(), obj);
 | 
			
		||||
    }
 | 
			
		||||
    else if (type == ltDIR_NODE)
 | 
			
		||||
    {
 | 
			
		||||
        RPC::populateDirectoryNode(*proto.mutable_directory_node(), obj);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // Ledger object not supported by protobuf/grpc yet
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateMeta(rpc::v1::Meta& proto, std::shared_ptr<TxMeta> txMeta)
 | 
			
		||||
{
 | 
			
		||||
    proto.set_transaction_index(txMeta->getIndex());
 | 
			
		||||
 | 
			
		||||
    populateTransactionResultType(
 | 
			
		||||
        *proto.mutable_transaction_result(), txMeta->getResultTER());
 | 
			
		||||
    proto.mutable_transaction_result()->set_result(
 | 
			
		||||
        transToken(txMeta->getResultTER()));
 | 
			
		||||
 | 
			
		||||
    STArray& nodes = txMeta->getNodes();
 | 
			
		||||
    for (auto it = nodes.begin(); it != nodes.end(); ++it)
 | 
			
		||||
    {
 | 
			
		||||
        STObject& obj = *it;
 | 
			
		||||
        rpc::v1::AffectedNode* node = proto.add_affected_nodes();
 | 
			
		||||
 | 
			
		||||
        // ledger index
 | 
			
		||||
        uint256 ledgerIndex = obj.getFieldH256(sfLedgerIndex);
 | 
			
		||||
        node->set_ledger_index(ledgerIndex.data(), ledgerIndex.size());
 | 
			
		||||
 | 
			
		||||
        // ledger entry type
 | 
			
		||||
        std::uint16_t lgrType = obj.getFieldU16(sfLedgerEntryType);
 | 
			
		||||
        populateLedgerEntryType(*node, lgrType);
 | 
			
		||||
 | 
			
		||||
        // modified node
 | 
			
		||||
        if (obj.getFName() == sfModifiedNode)
 | 
			
		||||
        {
 | 
			
		||||
            // final fields
 | 
			
		||||
            if (obj.isFieldPresent(sfFinalFields))
 | 
			
		||||
            {
 | 
			
		||||
                STObject& finalFields =
 | 
			
		||||
                    obj.getField(sfFinalFields).downcast<STObject>();
 | 
			
		||||
 | 
			
		||||
                rpc::v1::LedgerObject* finalFieldsProto =
 | 
			
		||||
                    node->mutable_modified_node()->mutable_final_fields();
 | 
			
		||||
 | 
			
		||||
                populateFields(*finalFieldsProto, finalFields, lgrType);
 | 
			
		||||
            }
 | 
			
		||||
            // previous fields
 | 
			
		||||
            if (obj.isFieldPresent(sfPreviousFields))
 | 
			
		||||
            {
 | 
			
		||||
                STObject& prevFields =
 | 
			
		||||
                    obj.getField(sfPreviousFields).downcast<STObject>();
 | 
			
		||||
 | 
			
		||||
                rpc::v1::LedgerObject* prevFieldsProto =
 | 
			
		||||
                    node->mutable_modified_node()->mutable_previous_fields();
 | 
			
		||||
 | 
			
		||||
                populateFields(*prevFieldsProto, prevFields, lgrType);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // prev txn id and prev txn ledger seq
 | 
			
		||||
            uint256 prevTxnId = obj.getFieldH256(sfPreviousTxnID);
 | 
			
		||||
            node->mutable_modified_node()->set_previous_transaction_id(
 | 
			
		||||
                prevTxnId.data(), prevTxnId.size());
 | 
			
		||||
 | 
			
		||||
            node->mutable_modified_node()
 | 
			
		||||
                ->set_previous_transaction_ledger_sequence(
 | 
			
		||||
                    obj.getFieldU32(sfPreviousTxnLgrSeq));
 | 
			
		||||
        }
 | 
			
		||||
        // created node
 | 
			
		||||
        else if (obj.getFName() == sfCreatedNode)
 | 
			
		||||
        {
 | 
			
		||||
            // new fields
 | 
			
		||||
            if (obj.isFieldPresent(sfNewFields))
 | 
			
		||||
            {
 | 
			
		||||
                STObject& newFields =
 | 
			
		||||
                    obj.getField(sfNewFields).downcast<STObject>();
 | 
			
		||||
 | 
			
		||||
                rpc::v1::LedgerObject* newFieldsProto =
 | 
			
		||||
                    node->mutable_created_node()->mutable_new_fields();
 | 
			
		||||
 | 
			
		||||
                populateFields(*newFieldsProto, newFields, lgrType);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // deleted node
 | 
			
		||||
        else if (obj.getFName() == sfDeletedNode)
 | 
			
		||||
        {
 | 
			
		||||
            // final fields
 | 
			
		||||
            if (obj.isFieldPresent(sfFinalFields))
 | 
			
		||||
            {
 | 
			
		||||
                STObject& finalFields =
 | 
			
		||||
                    obj.getField(sfFinalFields).downcast<STObject>();
 | 
			
		||||
 | 
			
		||||
                rpc::v1::LedgerObject* finalFieldsProto =
 | 
			
		||||
                    node->mutable_deleted_node()->mutable_final_fields();
 | 
			
		||||
 | 
			
		||||
                populateFields(*finalFieldsProto, finalFields, lgrType);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateAmount(rpc::v1::CurrencyAmount& proto, STAmount const& amount)
 | 
			
		||||
{
 | 
			
		||||
    if (amount.native())
 | 
			
		||||
    {
 | 
			
		||||
        proto.mutable_xrp_amount()->set_drops(amount.xrp().drops());
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        rpc::v1::IssuedCurrencyAmount* issued =
 | 
			
		||||
            proto.mutable_issued_currency_amount();
 | 
			
		||||
        Issue const& issue = amount.issue();
 | 
			
		||||
        Currency currency = issue.currency;
 | 
			
		||||
        issued->mutable_currency()->set_name(to_string(issue.currency));
 | 
			
		||||
        issued->mutable_currency()->set_code(currency.data(), currency.size());
 | 
			
		||||
        issued->set_value(to_string(amount.iou()));
 | 
			
		||||
        issued->mutable_issuer()->set_address(toBase58(issue.account));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateTransaction(
 | 
			
		||||
    rpc::v1::Transaction& proto,
 | 
			
		||||
    std::shared_ptr<STTx const> txnSt)
 | 
			
		||||
{
 | 
			
		||||
    AccountID account = txnSt->getAccountID(sfAccount);
 | 
			
		||||
    proto.mutable_account()->set_address(toBase58(account));
 | 
			
		||||
 | 
			
		||||
    STAmount amount = txnSt->getFieldAmount(sfAmount);
 | 
			
		||||
    populateAmount(*proto.mutable_payment()->mutable_amount(), amount);
 | 
			
		||||
 | 
			
		||||
    AccountID accountDest = txnSt->getAccountID(sfDestination);
 | 
			
		||||
    proto.mutable_payment()->mutable_destination()->set_address(
 | 
			
		||||
        toBase58(accountDest));
 | 
			
		||||
 | 
			
		||||
    STAmount fee = txnSt->getFieldAmount(sfFee);
 | 
			
		||||
    proto.mutable_fee()->set_drops(fee.xrp().drops());
 | 
			
		||||
 | 
			
		||||
    proto.set_sequence(txnSt->getFieldU32(sfSequence));
 | 
			
		||||
 | 
			
		||||
    Blob signingPubKey = txnSt->getFieldVL(sfSigningPubKey);
 | 
			
		||||
    proto.set_signing_public_key(signingPubKey.data(), signingPubKey.size());
 | 
			
		||||
 | 
			
		||||
    proto.set_flags(txnSt->getFieldU32(sfFlags));
 | 
			
		||||
 | 
			
		||||
    proto.set_last_ledger_sequence(txnSt->getFieldU32(sfLastLedgerSequence));
 | 
			
		||||
 | 
			
		||||
    Blob blob = txnSt->getFieldVL(sfTxnSignature);
 | 
			
		||||
    proto.set_signature(blob.data(), blob.size());
 | 
			
		||||
 | 
			
		||||
    if (txnSt->isFieldPresent(sfSourceTag))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_source_tag(txnSt->getFieldU32(sfSourceTag));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (txnSt->isFieldPresent(sfAccountTxnID))
 | 
			
		||||
    {
 | 
			
		||||
        auto field = txnSt->getFieldH256(sfAccountTxnID);
 | 
			
		||||
        proto.set_account_transaction_id(field.data(), field.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (txnSt->isFieldPresent(sfMemos))
 | 
			
		||||
    {
 | 
			
		||||
        auto memos = txnSt->getFieldArray(sfMemos);
 | 
			
		||||
        for (auto it = memos.begin(); it != memos.end(); ++it)
 | 
			
		||||
        {
 | 
			
		||||
            rpc::v1::Memo* elt = proto.add_memos();
 | 
			
		||||
            auto memo = it->getField(sfMemo).downcast<STObject>();
 | 
			
		||||
            if (memo.isFieldPresent(sfMemoData))
 | 
			
		||||
            {
 | 
			
		||||
                auto memoData = memo.getFieldVL(sfMemoData);
 | 
			
		||||
                elt->set_memo_data(memoData.data(), memoData.size());
 | 
			
		||||
            }
 | 
			
		||||
            if (memo.isFieldPresent(sfMemoFormat))
 | 
			
		||||
            {
 | 
			
		||||
                auto memoFormat = memo.getFieldVL(sfMemoFormat);
 | 
			
		||||
                elt->set_memo_format(memoFormat.data(), memoFormat.size());
 | 
			
		||||
            }
 | 
			
		||||
            if (memo.isFieldPresent(sfMemoType))
 | 
			
		||||
            {
 | 
			
		||||
                auto memoType = memo.getFieldVL(sfMemoType);
 | 
			
		||||
                elt->set_memo_type(memoType.data(), memoType.size());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (txnSt->isFieldPresent(sfSigners))
 | 
			
		||||
    {
 | 
			
		||||
        auto signers = txnSt->getFieldArray(sfSigners);
 | 
			
		||||
 | 
			
		||||
        for (auto it = signers.begin(); it != signers.end(); ++it)
 | 
			
		||||
        {
 | 
			
		||||
            rpc::v1::Signer* elt = proto.add_signers();
 | 
			
		||||
            auto signer = it->getField(sfSigner).downcast<STObject>();
 | 
			
		||||
            if (signer.isFieldPresent(sfAccount))
 | 
			
		||||
            {
 | 
			
		||||
                elt->mutable_account()->set_address(
 | 
			
		||||
                    toBase58(signer.getAccountID(sfAccount)));
 | 
			
		||||
            }
 | 
			
		||||
            if (signer.isFieldPresent(sfTxnSignature))
 | 
			
		||||
            {
 | 
			
		||||
                auto sig = signer.getFieldVL(sfTxnSignature);
 | 
			
		||||
                elt->set_transaction_signature(sig.data(), sig.size());
 | 
			
		||||
            }
 | 
			
		||||
            if (signer.isFieldPresent(sfSigningPubKey))
 | 
			
		||||
            {
 | 
			
		||||
                auto pubKey = signer.getFieldVL(sfSigningPubKey);
 | 
			
		||||
                elt->set_signing_public_key(pubKey.data(), pubKey.size());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (safe_cast<TxType>(txnSt->getFieldU16(sfTransactionType)) ==
 | 
			
		||||
        TxType::ttPAYMENT)
 | 
			
		||||
    {
 | 
			
		||||
        if (txnSt->isFieldPresent(sfSendMax))
 | 
			
		||||
        {
 | 
			
		||||
            STAmount const& sendMax = txnSt->getFieldAmount(sfSendMax);
 | 
			
		||||
            populateAmount(
 | 
			
		||||
                *proto.mutable_payment()->mutable_send_max(), sendMax);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (txnSt->isFieldPresent(sfInvoiceID))
 | 
			
		||||
        {
 | 
			
		||||
            auto invoice = txnSt->getFieldH256(sfInvoiceID);
 | 
			
		||||
            proto.mutable_payment()->set_invoice_id(
 | 
			
		||||
                invoice.data(), invoice.size());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (txnSt->isFieldPresent(sfDestinationTag))
 | 
			
		||||
        {
 | 
			
		||||
            proto.mutable_payment()->set_destination_tag(
 | 
			
		||||
                txnSt->getFieldU32(sfDestinationTag));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // populate path data
 | 
			
		||||
        STPathSet const& pathset = txnSt->getFieldPathSet(sfPaths);
 | 
			
		||||
        for (auto it = pathset.begin(); it < pathset.end(); ++it)
 | 
			
		||||
        {
 | 
			
		||||
            STPath const& path = *it;
 | 
			
		||||
 | 
			
		||||
            rpc::v1::Path* protoPath = proto.mutable_payment()->add_paths();
 | 
			
		||||
 | 
			
		||||
            for (auto it2 = path.begin(); it2 != path.end(); ++it2)
 | 
			
		||||
            {
 | 
			
		||||
                rpc::v1::PathElement* protoElement = protoPath->add_elements();
 | 
			
		||||
                STPathElement const& elt = *it2;
 | 
			
		||||
 | 
			
		||||
                if (elt.isOffer())
 | 
			
		||||
                {
 | 
			
		||||
                    if (elt.hasCurrency())
 | 
			
		||||
                    {
 | 
			
		||||
                        Currency const& currency = elt.getCurrency();
 | 
			
		||||
                        protoElement->mutable_currency()->set_name(
 | 
			
		||||
                            to_string(currency));
 | 
			
		||||
                    }
 | 
			
		||||
                    if (elt.hasIssuer())
 | 
			
		||||
                    {
 | 
			
		||||
                        AccountID const& issuer = elt.getIssuerID();
 | 
			
		||||
                        protoElement->mutable_issuer()->set_address(
 | 
			
		||||
                            toBase58(issuer));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    AccountID const& pathAccount = elt.getAccountID();
 | 
			
		||||
                    protoElement->mutable_account()->set_address(
 | 
			
		||||
                        toBase58(pathAccount));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
populateTransactionResultType(rpc::v1::TransactionResult& proto, TER result)
 | 
			
		||||
{
 | 
			
		||||
    if (isTecClaim(result))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEC);
 | 
			
		||||
    }
 | 
			
		||||
    if (isTefFailure(result))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEF);
 | 
			
		||||
    }
 | 
			
		||||
    if (isTelLocal(result))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEL);
 | 
			
		||||
    }
 | 
			
		||||
    if (isTemMalformed(result))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEM);
 | 
			
		||||
    }
 | 
			
		||||
    if (isTerRetry(result))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TER);
 | 
			
		||||
    }
 | 
			
		||||
    if (isTesSuccess(result))
 | 
			
		||||
    {
 | 
			
		||||
        proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TES);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
beast::SemanticVersion const firstVersion("1.0.0");
 | 
			
		||||
beast::SemanticVersion const goodVersion("1.0.0");
 | 
			
		||||
beast::SemanticVersion const lastVersion("1.0.0");
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user