mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-04 18:55:49 +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