mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 11:12:16 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
88
.clang-format
Normal file
88
.clang-format
Normal file
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Google
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None # All
|
||||
AllowShortIfStatementsOnASingleLine: false # true
|
||||
AllowShortLoopsOnASingleLine: false # true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: true # false
|
||||
# BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120 # 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
# ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
# JavaScriptQuotes: Leave
|
||||
# JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
# ObjCBlockIndentWidth: 2
|
||||
# ObjCSpaceAfterProperty: false
|
||||
# ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false # true
|
||||
SortIncludes: false # disabled, because we need case insensitive sort
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 100 # 8
|
||||
UseTab: Never
|
||||
...
|
12
.clang_complete
Normal file
12
.clang_complete
Normal file
|
@ -0,0 +1,12 @@
|
|||
-xc++
|
||||
-std=c++14
|
||||
-iquote .
|
||||
-iquote tdtl/
|
||||
-iquote tl/
|
||||
-iquote tl/generate/
|
||||
-iquote tdactor/
|
||||
-iquote tdnet/
|
||||
-iquote tdutils/
|
||||
-iquote ../ton-build/tdutils/
|
||||
-iquote crypto/
|
||||
-I/opt/local/include/
|
36
.gitattributes
vendored
Normal file
36
.gitattributes
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
* text=auto
|
||||
|
||||
*.cpp text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.hpp text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.h text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.c text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.fc text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.fif text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.tl text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.tlb text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.txt text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.sh text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent eol=lf
|
||||
*.cmake text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.in text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.tex text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.py text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
|
||||
*.ans text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.bat text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent eol=crlf
|
||||
*.fp text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.gradle text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.java text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.kt text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.md text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.php text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.pro text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.properties text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.ps1 text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent eol=crlf
|
||||
*.xml text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.yml text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
|
||||
third_party/** linguist-vendored
|
||||
|
||||
*.a binary
|
||||
*.jar binary
|
||||
*.tlo binary
|
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
__pycache__
|
||||
parser.out
|
||||
parsetab.py
|
||||
parsetab.pyc
|
||||
tdutils/generate/auto/
|
||||
tl/generate/auto/
|
||||
compile_commands.json
|
||||
crypto/block/block-auto.cpp
|
||||
crypto/block/block-auto.h
|
||||
crypto/smartcont/*-code.fif
|
||||
test/regression-tests.cache/
|
||||
*.swp
|
||||
**/*build*/
|
12
.gitmodules
vendored
Normal file
12
.gitmodules
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
[submodule "third-party/rocksdb"]
|
||||
path = third-party/rocksdb
|
||||
url = https://github.com/facebook/rocksdb.git
|
||||
[submodule "third-party/crc32c"]
|
||||
path = third-party/crc32c
|
||||
url = https://github.com/google/crc32c
|
||||
[submodule "third-party/abseil-cpp"]
|
||||
path = third-party/abseil-cpp
|
||||
url = https://github.com/abseil/abseil-cpp.git
|
||||
[submodule "third-party/libraptorq"]
|
||||
path = third-party/libraptorq
|
||||
url = https://github.com/ton-blockchain/libRaptorQ
|
74
CMake/AddCXXCompilerFlag.cmake
Normal file
74
CMake/AddCXXCompilerFlag.cmake
Normal file
|
@ -0,0 +1,74 @@
|
|||
# - Adds a compiler flag if it is supported by the compiler
|
||||
#
|
||||
# This function checks that the supplied compiler flag is supported and then
|
||||
# adds it to the corresponding compiler flags
|
||||
#
|
||||
# add_cxx_compiler_flag(<FLAG> [<VARIANT>])
|
||||
#
|
||||
# - Example
|
||||
#
|
||||
# include(AddCXXCompilerFlag)
|
||||
# add_cxx_compiler_flag(-Wall)
|
||||
# add_cxx_compiler_flag(-no-strict-aliasing RELEASE)
|
||||
# Requires CMake 2.6+
|
||||
|
||||
if (__add_cxx_compiler_flag)
|
||||
return()
|
||||
endif()
|
||||
set(__add_cxx_compiler_flag INCLUDED)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
function(mangle_compiler_flag FLAG OUTPUT)
|
||||
string(TOUPPER "HAVE_CXX_FLAG_${FLAG}" SANITIZED_FLAG)
|
||||
string(REPLACE "+" "X" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
set(${OUTPUT} "${SANITIZED_FLAG}" PARENT_SCOPE)
|
||||
endfunction(mangle_compiler_flag)
|
||||
|
||||
function(add_cxx_compiler_flag FLAG)
|
||||
string(REPLACE "-Wno-" "-W" MAIN_FLAG ${FLAG})
|
||||
mangle_compiler_flag("${MAIN_FLAG}" MANGLED_FLAG_NAME)
|
||||
if (DEFINED CMAKE_REQUIRED_FLAGS)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
|
||||
else()
|
||||
set(CMAKE_REQUIRED_FLAGS "${FLAG}")
|
||||
endif()
|
||||
check_cxx_compiler_flag("${MAIN_FLAG}" ${MANGLED_FLAG_NAME})
|
||||
if (DEFINED OLD_CMAKE_REQUIRED_FLAGS)
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
else()
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
endif()
|
||||
if (${MANGLED_FLAG_NAME})
|
||||
set(VARIANT ${ARGV1})
|
||||
if (ARGV1)
|
||||
string(TOUPPER "_${VARIANT}" VARIANT)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(add_required_cxx_compiler_flag FLAG)
|
||||
string(REPLACE "-Wno-" "-W" MAIN_FLAG ${FLAG})
|
||||
mangle_compiler_flag("${MAIN_FLAG}" MANGLED_FLAG_NAME)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
|
||||
check_cxx_compiler_flag("${MAIN_FLAG}" ${MANGLED_FLAG_NAME})
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
if (${MANGLED_FLAG_NAME})
|
||||
set(VARIANT ${ARGV1})
|
||||
if (ARGV1)
|
||||
string(TOUPPER "_${VARIANT}" VARIANT)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
else()
|
||||
message(FATAL_ERROR "Required flag '${FLAG}' is not supported by the compiler")
|
||||
endif()
|
||||
endfunction()
|
21
CMake/FindJeMalloc.cmake
Normal file
21
CMake/FindJeMalloc.cmake
Normal file
|
@ -0,0 +1,21 @@
|
|||
# - Find JeMalloc library
|
||||
# Find the native JeMalloc includes and library
|
||||
#
|
||||
# JEMALLOC_INCLUDE_DIR - where to find jemalloc.h, etc.
|
||||
# JEMALLOC_LIBRARIES - List of libraries when using jemalloc.
|
||||
# JEMALLOC_FOUND - True if jemalloc found.
|
||||
|
||||
find_path(JEMALLOC_INCLUDE_DIR
|
||||
NAMES jemalloc/jemalloc.h
|
||||
HINTS ${JEMALLOC_ROOT_DIR}/include)
|
||||
|
||||
find_library(JEMALLOC_LIBRARIES
|
||||
NAMES jemalloc
|
||||
HINTS ${JEMALLOC_ROOT_DIR}/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(jemalloc DEFAULT_MSG JEMALLOC_LIBRARIES JEMALLOC_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
JEMALLOC_LIBRARIES
|
||||
JEMALLOC_INCLUDE_DIR)
|
38
CMake/FindMHD.cmake
Normal file
38
CMake/FindMHD.cmake
Normal file
|
@ -0,0 +1,38 @@
|
|||
# - Try to find MHD
|
||||
# Once done this will define
|
||||
#
|
||||
# MHD_FOUND - system has MHD
|
||||
# MHD_INCLUDE_DIRS - the MHD include directory
|
||||
# MHD_LIBRARY - Link these to use MHD
|
||||
|
||||
find_path(
|
||||
MHD_INCLUDE_DIR
|
||||
NAMES microhttpd.h
|
||||
DOC "microhttpd include dir"
|
||||
)
|
||||
|
||||
find_library(
|
||||
MHD_LIBRARY
|
||||
NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll
|
||||
DOC "microhttpd library"
|
||||
)
|
||||
|
||||
set(MHD_INCLUDE_DIRS ${MHD_INCLUDE_DIR})
|
||||
set(MHD_LIBRARIES ${MHD_LIBRARY})
|
||||
|
||||
# debug library on windows
|
||||
# same naming convention as in qt (appending debug library with d)
|
||||
# boost is using the same "hack" as us with "optimized" and "debug"
|
||||
# official MHD project actually uses _d suffix
|
||||
if (MSVC)
|
||||
find_library(
|
||||
MHD_LIBRARY_DEBUG
|
||||
NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d
|
||||
DOC "mhd debug library"
|
||||
)
|
||||
set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(mhd DEFAULT_MSG MHD_INCLUDE_DIR MHD_LIBRARY)
|
||||
mark_as_advanced(MHD_INCLUDE_DIR MHD_LIBRARY)
|
25
CMake/FindReadline.cmake
Normal file
25
CMake/FindReadline.cmake
Normal file
|
@ -0,0 +1,25 @@
|
|||
if (APPLE)
|
||||
find_path(READLINE_INCLUDE_DIR readline/readline.h /usr/local/opt/readline/include /opt/local/include /opt/include /usr/local/include /usr/include NO_DEFAULT_PATH)
|
||||
endif()
|
||||
find_path(READLINE_INCLUDE_DIR readline/readline.h)
|
||||
|
||||
if (APPLE)
|
||||
find_library(READLINE_LIBRARY readline /usr/local/opt/readline/lib /opt/local/lib /opt/lib /usr/local/lib /usr/lib NO_DEFAULT_PATH)
|
||||
endif()
|
||||
find_library(READLINE_LIBRARY readline)
|
||||
|
||||
if (READLINE_INCLUDE_DIR AND READLINE_LIBRARY AND NOT GNU_READLINE_FOUND)
|
||||
set(CMAKE_REQUIRED_INCLUDES "${READLINE_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${READLINE_LIBRARY}")
|
||||
include(CheckCXXSourceCompiles)
|
||||
unset(GNU_READLINE_FOUND CACHE)
|
||||
check_cxx_source_compiles("#include <stdio.h>\n#include <readline/readline.h>\nint main() { rl_replace_line(\"\", 0); }" GNU_READLINE_FOUND)
|
||||
if (NOT GNU_READLINE_FOUND)
|
||||
unset(READLINE_INCLUDE_DIR CACHE)
|
||||
unset(READLINE_LIBRARY CACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Readline DEFAULT_MSG READLINE_INCLUDE_DIR READLINE_LIBRARY)
|
||||
mark_as_advanced(READLINE_INCLUDE_DIR READLINE_LIBRARY)
|
1936
CMake/UseLATEX.cmake
Normal file
1936
CMake/UseLATEX.cmake
Normal file
File diff suppressed because it is too large
Load diff
452
CMakeLists.txt
Normal file
452
CMakeLists.txt
Normal file
|
@ -0,0 +1,452 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
project(TON VERSION 0.5 LANGUAGES C CXX)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
#set(OPENSSL_USE_STATIC_LIBS TRUE)
|
||||
|
||||
# Prevent in-source build
|
||||
get_filename_component(TON_REAL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH)
|
||||
get_filename_component(TON_REAL_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" REALPATH)
|
||||
|
||||
if (TON_REAL_BINARY_DIR STREQUAL TON_REAL_SOURCE_DIR)
|
||||
message(" Out-of-source build should be used to build TDLib.")
|
||||
message(" You need to remove the files already created by CMake and")
|
||||
message(" rerun CMake from a new directory:")
|
||||
message(" rm -rf CMakeFiles CMakeCache.txt")
|
||||
message(" mkdir build")
|
||||
message(" cd build")
|
||||
message(" cmake ..")
|
||||
message(FATAL_ERROR "In-source build failed.")
|
||||
endif()
|
||||
|
||||
#BEGIN internal
|
||||
option(TON_USE_ROCKSDB "Use \"ON\" to enable RocksDb." ON)
|
||||
option(TON_USE_ABSEIL "Use \"ON\" to enable Abseil." ON)
|
||||
option(TON_USE_JEMALLOC "Use \"ON\" to enable JeMalloc." OFF)
|
||||
#END internal
|
||||
|
||||
option(TONLIB_ENABLE_JNI "Use \"ON\" to enable JNI-compatible TonLib API.")
|
||||
option(TON_USE_ASAN "Use \"ON\" to enable AddressSanitizer." OFF)
|
||||
option(TON_USE_TSAN "Use \"ON\" to enable ThreadSanitizer." OFF)
|
||||
option(TON_USE_UBSAN "Use \"ON\" to enable UndefinedBehaviorSanitizer." OFF)
|
||||
set(TON_ARCH "native" CACHE STRING "Architecture, will be passed to -march=")
|
||||
|
||||
if (TON_USE_ABSEIL)
|
||||
message("Add abseil-cpp")
|
||||
add_subdirectory(third-party/abseil-cpp EXCLUDE_FROM_ALL)
|
||||
set(ABSL_FOUND 1)
|
||||
endif()
|
||||
|
||||
#add_subdirectory(third-party/libcuckoo EXCLUDE_FROM_ALL)
|
||||
#add_subdirectory(third-party/junction EXCLUDE_FROM_ALL)
|
||||
|
||||
if (WIN32)
|
||||
message("Add wingetopt")
|
||||
add_subdirectory(third-party/wingetopt EXCLUDE_FROM_ALL)
|
||||
set(WINGETOPT_FOUND 1)
|
||||
message(STATUS "Use wingetopt")
|
||||
endif()
|
||||
|
||||
set(CRC32C_BUILD_TESTS OFF CACHE BOOL "Build CRC32C's unit tests")
|
||||
set(CRC32C_BUILD_BENCHMARKS OFF CACHE BOOL "Build CRC32C's benchmarks")
|
||||
set(CRC32C_USE_GLOG OFF CACHE BOOL "Build CRC32C's tests with Google Logging")
|
||||
set(CRC32C_INSTALL OFF CACHE BOOL "Install CRC32C's header and library")
|
||||
message("Add crc32c")
|
||||
add_subdirectory(third-party/crc32c EXCLUDE_FROM_ALL)
|
||||
set(CRC32C_FOUND 1)
|
||||
|
||||
if (TON_USE_ROCKSDB)
|
||||
if (ANDROID)
|
||||
set(PORTABLE ON CACHE BOOL "portable")
|
||||
endif()
|
||||
set(WITH_TESTS OFF CACHE BOOL "build with tests")
|
||||
set(WITH_TOOLS OFF CACHE BOOL "build with tools")
|
||||
set(FAIL_ON_WARNINGS OFF CACHE BOOL "fail on warnings")
|
||||
message("Add rocksdb")
|
||||
add_subdirectory(third-party/rocksdb EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
option(USE_COROUTINES "experimental support of coroutines" OFF)
|
||||
if (USE_COROUTINES)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(TD_HAVE_COROUTINES 1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines-ts")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(USE_LIBRAPTORQ "use libraptorq for tests" OFF)
|
||||
if (USE_LIBRAPTORQ)
|
||||
set(USE_LZ4 OFF CACHE BOOL "use lz4")
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CLANG_STDLIB "ON") # for libraptorq
|
||||
endif()
|
||||
message("Add libraptorq")
|
||||
add_subdirectory(third-party/libraptorq EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
message("Add ton")
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
|
||||
|
||||
# Configure CCache if available
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
#set(CCACHE_FOUND 0)
|
||||
if (CCACHE_FOUND)
|
||||
message(STATUS "Found ccache")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
else()
|
||||
message(STATUS "Could NOT find ccache")
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(GCC 1)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CLANG 1)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
set(INTEL 1)
|
||||
elseif (NOT MSVC)
|
||||
message(FATAL_ERROR "Compiler isn't supported")
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if (GCC OR CLANG OR INTEL)
|
||||
if (WIN32 AND INTEL)
|
||||
set(STD14_FLAG /Qstd=c++14)
|
||||
else()
|
||||
set(STD14_FLAG -std=c++14)
|
||||
endif()
|
||||
check_cxx_compiler_flag(${STD14_FLAG} HAVE_STD14)
|
||||
if (NOT HAVE_STD14)
|
||||
string(REPLACE "c++14" "c++1y" STD14_FLAG "${STD14_FLAG}")
|
||||
check_cxx_compiler_flag(${STD14_FLAG} HAVE_STD1Y)
|
||||
set(HAVE_STD14 ${HAVE_STD1Y})
|
||||
endif()
|
||||
elseif (MSVC)
|
||||
set(HAVE_STD14 MSVC_VERSION>=1900)
|
||||
endif()
|
||||
|
||||
if (NOT HAVE_STD14)
|
||||
message(FATAL_ERROR "No C++14 support in the compiler. Please upgrade the compiler.")
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD ON)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if (TON_ARCH AND NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${TON_ARCH}")
|
||||
endif()
|
||||
if (THREADS_HAVE_PTHREAD_ARG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
endif()
|
||||
|
||||
if (TON_USE_JEMALLOC)
|
||||
find_package(JeMalloc REQUIRED)
|
||||
endif()
|
||||
|
||||
set(MEMPROF "" CACHE STRING "Use one of \"ON\", \"FAST\" or \"SAFE\" to enable memory profiling. \
|
||||
Works under macOS and Linux when compiled using glibc. \
|
||||
In FAST mode stack is unwinded only using frame pointers, which may fail. \
|
||||
In SAFE mode stack is unwinded using backtrace function from execinfo.h, which may be very slow. \
|
||||
By default both methods are used to achieve maximum speed and accuracy")
|
||||
|
||||
if (CLANG OR GCC)
|
||||
if (MEMPROF)
|
||||
check_cxx_compiler_flag(-no-pie CXX_NO_PIE_FLAG)
|
||||
if (CXX_NO_PIE_FLAG)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
|
||||
elseif (APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_pie")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1")
|
||||
string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
endif()
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /wd4127 /wd4324 /wd4456 /wd4457 /wd4458 /wd4505 /wd4702")
|
||||
elseif (CLANG OR GCC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STD14_FLAG} -fno-omit-frame-pointer")
|
||||
if (APPLE)
|
||||
#use "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/export_list" for exported symbols
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fvisibility=hidden -Wl,-dead_strip,-x,-S")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fvisibility=hidden -Wl,-dead_strip,-x,-S")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,--exclude-libs,ALL")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
if (NOT TON_USE_ASAN AND NOT TON_USE_TSAN AND NOT MEMPROF)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--exclude-libs,ALL")
|
||||
endif()
|
||||
endif()
|
||||
elseif (INTEL)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STD14_FLAG}")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
add_definitions(-DNTDDI_VERSION=0x06020000 -DWINVER=0x0602 -D_WIN32_WINNT=0x0602 -DNOMINMAX -DUNICODE -D_UNICODE)
|
||||
endif()
|
||||
if (CYGWIN)
|
||||
add_definitions(-D_DEFAULT_SOURCE=1 -DFD_SETSIZE=4096)
|
||||
endif()
|
||||
|
||||
if (NOT ANDROID) # _FILE_OFFSET_BITS is broken in ndk r15 and r15b and doesn't work prior to Android 7.0
|
||||
add_definitions(-D_FILE_OFFSET_BITS=64)
|
||||
endif()
|
||||
|
||||
include(AddCXXCompilerFlag)
|
||||
if (MSVC)
|
||||
add_cxx_compiler_flag("/experimental:external /external:anglebrackets /external:W0")
|
||||
endif()
|
||||
if (NOT MSVC)
|
||||
add_cxx_compiler_flag("-Wall")
|
||||
endif()
|
||||
add_cxx_compiler_flag("-Wextra")
|
||||
add_cxx_compiler_flag("-Wimplicit-fallthrough=2")
|
||||
add_cxx_compiler_flag("-Wpointer-arith")
|
||||
add_cxx_compiler_flag("-Wcast-qual")
|
||||
add_cxx_compiler_flag("-Wsign-compare")
|
||||
add_cxx_compiler_flag("-Wduplicated-branches")
|
||||
add_cxx_compiler_flag("-Wduplicated-cond")
|
||||
add_cxx_compiler_flag("-Walloc-zero")
|
||||
add_cxx_compiler_flag("-Wlogical-op")
|
||||
add_cxx_compiler_flag("-Wno-tautological-compare")
|
||||
add_cxx_compiler_flag("-Wpointer-arith")
|
||||
add_cxx_compiler_flag("-Wvla")
|
||||
add_cxx_compiler_flag("-Wnon-virtual-dtor")
|
||||
add_cxx_compiler_flag("-Wno-unused-parameter")
|
||||
add_cxx_compiler_flag("-Wconversion")
|
||||
add_cxx_compiler_flag("-Wno-sign-conversion")
|
||||
add_cxx_compiler_flag("-Qunused-arguments")
|
||||
add_cxx_compiler_flag("-Wno-unused-private-field")
|
||||
add_cxx_compiler_flag("-Wno-redundant-move")
|
||||
#add_cxx_compiler_flag("-Werror")
|
||||
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem /usr/include/c++/v1")
|
||||
if (CLANG)
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
if (TON_USE_ASAN)
|
||||
if (CLANG)
|
||||
add_cxx_compiler_flag("-stdlib=libc++")
|
||||
endif()
|
||||
add_cxx_compiler_flag("-fsanitize=address")
|
||||
add_definitions(-DTD_USE_ASAN=1)
|
||||
endif()
|
||||
if (TON_USE_TSAN)
|
||||
if (CLANG)
|
||||
add_cxx_compiler_flag("-stdlib=libc++")
|
||||
endif()
|
||||
add_cxx_compiler_flag("-fsanitize=thread")
|
||||
endif()
|
||||
if (TON_USE_UBSAN)
|
||||
if (CLANG)
|
||||
add_cxx_compiler_flag("-stdlib=libc++")
|
||||
endif()
|
||||
add_cxx_compiler_flag("-fsanitize=undefined")
|
||||
endif()
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=leak")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -finstrument-functions")
|
||||
|
||||
#Compilation database
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
|
||||
|
||||
#BEGIN internal
|
||||
find_package(LATEX)
|
||||
if (LATEX_FOUND)
|
||||
include(UseLATEX)
|
||||
add_latex_document(doc/ton.tex TARGET_NAME ton_white_paper)
|
||||
add_latex_document(doc/tvm.tex TARGET_NAME ton_vm_description)
|
||||
add_latex_document(doc/tblkch.tex TARGET_NAME ton_blockchain_description)
|
||||
add_latex_document(doc/fiftbase.tex TARGET_NAME fift_basic_description)
|
||||
endif()
|
||||
#END internal
|
||||
|
||||
function(target_link_libraries_system target)
|
||||
set(libs ${ARGN})
|
||||
foreach(lib ${libs})
|
||||
get_target_property(lib_include_dirs ${lib} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(${target} SYSTEM PUBLIC ${lib_include_dirs})
|
||||
target_link_libraries(${target} PUBLIC ${lib})
|
||||
endforeach(lib)
|
||||
endfunction(target_link_libraries_system)
|
||||
|
||||
add_subdirectory(tdutils)
|
||||
add_subdirectory(memprof)
|
||||
add_subdirectory(tdactor)
|
||||
add_subdirectory(tdnet)
|
||||
if (TON_USE_ROCKSDB)
|
||||
option(TDDB_USE_ROCKSDB "Use rockdb" ON)
|
||||
endif()
|
||||
add_subdirectory(tddb)
|
||||
add_subdirectory(tdtl)
|
||||
add_subdirectory(tl)
|
||||
add_subdirectory(terminal)
|
||||
add_subdirectory(keys)
|
||||
add_subdirectory(tl-utils)
|
||||
add_subdirectory(adnl)
|
||||
add_subdirectory(crypto)
|
||||
add_subdirectory(lite-client)
|
||||
|
||||
#BEGIN tonlib
|
||||
add_subdirectory(tonlib)
|
||||
#END tonlib
|
||||
|
||||
#BEGIN internal
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(tdfec)
|
||||
add_subdirectory(keyring)
|
||||
add_subdirectory(fec)
|
||||
add_subdirectory(rldp)
|
||||
add_subdirectory(dht)
|
||||
add_subdirectory(overlay)
|
||||
add_subdirectory(catchain)
|
||||
add_subdirectory(validator-session)
|
||||
add_subdirectory(validator)
|
||||
add_subdirectory(blockchain-explorer)
|
||||
add_subdirectory(validator-engine)
|
||||
add_subdirectory(validator-engine-console)
|
||||
add_subdirectory(dht-server)
|
||||
add_subdirectory(utils)
|
||||
#END internal
|
||||
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
add_custom_target(prepare_cross_compiling DEPENDS tl_generate_common tdmime_auto tlb_generate_block)
|
||||
endif()
|
||||
|
||||
#TESTS
|
||||
add_executable(test-ed25519 test/test-td-main.cpp ${ED25519_TEST_SOURCE})
|
||||
target_link_libraries(test-ed25519 PRIVATE ton_crypto)
|
||||
|
||||
add_executable(test-vm test/test-td-main.cpp ${TONVM_TEST_SOURCE})
|
||||
target_link_libraries(test-vm PRIVATE ton_crypto fift-lib)
|
||||
|
||||
add_executable(test-cells test/test-td-main.cpp ${CELLS_TEST_SOURCE})
|
||||
target_link_libraries(test-cells PRIVATE ton_crypto)
|
||||
|
||||
add_executable(test-fift test/test-td-main.cpp ${FIFT_TEST_SOURCE})
|
||||
target_link_libraries(test-fift PRIVATE fift-lib)
|
||||
|
||||
add_executable(test-tdutils test/test-td-main.cpp ${TDUTILS_TEST_SOURCE})
|
||||
target_link_libraries(test-tdutils PRIVATE tdutils ${CMAKE_THREAD_LIBS_INIT} memprof ${JEMALLOC_LIBRARIES})
|
||||
#target_link_libraries_system(test-tdutils absl::base absl::container absl::hash )
|
||||
#target_link_libraries_system(test-tdutils libcuckoo)
|
||||
#target_include_directories(test-tdutils PRIVATE SYSTEM ${JUNCTION_ALL_INCLUDE_DIRS})
|
||||
#target_link_libraries(test-tdutils PRIVATE ${JUNCTION_ALL_LIBRARIES})
|
||||
|
||||
add_executable(test-tdactor test/test-td-main.cpp ${TDACTOR_TEST_SOURCE})
|
||||
target_link_libraries(test-tdactor PRIVATE tdactor ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
add_executable(test-net test/test-td-main.cpp ${NET_TEST_SOURCE})
|
||||
target_link_libraries(test-net PRIVATE tdnet tdutils ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
#BEGIN tonlib
|
||||
add_executable(test-tonlib ${TONLIB_ONLINE_TEST_SOURCE})
|
||||
target_link_libraries(test-tonlib tdutils tdactor adnllite tl_api ton_crypto ton_block tl_tonlib_api tonlib)
|
||||
|
||||
add_executable(test-tonlib-offline test/test-td-main.cpp ${TONLIB_OFFLINE_TEST_SOURCE})
|
||||
target_link_libraries(test-tonlib-offline tdutils tdactor adnllite tl_api ton_crypto ton_block fift-lib tl_tonlib_api tonlib)
|
||||
#END tonlib
|
||||
|
||||
#BEGIN internal
|
||||
add_executable(test-db test/test-td-main.cpp ${TONDB_TEST_SOURCE})
|
||||
target_link_libraries(test-db PRIVATE ton_db memprof)
|
||||
|
||||
add_executable(test-tddb test/test-td-main.cpp ${TDDB_TEST_SOURCE})
|
||||
target_link_libraries(test-tddb PRIVATE tdutils tddb ${CMAKE_THREAD_LIBS_INIT} memprof)
|
||||
|
||||
add_executable(test-fec test/test-td-main.cpp ${FEC_TEST_SOURCE})
|
||||
target_link_libraries(test-fec PRIVATE tdfec tdutils ${CMAKE_THREAD_LIBS_INIT})
|
||||
if (USE_LIBRAPTORQ)
|
||||
target_link_libraries(test-fec PRIVATE third_party_fec)
|
||||
target_compile_definitions(test-fec PRIVATE "USE_LIBRAPTORQ=1")
|
||||
endif()
|
||||
|
||||
add_executable(test-hello-world test/test-hello-world.cpp )
|
||||
target_link_libraries(test-hello-world tl_api)
|
||||
|
||||
add_executable(test-adnl test/test-adnl.cpp)
|
||||
target_link_libraries(test-adnl adnl adnltest dht tl_api)
|
||||
add_executable(test-dht test/test-dht.cpp)
|
||||
target_link_libraries(test-dht adnl adnltest dht tl_api)
|
||||
add_executable(test-rldp test/test-rldp.cpp)
|
||||
target_link_libraries(test-rldp adnl adnltest dht rldp tl_api)
|
||||
add_executable(test-validator-session-state test/test-validator-session-state.cpp)
|
||||
target_link_libraries(test-validator-session-state adnl dht rldp validatorsession tl_api)
|
||||
|
||||
#add_executable(test-node test/test-node.cpp)
|
||||
#target_link_libraries(test-node overlay tdutils tdactor adnl tl_api dht
|
||||
# catchain validatorsession)
|
||||
|
||||
add_executable(test-catchain test/test-catchain.cpp)
|
||||
target_link_libraries(test-catchain overlay tdutils tdactor adnl adnltest rldp tl_api dht
|
||||
catchain )
|
||||
#add_executable(test-validator-session test/test-validator-session.cpp)
|
||||
#target_link_libraries(test-validator-session overlay tdutils tdactor adnl tl_api dht
|
||||
# catchain validatorsession)
|
||||
#add_executable(test-ton-dummy-0 test/test-ton-dummy-0.cpp)
|
||||
#target_link_libraries(test-ton-dummy-0 overlay tdutils tdactor adnl tl_api dht
|
||||
# catchain validatorsession ton-node validator dummy_validator validator )
|
||||
#add_executable(test-dummy-0-lite-client test/test-dummy-0-lite-client.cpp)
|
||||
#target_link_libraries(test-dummy-0-lite-client overlay tdutils tdactor adnl tl_api dht
|
||||
# catchain validatorsession ton-node validator dummy_validator validator
|
||||
# terminal )
|
||||
#add_executable(test-ton-dummy-0-collator test/test-ton-collator.cpp)
|
||||
#target_link_libraries(test-ton-dummy-0-collator overlay tdutils tdactor adnl tl_api
|
||||
# dht catchain validatorsession ton-node validator_disk dummy_validator validator_disk )
|
||||
add_executable(test-ton-collator test/test-ton-collator.cpp)
|
||||
target_link_libraries(test-ton-collator overlay tdutils tdactor adnl tl_api dht
|
||||
catchain validatorsession validator-disk ton_validator validator-disk )
|
||||
#add_executable(test-validator test/test-validator.cpp)
|
||||
#target_link_libraries(test-validator overlay tdutils tdactor adnl tl_api dht
|
||||
# rldp catchain validatorsession ton-node validator ton_validator validator memprof ${JEMALLOC_LIBRARIES})
|
||||
#add_executable(test-ext-server test/test-ext-server.cpp)
|
||||
#target_link_libraries(test-ext-server tdutils tdactor adnl tl_api dht )
|
||||
#add_executable(test-ext-client test/test-ext-client.cpp)
|
||||
#target_link_libraries(test-ext-client tdutils tdactor adnl tl_api tl-lite-utils)
|
||||
|
||||
get_directory_property(HAS_PARENT PARENT_DIRECTORY)
|
||||
if (HAS_PARENT)
|
||||
set(ALL_TEST_SOURCE
|
||||
${TDUTILS_TEST_SOURCE}
|
||||
${TDACTOR_TEST_SOURCE}
|
||||
${NET_TEST_SOURCE}
|
||||
${TDDB_TEST_SOURCE}
|
||||
${FEC_TEST_SOURCE}
|
||||
${ED25519_TEST_SOURCE}
|
||||
${TONDB_TEST_SOURCE}
|
||||
${CELLS_TEST_SOURCE} # ${TONVM_TEST_SOURCE} ${FIFT_TEST_SOURCE} ${TONLIB_ONLINE_TEST_SOURCE}
|
||||
PARENT_SCOPE)
|
||||
endif()
|
||||
add_library(all_tests INTERFACE)
|
||||
target_link_libraries(all_tests INTERFACE tdutils tdactor tdnet tdfec ton_db ton_crypto fift-lib)
|
||||
#END internal
|
||||
|
||||
enable_testing()
|
||||
set(TEST_OPTIONS "--regression ${CMAKE_CURRENT_SOURCE_DIR}/test/regression-tests.ans --filter -Bench")
|
||||
separate_arguments(TEST_OPTIONS)
|
||||
add_test(test-ed25519 test-ed25519)
|
||||
add_test(test-vm test-vm ${TEST_OPTIONS})
|
||||
add_test(test-fift test-fift ${TEST_OPTIONS})
|
||||
add_test(test-cells test-cells ${TEST_OPTIONS})
|
||||
add_test(test-net test-net)
|
||||
add_test(test-actors test-tdactor)
|
||||
|
||||
#BEGIN tonlib
|
||||
add_test(test-tdutils test-tdutils)
|
||||
add_test(test-tonlib-offline test-tonlib-offline)
|
||||
#END tonlib
|
||||
|
||||
#BEGIN internal
|
||||
add_test(test-fec test-fec)
|
||||
add_test(test-tddb test-tddb ${TEST_OPTIONS})
|
||||
add_test(test-db test-db ${TEST_OPTIONS})
|
||||
#END internal
|
||||
|
27
GPLv2
Normal file
27
GPLv2
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
18
LGPLv2
Normal file
18
LGPLv2
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
481
LICENSE.LGPL
Normal file
481
LICENSE.LGPL
Normal file
|
@ -0,0 +1,481 @@
|
|||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
98
adnl/CMakeLists.txt
Normal file
98
adnl/CMakeLists.txt
Normal file
|
@ -0,0 +1,98 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
#BEGIN internal
|
||||
set(ADNL_HEADERS
|
||||
adnl-address-list.h
|
||||
adnl-address-list.hpp
|
||||
adnl-db.h
|
||||
adnl-db.hpp
|
||||
adnl-channel.h
|
||||
adnl-channel.hpp
|
||||
adnl-ext-client.h
|
||||
adnl-ext-client.hpp
|
||||
adnl-ext-connection.hpp
|
||||
adnl-ext-server.h
|
||||
adnl-ext-server.hpp
|
||||
adnl-local-id.h
|
||||
adnl-message.h
|
||||
adnl-network-manager.h
|
||||
adnl-network-manager.hpp
|
||||
adnl-node.h
|
||||
adnl-packet.h
|
||||
adnl-peer-table.h
|
||||
adnl-peer-table.hpp
|
||||
adnl-peer.h
|
||||
adnl-peer.hpp
|
||||
adnl-query.h
|
||||
adnl-static-nodes.h
|
||||
adnl-static-nodes.hpp
|
||||
adnl-proxy-types.h
|
||||
adnl-proxy-types.hpp
|
||||
adnl.h
|
||||
utils.hpp
|
||||
)
|
||||
set(ADNL_SOURCE
|
||||
adnl-address-list.cpp
|
||||
adnl-db.cpp
|
||||
adnl-ext-client.cpp
|
||||
adnl-ext-server.cpp
|
||||
adnl-ext-connection.cpp
|
||||
adnl-local-id.cpp
|
||||
adnl-message.cpp
|
||||
adnl-network-manager.cpp
|
||||
adnl-node.cpp
|
||||
adnl-packet.cpp
|
||||
adnl-peer-table.cpp
|
||||
adnl-peer.cpp
|
||||
adnl-query.cpp
|
||||
adnl-channel.cpp
|
||||
adnl-static-nodes.cpp
|
||||
adnl-proxy-types.cpp
|
||||
utils.cpp
|
||||
${ADNL_HEADERS}
|
||||
)
|
||||
|
||||
set(ADNL_TEST_SOURCE
|
||||
adnl-test-loopback-implementation.h
|
||||
adnl-test-loopback-implementation.cpp
|
||||
)
|
||||
|
||||
set(ADNL_PROXY_SOURCE
|
||||
adnl-proxy.cpp
|
||||
adnl-proxy-types.h
|
||||
adnl-proxy-types.hpp
|
||||
adnl-proxy-types.cpp
|
||||
)
|
||||
|
||||
#FIXME
|
||||
set(ADNL_LITE_HEADERS ${ADNL_HEADERS})
|
||||
#END internal
|
||||
|
||||
set(ADNL_LITE_SOURCE
|
||||
adnl-ext-client.cpp
|
||||
adnl-ext-connection.cpp
|
||||
adnl-query.cpp
|
||||
|
||||
${ADNL_LITE_HEADERS}
|
||||
)
|
||||
|
||||
#BEGIN internal
|
||||
add_library(adnl STATIC ${ADNL_SOURCE})
|
||||
|
||||
target_include_directories(adnl PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(adnl PUBLIC tdactor ton_crypto tl_api tdnet tddb keys keyring )
|
||||
|
||||
add_executable(adnl-proxy ${ADNL_PROXY_SOURCE})
|
||||
target_include_directories(adnl-proxy PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(adnl-proxy PUBLIC tdactor ton_crypto tl_api tdnet common
|
||||
tl-utils)
|
||||
|
||||
add_library(adnltest STATIC ${ADNL_TEST_SOURCE})
|
||||
target_include_directories(adnltest PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(adnltest PUBLIC adnl )
|
||||
#END internal
|
||||
|
||||
add_library(adnllite STATIC ${ADNL_LITE_SOURCE})
|
||||
|
||||
target_include_directories(adnllite PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(adnllite PUBLIC tdactor ton_crypto tl_lite_api tdnet keys )
|
160
adnl/adnl-address-list.cpp
Normal file
160
adnl/adnl-address-list.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-address-list.hpp"
|
||||
#include "adnl-peer-table.h"
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "td/net/UdpServer.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlNetworkConnectionUdp : public AdnlNetworkConnection {
|
||||
public:
|
||||
void send(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::uint32 priority, td::BufferSlice message) override;
|
||||
bool is_alive() const override {
|
||||
return true;
|
||||
}
|
||||
bool is_active() const override {
|
||||
return true;
|
||||
}
|
||||
void start_up() override {
|
||||
callback_->on_change_state(true);
|
||||
}
|
||||
|
||||
AdnlNetworkConnectionUdp(td::actor::ActorId<AdnlNetworkManager> network_manager, td::uint32 ip, td::uint16 port,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback);
|
||||
AdnlNetworkConnectionUdp(td::actor::ActorId<AdnlNetworkManager> network_manager, td::Bits128 ip, td::uint16 port,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback);
|
||||
|
||||
private:
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager_;
|
||||
td::IPAddress addr_;
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback_;
|
||||
};
|
||||
|
||||
void AdnlNetworkConnectionUdp::send(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::uint32 priority,
|
||||
td::BufferSlice message) {
|
||||
LOG_CHECK(message.size() <= AdnlNetworkManager::get_mtu()) << "dst=" << addr_ << " size=" << message.size();
|
||||
td::actor::send_closure(network_manager_, &AdnlNetworkManager::send_udp_packet, src, dst, addr_, priority,
|
||||
std::move(message));
|
||||
}
|
||||
|
||||
AdnlNetworkConnectionUdp::AdnlNetworkConnectionUdp(td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
td::uint32 ip, td::uint16 port,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback)
|
||||
: network_manager_(network_manager), callback_(std::move(callback)) {
|
||||
addr_.init_host_port(td::IPAddress::ipv4_to_str(ip), port).ensure();
|
||||
}
|
||||
|
||||
AdnlNetworkConnectionUdp::AdnlNetworkConnectionUdp(td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
td::Bits128 ip, td::uint16 port,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback)
|
||||
: network_manager_(network_manager), callback_(std::move(callback)) {
|
||||
addr_.init_host_port(td::IPAddress::ipv6_to_str(ip.as_slice()), port).ensure();
|
||||
}
|
||||
|
||||
AdnlAddressImpl::Hash AdnlAddressImpl::get_hash() const {
|
||||
return get_tl_object_sha_bits256(tl());
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlNetworkConnection> AdnlAddressUdp::create_connection(
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const {
|
||||
return td::actor::create_actor<AdnlNetworkConnectionUdp>("udpconn", network_manager, ip_, port_, std::move(callback));
|
||||
}
|
||||
|
||||
AdnlAddressUdp::AdnlAddressUdp(const ton_api::adnl_address_udp &obj) {
|
||||
ip_ = obj.ip_;
|
||||
port_ = static_cast<td::uint16>(obj.port_);
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlNetworkConnection> AdnlAddressUdp6::create_connection(
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const {
|
||||
return td::actor::create_actor<AdnlNetworkConnectionUdp>("udpconn", network_manager, ip_, port_, std::move(callback));
|
||||
}
|
||||
|
||||
AdnlAddressUdp6::AdnlAddressUdp6(const ton_api::adnl_address_udp6 &obj) {
|
||||
ip_ = obj.ip_;
|
||||
port_ = static_cast<td::uint16>(obj.port_);
|
||||
}
|
||||
|
||||
td::Ref<AdnlAddressImpl> AdnlAddressImpl::create(const tl_object_ptr<ton_api::adnl_Address> &addr) {
|
||||
td::Ref<AdnlAddressImpl> res = td::Ref<AdnlAddressImpl>{};
|
||||
ton_api::downcast_call(*const_cast<ton_api::adnl_Address *>(addr.get()),
|
||||
td::overloaded(
|
||||
[&](const ton_api::adnl_address_udp &obj) {
|
||||
res = td::Ref<AdnlAddressUdp>{true, obj};
|
||||
},
|
||||
[&](const ton_api::adnl_address_udp6 &obj) {
|
||||
res = td::Ref<AdnlAddressUdp6>{true, obj};
|
||||
}));
|
||||
return res;
|
||||
}
|
||||
|
||||
bool AdnlAddressList::public_only() const {
|
||||
for (auto &addr : addrs_) {
|
||||
if (!addr->is_public()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AdnlAddressList::AdnlAddressList(const tl_object_ptr<ton_api::adnl_addressList> &addrs) {
|
||||
version_ = static_cast<td::uint32>(addrs->version_);
|
||||
std::vector<td::Ref<AdnlAddressImpl>> vec;
|
||||
for (auto &addr : addrs->addrs_) {
|
||||
vec.push_back(AdnlAddressImpl::create(addr));
|
||||
}
|
||||
addrs_ = std::move(vec);
|
||||
reinit_date_ = addrs->reinit_date_;
|
||||
priority_ = addrs->priority_;
|
||||
expire_at_ = addrs->expire_at_;
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::adnl_addressList> AdnlAddressList::tl() const {
|
||||
std::vector<tl_object_ptr<ton_api::adnl_Address>> addrs;
|
||||
for (auto &v : addrs_) {
|
||||
addrs.emplace_back(v->tl());
|
||||
}
|
||||
return create_tl_object<ton_api::adnl_addressList>(std::move(addrs), version_, reinit_date_, priority_, expire_at_);
|
||||
}
|
||||
|
||||
td::uint32 AdnlAddressList::serialized_size() const {
|
||||
td::uint32 res = 24;
|
||||
for (auto &addr : addrs_) {
|
||||
res += addr->serialized_size();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Result<AdnlAddressList> AdnlAddressList::create(const tl_object_ptr<ton_api::adnl_addressList> &addr_list) {
|
||||
auto A = AdnlAddressList{addr_list};
|
||||
if (A.serialized_size() > max_serialized_size()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, PSTRING() << "too big addr list: size=" << A.serialized_size());
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
105
adnl/adnl-address-list.h
Normal file
105
adnl/adnl-address-list.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-network-manager.h"
|
||||
#include "crypto/common/refcnt.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlAddressImpl : public td::CntObject {
|
||||
public:
|
||||
using Hash = td::Bits256;
|
||||
virtual ~AdnlAddressImpl() = default;
|
||||
|
||||
virtual Hash get_hash() const;
|
||||
virtual bool is_public() const = 0;
|
||||
virtual td::uint32 serialized_size() const = 0;
|
||||
virtual tl_object_ptr<ton_api::adnl_Address> tl() const = 0;
|
||||
virtual td::actor::ActorOwn<AdnlNetworkConnection> create_connection(
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const = 0;
|
||||
|
||||
static td::Ref<AdnlAddressImpl> create(const tl_object_ptr<ton_api::adnl_Address> &addr);
|
||||
};
|
||||
|
||||
using AdnlAddress = td::Ref<AdnlAddressImpl>;
|
||||
|
||||
class AdnlAddressList {
|
||||
private:
|
||||
AdnlAddressList(const tl_object_ptr<ton_api::adnl_addressList> &addrs);
|
||||
|
||||
td::int32 version_;
|
||||
td::int32 reinit_date_;
|
||||
td::int32 priority_;
|
||||
td::int32 expire_at_;
|
||||
std::vector<AdnlAddress> addrs_;
|
||||
|
||||
public:
|
||||
static constexpr td::uint32 max_serialized_size() {
|
||||
return 128;
|
||||
}
|
||||
|
||||
const auto &addrs() const {
|
||||
return addrs_;
|
||||
}
|
||||
auto version() const {
|
||||
return version_;
|
||||
}
|
||||
auto reinit_date() const {
|
||||
return reinit_date_;
|
||||
}
|
||||
auto priority() const {
|
||||
return priority_;
|
||||
}
|
||||
auto expire_at() const {
|
||||
return expire_at_;
|
||||
}
|
||||
void set_version(td::uint32 version) {
|
||||
version_ = version;
|
||||
}
|
||||
void set_reinit_date(td::int32 date) {
|
||||
reinit_date_ = date;
|
||||
}
|
||||
void set_expire_at(td::int32 date) {
|
||||
expire_at_ = date;
|
||||
}
|
||||
bool empty() const {
|
||||
return version_ == -1;
|
||||
}
|
||||
void add_addr(AdnlAddress addr) {
|
||||
addrs_.push_back(addr);
|
||||
}
|
||||
bool public_only() const;
|
||||
td::uint32 size() const {
|
||||
return static_cast<td::uint32>(addrs_.size());
|
||||
}
|
||||
td::uint32 serialized_size() const;
|
||||
tl_object_ptr<ton_api::adnl_addressList> tl() const;
|
||||
AdnlAddressList() : version_{-1}, reinit_date_{0}, priority_{0}, expire_at_{0} {
|
||||
}
|
||||
|
||||
static td::Result<AdnlAddressList> create(const tl_object_ptr<ton_api::adnl_addressList> &addr_list);
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
90
adnl/adnl-address-list.hpp
Normal file
90
adnl/adnl-address-list.hpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-node-id.hpp"
|
||||
#include "adnl-address-list.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlAddressUdp : public AdnlAddressImpl {
|
||||
private:
|
||||
td::uint32 ip_;
|
||||
td::uint16 port_;
|
||||
|
||||
public:
|
||||
explicit AdnlAddressUdp(const ton_api::adnl_address_udp &obj);
|
||||
|
||||
AdnlAddressUdp(td::uint32 ip, td::uint16 port) : ip_(ip), port_(port) {
|
||||
}
|
||||
|
||||
AdnlAddressUdp *make_copy() const override {
|
||||
return new AdnlAddressUdp{ip_, port_};
|
||||
}
|
||||
|
||||
bool is_public() const override {
|
||||
return true;
|
||||
}
|
||||
td::uint32 serialized_size() const override {
|
||||
return 12;
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::adnl_Address> tl() const override {
|
||||
return create_tl_object<ton_api::adnl_address_udp>(ip_, port_);
|
||||
}
|
||||
td::actor::ActorOwn<AdnlNetworkConnection> create_connection(
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const override;
|
||||
};
|
||||
|
||||
class AdnlAddressUdp6 : public AdnlAddressImpl {
|
||||
private:
|
||||
td::Bits128 ip_;
|
||||
td::uint16 port_;
|
||||
|
||||
public:
|
||||
explicit AdnlAddressUdp6(const ton_api::adnl_address_udp6 &obj);
|
||||
|
||||
AdnlAddressUdp6(td::Bits128 ip, td::uint16 port) : ip_(ip), port_(port) {
|
||||
}
|
||||
|
||||
AdnlAddressUdp6 *make_copy() const override {
|
||||
return new AdnlAddressUdp6{ip_, port_};
|
||||
}
|
||||
|
||||
bool is_public() const override {
|
||||
return true;
|
||||
}
|
||||
td::uint32 serialized_size() const override {
|
||||
return 12;
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::adnl_Address> tl() const override {
|
||||
return create_tl_object<ton_api::adnl_address_udp6>(ip_, port_);
|
||||
}
|
||||
td::actor::ActorOwn<AdnlNetworkConnection> create_connection(
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
std::unique_ptr<AdnlNetworkConnection::Callback> callback) const override;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
129
adnl/adnl-channel.cpp
Normal file
129
adnl/adnl-channel.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-channel.hpp"
|
||||
#include "adnl-peer.h"
|
||||
#include "adnl-peer-table.h"
|
||||
|
||||
#include "td/utils/crypto.h"
|
||||
#include "crypto/Ed25519.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
td::Result<td::actor::ActorOwn<AdnlChannel>> AdnlChannel::create(privkeys::Ed25519 pk_data, pubkeys::Ed25519 pub_data,
|
||||
AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
|
||||
AdnlChannelIdShort &out_id, AdnlChannelIdShort &in_id,
|
||||
td::actor::ActorId<AdnlPeerPair> peer_pair) {
|
||||
td::Ed25519::PublicKey pub_k = pub_data.export_key();
|
||||
td::Ed25519::PrivateKey priv_k = pk_data.export_key();
|
||||
|
||||
TRY_RESULT_PREFIX(shared_secret, td::Ed25519::compute_shared_secret(pub_k, priv_k),
|
||||
"failed to compute channel shared secret: ");
|
||||
CHECK(shared_secret.length() == 32);
|
||||
|
||||
td::SecureString rev_secret{32};
|
||||
for (td::uint32 i = 0; i < 32; i++) {
|
||||
rev_secret.as_mutable_slice()[i] = shared_secret[31 - i];
|
||||
}
|
||||
|
||||
auto R = [&]() -> std::pair<PrivateKey, PublicKey> {
|
||||
if (local_id < peer_id) {
|
||||
return {privkeys::AES{std::move(shared_secret)}, pubkeys::AES{std::move(rev_secret)}};
|
||||
} else if (peer_id < local_id) {
|
||||
return {privkeys::AES{std::move(rev_secret)}, pubkeys::AES{std::move(shared_secret)}};
|
||||
} else {
|
||||
auto c = shared_secret.copy();
|
||||
return {privkeys::AES{std::move(c)}, pubkeys::AES{std::move(shared_secret)}};
|
||||
}
|
||||
}();
|
||||
|
||||
in_id = AdnlChannelIdShort{R.first.compute_short_id()};
|
||||
out_id = AdnlChannelIdShort{R.second.compute_short_id()};
|
||||
|
||||
TRY_RESULT_PREFIX(encryptor, R.second.create_encryptor(), "failed to init channel encryptor: ");
|
||||
TRY_RESULT_PREFIX(decryptor, R.first.create_decryptor(), "failed to init channel decryptor: ");
|
||||
|
||||
return td::actor::create_actor<AdnlChannelImpl>("channel", local_id, peer_id, peer_pair, in_id, out_id,
|
||||
std::move(encryptor), std::move(decryptor));
|
||||
}
|
||||
|
||||
AdnlChannelImpl::AdnlChannelImpl(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
|
||||
td::actor::ActorId<AdnlPeerPair> peer_pair, AdnlChannelIdShort in_id,
|
||||
AdnlChannelIdShort out_id, std::unique_ptr<Encryptor> encryptor,
|
||||
std::unique_ptr<Decryptor> decryptor) {
|
||||
local_id_ = local_id;
|
||||
peer_id_ = peer_id;
|
||||
|
||||
encryptor_ = std::move(encryptor);
|
||||
decryptor_ = std::move(decryptor);
|
||||
|
||||
channel_in_id_ = in_id;
|
||||
channel_out_id_ = out_id;
|
||||
|
||||
peer_pair_ = peer_pair;
|
||||
|
||||
VLOG(ADNL_INFO) << this << ": created";
|
||||
}
|
||||
|
||||
void AdnlChannelImpl::decrypt(td::BufferSlice raw_data, td::Promise<AdnlPacket> promise) {
|
||||
TRY_RESULT_PROMISE_PREFIX(promise, data, decryptor_->decrypt(raw_data.as_slice()),
|
||||
"failed to decrypt channel message: ");
|
||||
TRY_RESULT_PROMISE_PREFIX(promise, tl_packet, fetch_tl_object<ton_api::adnl_packetContents>(std::move(data), true),
|
||||
"decrypted channel packet contains invalid TL scheme: ");
|
||||
TRY_RESULT_PROMISE_PREFIX(promise, packet, AdnlPacket::create(std::move(tl_packet)), "received bad packet: ");
|
||||
if (packet.inited_from_short() && packet.from_short() != peer_id_) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "bad channel packet destination"));
|
||||
return;
|
||||
}
|
||||
promise.set_value(std::move(packet));
|
||||
}
|
||||
|
||||
void AdnlChannelImpl::send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn,
|
||||
td::BufferSlice data) {
|
||||
auto E = encryptor_->encrypt(data.as_slice());
|
||||
if (E.is_error()) {
|
||||
VLOG(ADNL_ERROR) << this << ": dropping OUT message: can not encrypt: " << E.move_as_error();
|
||||
return;
|
||||
}
|
||||
auto enc = E.move_as_ok();
|
||||
auto B = td::BufferSlice(enc.size() + 32);
|
||||
td::MutableSlice S = B.as_slice();
|
||||
S.copy_from(channel_out_id_.as_slice());
|
||||
S.remove_prefix(32);
|
||||
S.copy_from(enc.as_slice());
|
||||
td::actor::send_closure(conn, &AdnlNetworkConnection::send, local_id_, peer_id_, priority, std::move(B));
|
||||
}
|
||||
|
||||
void AdnlChannelImpl::receive(td::BufferSlice data) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[peer = peer_pair_, channel_id = channel_in_id_, id = print_id()](td::Result<AdnlPacket> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(ADNL_WARNING) << id << ": dropping IN message: can not decrypt: " << R.move_as_error();
|
||||
} else {
|
||||
td::actor::send_closure(peer, &AdnlPeerPair::receive_packet_from_channel, channel_id, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
decrypt(std::move(data), std::move(P));
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
46
adnl/adnl-channel.h
Normal file
46
adnl/adnl-channel.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-local-id.h"
|
||||
#include "adnl-peer.h"
|
||||
#include "adnl-peer-table.h"
|
||||
#include "adnl-network-manager.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlPeerPair;
|
||||
|
||||
class AdnlChannel : public td::actor::Actor {
|
||||
public:
|
||||
static td::Result<td::actor::ActorOwn<AdnlChannel>> create(privkeys::Ed25519 pk, pubkeys::Ed25519 pub,
|
||||
AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
|
||||
AdnlChannelIdShort &out_id, AdnlChannelIdShort &in_id,
|
||||
td::actor::ActorId<AdnlPeerPair> peer_pair);
|
||||
virtual void receive(td::BufferSlice data) = 0;
|
||||
virtual void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn,
|
||||
td::BufferSlice data) = 0;
|
||||
virtual ~AdnlChannel() = default;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
82
adnl/adnl-channel.hpp
Normal file
82
adnl/adnl-channel.hpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-channel.h"
|
||||
#include "keys/encryptor.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlPeerPair;
|
||||
|
||||
class AdnlChannelImpl : public AdnlChannel {
|
||||
public:
|
||||
AdnlChannelImpl(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, td::actor::ActorId<AdnlPeerPair> peer_pair,
|
||||
AdnlChannelIdShort in_id, AdnlChannelIdShort out_id, std::unique_ptr<Encryptor> encryptor,
|
||||
std::unique_ptr<Decryptor> decryptor);
|
||||
void decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise);
|
||||
void receive(td::BufferSlice data) override;
|
||||
void send_message(td::uint32 priority, td::actor::ActorId<AdnlNetworkConnection> conn, td::BufferSlice data) override;
|
||||
|
||||
struct AdnlChannelPrintId {
|
||||
AdnlChannelIdShort channel_out_id_;
|
||||
AdnlChannelIdShort channel_in_id_;
|
||||
AdnlNodeIdShort local_id_;
|
||||
AdnlNodeIdShort peer_id_;
|
||||
};
|
||||
|
||||
AdnlChannelPrintId print_id() const {
|
||||
return AdnlChannelPrintId{channel_out_id_, channel_in_id_, local_id_, peer_id_};
|
||||
}
|
||||
|
||||
private:
|
||||
AdnlChannelIdShort channel_out_id_;
|
||||
AdnlChannelIdShort channel_in_id_;
|
||||
AdnlNodeIdShort local_id_;
|
||||
AdnlNodeIdShort peer_id_;
|
||||
std::unique_ptr<Encryptor> encryptor_;
|
||||
std::unique_ptr<Decryptor> decryptor_;
|
||||
td::actor::ActorId<AdnlPeerPair> peer_pair_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlChannelImpl::AdnlChannelPrintId &id) {
|
||||
sb << "[channel " << id.peer_id_ << "-" << id.local_id_ << " " << id.channel_out_id_ << "-" << id.channel_in_id_
|
||||
<< "]";
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlChannelImpl &channel) {
|
||||
sb << channel.print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlChannelImpl *channel) {
|
||||
sb << channel->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
82
adnl/adnl-db.cpp
Normal file
82
adnl/adnl-db.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-db.hpp"
|
||||
#include "td/db/RocksDb.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
void AdnlDbImpl::update(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem item,
|
||||
td::Promise<td::Unit> promise) {
|
||||
td::BufferSlice b{64};
|
||||
auto S = b.as_slice();
|
||||
S.copy_from(local_id.as_slice());
|
||||
S.remove_prefix(32);
|
||||
S.copy_from(peer_id.as_slice());
|
||||
|
||||
auto obj = create_tl_object<ton_api::adnl_db_node_value>(static_cast<td::int32>(td::Clocks::system()), item.id.tl(),
|
||||
item.addr_list.tl(), item.priority_addr_list.tl());
|
||||
|
||||
kv_->begin_transaction().ensure();
|
||||
kv_->set(b.as_slice(), serialize_tl_object(obj, true).as_slice()).ensure();
|
||||
kv_->commit_transaction().ensure();
|
||||
}
|
||||
|
||||
void AdnlDbImpl::get(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, td::Promise<AdnlDbItem> promise) {
|
||||
td::BufferSlice b{64};
|
||||
auto S = b.as_slice();
|
||||
S.copy_from(local_id.as_slice());
|
||||
S.remove_prefix(32);
|
||||
S.copy_from(peer_id.as_slice());
|
||||
|
||||
std::string value;
|
||||
auto R = kv_->get(b.as_slice(), value);
|
||||
R.ensure();
|
||||
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not in db"));
|
||||
return;
|
||||
}
|
||||
auto F = fetch_tl_object<ton_api::adnl_db_node_value>(td::BufferSlice{value}, true);
|
||||
F.ensure();
|
||||
auto f = F.move_as_ok();
|
||||
AdnlDbItem n;
|
||||
auto id = AdnlNodeIdFull::create(f->id_);
|
||||
id.ensure();
|
||||
n.id = id.move_as_ok();
|
||||
auto addr_list = AdnlAddressList::create(std::move(f->addr_list_));
|
||||
addr_list.ensure();
|
||||
n.addr_list = addr_list.move_as_ok();
|
||||
auto priority_addr_list = AdnlAddressList::create(std::move(f->priority_addr_list_));
|
||||
priority_addr_list.ensure();
|
||||
n.priority_addr_list = priority_addr_list.move_as_ok();
|
||||
promise.set_value(std::move(n));
|
||||
}
|
||||
|
||||
void AdnlDbImpl::start_up() {
|
||||
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(path_).move_as_ok());
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlDb> AdnlDb::create(std::string path) {
|
||||
return td::actor::create_actor<AdnlDbImpl>("adnldb", path);
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
47
adnl/adnl-db.h
Normal file
47
adnl/adnl-db.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include "adnl.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
struct AdnlDbItem {
|
||||
AdnlNodeIdFull id;
|
||||
AdnlAddressList addr_list;
|
||||
AdnlAddressList priority_addr_list;
|
||||
};
|
||||
|
||||
class AdnlDb : public td::actor::Actor {
|
||||
public:
|
||||
virtual ~AdnlDb() = default;
|
||||
virtual void update(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem item,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, td::Promise<AdnlDbItem> promise) = 0;
|
||||
|
||||
static td::actor::ActorOwn<AdnlDb> create(std::string path);
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
47
adnl/adnl-db.hpp
Normal file
47
adnl/adnl-db.hpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-db.h"
|
||||
#include "td/db/KeyValue.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlDbImpl : public AdnlDb {
|
||||
public:
|
||||
void update(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem item,
|
||||
td::Promise<td::Unit> promise) override;
|
||||
void get(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, td::Promise<AdnlDbItem> promise) override;
|
||||
|
||||
void start_up() override;
|
||||
|
||||
AdnlDbImpl(std::string path) : path_(path) {
|
||||
}
|
||||
|
||||
private:
|
||||
std::string path_;
|
||||
|
||||
std::shared_ptr<td::KeyValue> kv_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
181
adnl/adnl-ext-client.cpp
Normal file
181
adnl/adnl-ext-client.cpp
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-ext-client.hpp"
|
||||
#include "adnl-ext-client.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
void AdnlExtClientImpl::alarm() {
|
||||
if (is_closing_) {
|
||||
return;
|
||||
}
|
||||
if (conn_.empty() || !conn_.is_alive()) {
|
||||
next_create_at_ = td::Timestamp::in(10.0);
|
||||
alarm_timestamp() = next_create_at_;
|
||||
|
||||
auto fd = td::SocketFd::open(dst_addr_);
|
||||
if (fd.is_error()) {
|
||||
LOG(INFO) << "failed to connect to " << dst_addr_ << ": " << fd.move_as_error();
|
||||
return;
|
||||
}
|
||||
|
||||
class Cb : public AdnlExtConnection::Callback {
|
||||
private:
|
||||
td::actor::ActorId<AdnlExtClientImpl> id_;
|
||||
|
||||
public:
|
||||
void on_ready(td::actor::ActorId<AdnlExtConnection> conn) {
|
||||
td::actor::send_closure(id_, &AdnlExtClientImpl::conn_ready, conn);
|
||||
}
|
||||
void on_close(td::actor::ActorId<AdnlExtConnection> conn) {
|
||||
td::actor::send_closure(id_, &AdnlExtClientImpl::conn_stopped, conn);
|
||||
}
|
||||
Cb(td::actor::ActorId<AdnlExtClientImpl> id) : id_(id) {
|
||||
}
|
||||
};
|
||||
|
||||
conn_ = td::actor::create_actor<AdnlOutboundConnection>(td::actor::ActorOptions().with_name("outconn").with_poll(),
|
||||
fd.move_as_ok(), std::make_unique<Cb>(actor_id(this)), dst_,
|
||||
local_id_, actor_id(this));
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlExtClientImpl::hangup() {
|
||||
conn_ = {};
|
||||
is_closing_ = true;
|
||||
ref_cnt_--;
|
||||
try_stop();
|
||||
}
|
||||
|
||||
void AdnlExtClientImpl::try_stop() {
|
||||
if (is_closing_ && ref_cnt_ == 0 && out_queries_.empty()) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
td::Status AdnlOutboundConnection::process_custom_packet(td::BufferSlice &data, bool &processed) {
|
||||
if (data.size() == 12) {
|
||||
auto F = fetch_tl_object<ton_api::tcp_pong>(data.clone(), true);
|
||||
if (F.is_ok()) {
|
||||
processed = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
}
|
||||
if (!local_id_.empty() && nonce_.size() != 0) {
|
||||
auto F = fetch_tl_object<ton_api::tcp_authentificationNonce>(data.clone(), true);
|
||||
if (F.is_ok()) {
|
||||
auto f = F.move_as_ok();
|
||||
if (f->nonce_.size() == 0 || f->nonce_.size() > 512) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad nonce size");
|
||||
}
|
||||
td::SecureString ss{nonce_.size() + f->nonce_.size()};
|
||||
ss.as_mutable_slice().copy_from(nonce_.as_slice());
|
||||
ss.as_mutable_slice().remove_prefix(nonce_.size()).copy_from(f->nonce_.as_slice());
|
||||
|
||||
TRY_RESULT(dec, local_id_.create_decryptor());
|
||||
TRY_RESULT(B, dec->sign(ss.as_slice()));
|
||||
|
||||
auto obj =
|
||||
create_tl_object<ton_api::tcp_authentificationComplete>(local_id_.compute_public_key().tl(), std::move(B));
|
||||
send(serialize_tl_object(obj, true));
|
||||
|
||||
nonce_.clear();
|
||||
|
||||
processed = true;
|
||||
authorization_complete_ = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void AdnlOutboundConnection::start_up() {
|
||||
AdnlExtConnection::start_up();
|
||||
auto X = dst_.pubkey().create_encryptor();
|
||||
if (X.is_error()) {
|
||||
LOG(ERROR) << "failed to init encryptor: " << X.move_as_error();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
auto enc = X.move_as_ok();
|
||||
|
||||
td::BufferSlice d{256};
|
||||
auto id = dst_.compute_short_id();
|
||||
auto S = d.as_slice();
|
||||
S.copy_from(id.as_slice());
|
||||
S.remove_prefix(32);
|
||||
S.truncate(256 - 64 - 32);
|
||||
td::Random::secure_bytes(S);
|
||||
init_crypto(S);
|
||||
|
||||
auto R = enc->encrypt(S);
|
||||
if (R.is_error()) {
|
||||
LOG(ERROR) << "failed to encrypt: " << R.move_as_error();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
auto data = R.move_as_ok();
|
||||
LOG_CHECK(data.size() == 256 - 32) << "size=" << data.size();
|
||||
S = d.as_slice();
|
||||
S.remove_prefix(32);
|
||||
CHECK(S.size() == data.size());
|
||||
S.copy_from(data.as_slice());
|
||||
|
||||
send_uninit(std::move(d));
|
||||
|
||||
if (!local_id_.empty()) {
|
||||
nonce_ = td::SecureString{32};
|
||||
td::Random::secure_bytes(nonce_.as_mutable_slice());
|
||||
auto obj = create_tl_object<ton_api::tcp_authentificate>(td::BufferSlice{nonce_.as_slice()});
|
||||
send(serialize_tl_object(obj, true));
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlExtClientImpl::check_ready(td::Promise<td::Unit> promise) {
|
||||
if (conn_.empty() || !conn_.is_alive()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(td::actor::ActorId<AdnlExtConnection>{conn_.get()}, &AdnlExtConnection::check_ready_async,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlExtClient> AdnlExtClient::create(AdnlNodeIdFull dst, td::IPAddress dst_addr,
|
||||
std::unique_ptr<AdnlExtClient::Callback> callback) {
|
||||
return td::actor::create_actor<AdnlExtClientImpl>("extclient", std::move(dst), dst_addr, std::move(callback));
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlExtClient> AdnlExtClient::create(AdnlNodeIdFull dst, PrivateKey local_id,
|
||||
td::IPAddress dst_addr,
|
||||
std::unique_ptr<AdnlExtClient::Callback> callback) {
|
||||
return td::actor::create_actor<AdnlExtClientImpl>("extclient", std::move(dst), std::move(local_id), dst_addr,
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
td::Status AdnlOutboundConnection::process_packet(td::BufferSlice data) {
|
||||
TRY_RESULT(F, fetch_tl_object<lite_api::adnl_message_answer>(std::move(data), true));
|
||||
td::actor::send_closure(ext_client_, &AdnlExtClientImpl::answer_query, F->query_id_, std::move(F->answer_));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
48
adnl/adnl-ext-client.h
Normal file
48
adnl/adnl-ext-client.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-node-id.hpp"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlExtClient : public td::actor::Actor {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
virtual ~Callback() = default;
|
||||
virtual void on_ready() = 0;
|
||||
virtual void on_stop_ready() = 0;
|
||||
};
|
||||
virtual ~AdnlExtClient() = default;
|
||||
virtual void check_ready(td::Promise<td::Unit> promise) = 0;
|
||||
virtual void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
static td::actor::ActorOwn<AdnlExtClient> create(AdnlNodeIdFull dst, td::IPAddress dst_addr,
|
||||
std::unique_ptr<AdnlExtClient::Callback> callback);
|
||||
static td::actor::ActorOwn<AdnlExtClient> create(AdnlNodeIdFull dst, PrivateKey local_id, td::IPAddress dst_addr,
|
||||
std::unique_ptr<AdnlExtClient::Callback> callback);
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
145
adnl/adnl-ext-client.hpp
Normal file
145
adnl/adnl-ext-client.hpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "auto/tl/lite_api.h"
|
||||
#include "adnl-ext-connection.hpp"
|
||||
#include "tl-utils/lite-utils.hpp"
|
||||
#include "td/utils/Random.h"
|
||||
#include "adnl-query.h"
|
||||
#include "keys/encryptor.h"
|
||||
#include "adnl-ext-client.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlExtClientImpl;
|
||||
|
||||
class AdnlOutboundConnection : public AdnlExtConnection {
|
||||
private:
|
||||
AdnlNodeIdFull dst_;
|
||||
PrivateKey local_id_;
|
||||
td::actor::ActorId<AdnlExtClientImpl> ext_client_;
|
||||
td::SecureString nonce_;
|
||||
bool authorization_complete_ = false;
|
||||
|
||||
public:
|
||||
AdnlOutboundConnection(td::SocketFd fd, std::unique_ptr<AdnlExtConnection::Callback> callback, AdnlNodeIdFull dst,
|
||||
td::actor::ActorId<AdnlExtClientImpl> ext_client)
|
||||
: AdnlExtConnection(std::move(fd), std::move(callback), true), dst_(std::move(dst)), ext_client_(ext_client) {
|
||||
}
|
||||
AdnlOutboundConnection(td::SocketFd fd, std::unique_ptr<AdnlExtConnection::Callback> callback, AdnlNodeIdFull dst,
|
||||
PrivateKey local_id, td::actor::ActorId<AdnlExtClientImpl> ext_client)
|
||||
: AdnlExtConnection(std::move(fd), std::move(callback), true)
|
||||
, dst_(std::move(dst))
|
||||
, local_id_(local_id)
|
||||
, ext_client_(ext_client) {
|
||||
}
|
||||
td::Status process_packet(td::BufferSlice data) override;
|
||||
td::Status process_init_packet(td::BufferSlice data) override {
|
||||
UNREACHABLE();
|
||||
}
|
||||
td::Status process_custom_packet(td::BufferSlice &data, bool &processed) override;
|
||||
void start_up() override;
|
||||
bool authorized() const override {
|
||||
return local_id_.empty() ? true : authorization_complete_;
|
||||
}
|
||||
};
|
||||
|
||||
class AdnlExtClientImpl : public AdnlExtClient {
|
||||
public:
|
||||
AdnlExtClientImpl(AdnlNodeIdFull dst_id, td::IPAddress dst_addr, std::unique_ptr<Callback> callback)
|
||||
: dst_(std::move(dst_id)), dst_addr_(dst_addr), callback_(std::move(callback)) {
|
||||
}
|
||||
AdnlExtClientImpl(AdnlNodeIdFull dst_id, PrivateKey local_id, td::IPAddress dst_addr,
|
||||
std::unique_ptr<Callback> callback)
|
||||
: dst_(std::move(dst_id)), local_id_(local_id), dst_addr_(dst_addr), callback_(std::move(callback)) {
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
alarm_timestamp() = next_create_at_;
|
||||
}
|
||||
void conn_stopped(td::actor::ActorId<AdnlExtConnection> conn) {
|
||||
if (!conn_.empty() && conn_.get() == conn) {
|
||||
callback_->on_stop_ready();
|
||||
conn_ = {};
|
||||
alarm_timestamp() = next_create_at_;
|
||||
try_stop();
|
||||
}
|
||||
}
|
||||
void conn_ready(td::actor::ActorId<AdnlExtConnection> conn) {
|
||||
if (!conn_.empty() && conn_.get() == conn) {
|
||||
callback_->on_ready();
|
||||
}
|
||||
}
|
||||
void check_ready(td::Promise<td::Unit> promise) override;
|
||||
void send_query(std::string name, td::BufferSlice data, td::Timestamp timeout,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
auto P = [SelfId = actor_id(this)](AdnlQueryId id) {
|
||||
td::actor::send_closure(SelfId, &AdnlExtClientImpl::destroy_query, id);
|
||||
};
|
||||
auto q_id = generate_next_query_id();
|
||||
out_queries_.emplace(q_id, AdnlQuery::create(std::move(promise), std::move(P), name, timeout, q_id));
|
||||
if (!conn_.empty()) {
|
||||
auto obj = create_tl_object<lite_api::adnl_message_query>(q_id, std::move(data));
|
||||
td::actor::send_closure(conn_, &AdnlOutboundConnection::send, serialize_tl_object(obj, true));
|
||||
}
|
||||
}
|
||||
void destroy_query(AdnlQueryId id) {
|
||||
out_queries_.erase(id);
|
||||
try_stop();
|
||||
}
|
||||
void answer_query(AdnlQueryId id, td::BufferSlice data) {
|
||||
auto it = out_queries_.find(id);
|
||||
if (it != out_queries_.end()) {
|
||||
td::actor::send_closure(it->second, &AdnlQuery::result, std::move(data));
|
||||
}
|
||||
}
|
||||
void alarm() override;
|
||||
void hangup() override;
|
||||
AdnlQueryId generate_next_query_id() {
|
||||
while (true) {
|
||||
AdnlQueryId q_id = AdnlQuery::random_query_id();
|
||||
if (out_queries_.count(q_id) == 0) {
|
||||
return q_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AdnlNodeIdFull dst_;
|
||||
PrivateKey local_id_;
|
||||
td::IPAddress dst_addr_;
|
||||
|
||||
std::unique_ptr<Callback> callback_;
|
||||
|
||||
td::actor::ActorOwn<AdnlOutboundConnection> conn_;
|
||||
td::Timestamp next_create_at_ = td::Timestamp::now_cached();
|
||||
|
||||
std::map<AdnlQueryId, td::actor::ActorId<AdnlQuery>> out_queries_;
|
||||
|
||||
bool is_closing_{false};
|
||||
td::uint32 ref_cnt_{1};
|
||||
void try_stop();
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
192
adnl/adnl-ext-connection.cpp
Normal file
192
adnl/adnl-ext-connection.cpp
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-ext-connection.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
void AdnlExtConnection::send_uninit(td::BufferSlice data) {
|
||||
buffered_fd_.output_buffer().append(std::move(data));
|
||||
loop();
|
||||
}
|
||||
|
||||
void AdnlExtConnection::send(td::BufferSlice data) {
|
||||
LOG(DEBUG) << "sending packet of size " << data.size();
|
||||
auto data_size = td::narrow_cast<td::uint32>(data.size()) + 32 + 32;
|
||||
if (data_size < 32 || data_size > (1 << 24)) {
|
||||
LOG(WARNING) << "bad packet size " << data_size;
|
||||
return;
|
||||
}
|
||||
|
||||
td::BufferSlice d{data.size() + 4 + 32 + 32};
|
||||
auto S = d.as_slice();
|
||||
|
||||
S.copy_from(td::Slice(reinterpret_cast<const td::uint8 *>(&data_size), 4));
|
||||
S.remove_prefix(4);
|
||||
auto Sc = S;
|
||||
td::Random::secure_bytes(S.copy().truncate(32));
|
||||
S.remove_prefix(32);
|
||||
S.copy_from(data.as_slice());
|
||||
S.remove_prefix(data.size());
|
||||
|
||||
td::sha256(Sc.truncate(32 + data.size()), S);
|
||||
|
||||
td::BufferSlice e{d.size()};
|
||||
|
||||
out_ctr_.encrypt(d.as_slice(), e.as_slice());
|
||||
|
||||
buffered_fd_.output_buffer().append(std::move(e));
|
||||
loop();
|
||||
}
|
||||
|
||||
td::Status AdnlExtConnection::receive(td::ChainBufferReader &input, bool &exit_loop) {
|
||||
if (stop_read_) {
|
||||
exit_loop = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
if (input.size() > 0) {
|
||||
received_bytes_ = 1;
|
||||
}
|
||||
if (inited_) {
|
||||
if (!read_len_) {
|
||||
if (input.size() < 4) {
|
||||
exit_loop = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
char x[4];
|
||||
td::MutableSlice s{x, 4};
|
||||
input.advance(4, s);
|
||||
|
||||
td::MutableSlice e{reinterpret_cast<td::uint8 *>(&len_), 4};
|
||||
in_ctr_.encrypt(s, e);
|
||||
LOG(DEBUG) << "len=" << len_;
|
||||
if (len_ > (1 << 24) || len_ < 32) {
|
||||
return td::Status::Error("Too big packet");
|
||||
}
|
||||
read_len_ = true;
|
||||
}
|
||||
if (input.size() < len_) {
|
||||
exit_loop = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
auto data = input.cut_head(len_).move_as_buffer_slice();
|
||||
update_timer();
|
||||
|
||||
td::BufferSlice dec_data{data.size()};
|
||||
in_ctr_.encrypt(data.as_slice(), dec_data.as_slice());
|
||||
|
||||
exit_loop = false;
|
||||
read_len_ = false;
|
||||
len_ = 0;
|
||||
return receive_packet(std::move(dec_data));
|
||||
} else {
|
||||
if (input.size() < 256) {
|
||||
exit_loop = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
auto data = input.cut_head(256).move_as_buffer_slice();
|
||||
update_timer();
|
||||
|
||||
exit_loop = false;
|
||||
return process_init_packet(std::move(data));
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlExtConnection::loop() {
|
||||
auto status = [&] {
|
||||
TRY_STATUS(buffered_fd_.flush_read());
|
||||
auto &input = buffered_fd_.input_buffer();
|
||||
bool exit_loop = false;
|
||||
while (!exit_loop) {
|
||||
TRY_STATUS(receive(input, exit_loop));
|
||||
}
|
||||
TRY_STATUS(buffered_fd_.flush_write());
|
||||
if (td::can_close(buffered_fd_)) {
|
||||
stop();
|
||||
}
|
||||
return td::Status::OK();
|
||||
}();
|
||||
if (status.is_error()) {
|
||||
LOG(ERROR) << "Client got error " << status;
|
||||
stop();
|
||||
} else {
|
||||
send_ready();
|
||||
}
|
||||
}
|
||||
|
||||
td::Status AdnlExtConnection::init_crypto(td::Slice S) {
|
||||
if (S.size() < 96) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "too small enc data");
|
||||
}
|
||||
CHECK(S.size() >= 96);
|
||||
td::SecureString s1(32), s2(32);
|
||||
td::SecureString v1(16), v2(16);
|
||||
s1.as_mutable_slice().copy_from(S.copy().truncate(32));
|
||||
S.remove_prefix(32);
|
||||
s2.as_mutable_slice().copy_from(S.copy().truncate(32));
|
||||
S.remove_prefix(32);
|
||||
v1.as_mutable_slice().copy_from(S.copy().truncate(16));
|
||||
S.remove_prefix(16);
|
||||
v2.as_mutable_slice().copy_from(S.copy().truncate(16));
|
||||
S.remove_prefix(16);
|
||||
if (is_client_) {
|
||||
in_ctr_.init(s1, v1);
|
||||
out_ctr_.init(s2, v2);
|
||||
} else {
|
||||
in_ctr_.init(s2, v2);
|
||||
out_ctr_.init(s1, v1);
|
||||
}
|
||||
inited_ = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status AdnlExtConnection::receive_packet(td::BufferSlice data) {
|
||||
LOG(DEBUG) << "received packet of size " << data.size();
|
||||
auto S = data.as_slice();
|
||||
S.truncate(data.size() - 32);
|
||||
auto D = data.as_slice();
|
||||
D.remove_prefix(data.size() - 32);
|
||||
|
||||
if (td::sha256(S) != D) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "sha256 mismatch");
|
||||
}
|
||||
|
||||
data.truncate(data.size() - 32);
|
||||
data.confirm_read(32);
|
||||
|
||||
if (data.size() == 0) {
|
||||
// keepalive
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
bool processed = false;
|
||||
TRY_STATUS(process_custom_packet(data, processed));
|
||||
if (processed) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
return process_packet(std::move(data));
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
163
adnl/adnl-ext-connection.hpp
Normal file
163
adnl/adnl-ext-connection.hpp
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/net/TcpListener.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/BufferedFd.h"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
#include "td/utils/Random.h"
|
||||
#include "common/errorcode.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlExtConnection : public td::actor::Actor, public td::ObserverBase {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
virtual ~Callback() = default;
|
||||
virtual void on_close(td::actor::ActorId<AdnlExtConnection> conn) = 0;
|
||||
virtual void on_ready(td::actor::ActorId<AdnlExtConnection> conn) = 0;
|
||||
};
|
||||
|
||||
double timeout() {
|
||||
return is_client_ ? 20.0 : 60.0;
|
||||
}
|
||||
|
||||
AdnlExtConnection(td::SocketFd fd, std::unique_ptr<Callback> callback, bool is_client)
|
||||
: buffered_fd_(std::move(fd)), callback_(std::move(callback)), is_client_(is_client) {
|
||||
}
|
||||
void send(td::BufferSlice data);
|
||||
void send_uninit(td::BufferSlice data);
|
||||
td::Status receive(td::ChainBufferReader &input, bool &exit_loop);
|
||||
virtual td::Status process_packet(td::BufferSlice data) = 0;
|
||||
td::Status receive_packet(td::BufferSlice data);
|
||||
virtual td::Status process_custom_packet(td::BufferSlice &data, bool &processed) = 0;
|
||||
virtual td::Status process_init_packet(td::BufferSlice data) = 0;
|
||||
virtual bool authorized() const {
|
||||
return false;
|
||||
}
|
||||
td::Status init_crypto(td::Slice data);
|
||||
void stop_read() {
|
||||
stop_read_ = true;
|
||||
}
|
||||
void resume_read() {
|
||||
stop_read_ = false;
|
||||
}
|
||||
bool check_ready() const {
|
||||
return received_bytes_ && inited_ && authorized() && !td::can_close(buffered_fd_);
|
||||
}
|
||||
void check_ready_async(td::Promise<td::Unit> promise) {
|
||||
if (check_ready()) {
|
||||
promise.set_value(td::Unit());
|
||||
} else {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
|
||||
}
|
||||
}
|
||||
void send_ready() {
|
||||
if (check_ready() && !sent_ready_ && callback_) {
|
||||
callback_->on_ready(actor_id(this));
|
||||
sent_ready_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
td::BufferedFd<td::SocketFd> buffered_fd_;
|
||||
td::actor::ActorId<AdnlExtConnection> self_;
|
||||
std::unique_ptr<Callback> callback_;
|
||||
bool sent_ready_ = false;
|
||||
bool is_client_;
|
||||
|
||||
void notify() override {
|
||||
// NB: Interface will be changed
|
||||
td::actor::send_closure_later(self_, &AdnlExtConnection::on_net);
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
self_ = actor_id(this);
|
||||
// Subscribe for socket updates
|
||||
// NB: Interface will be changed
|
||||
td::actor::SchedulerContext::get()->get_poll().subscribe(buffered_fd_.get_poll_info().extract_pollable_fd(this),
|
||||
td::PollFlags::ReadWrite());
|
||||
update_timer();
|
||||
notify();
|
||||
}
|
||||
|
||||
private:
|
||||
td::AesCtrState in_ctr_;
|
||||
td::AesCtrState out_ctr_;
|
||||
bool inited_ = false;
|
||||
bool stop_read_ = false;
|
||||
bool read_len_ = false;
|
||||
td::uint32 len_;
|
||||
td::uint32 received_bytes_ = 0;
|
||||
td::Timestamp fail_at_;
|
||||
td::Timestamp send_ping_at_;
|
||||
bool ping_sent_ = false;
|
||||
|
||||
void on_net() {
|
||||
loop();
|
||||
}
|
||||
|
||||
void tear_down() override {
|
||||
if (callback_) {
|
||||
callback_->on_close(actor_id(this));
|
||||
callback_ = nullptr;
|
||||
}
|
||||
// unsubscribe from socket updates
|
||||
// nb: interface will be changed
|
||||
td::actor::SchedulerContext::get()->get_poll().unsubscribe(buffered_fd_.get_poll_info().get_pollable_fd_ref());
|
||||
}
|
||||
|
||||
void update_timer() {
|
||||
fail_at_ = td::Timestamp::in(timeout());
|
||||
alarm_timestamp() = fail_at_;
|
||||
if (is_client_) {
|
||||
ping_sent_ = false;
|
||||
send_ping_at_ = td::Timestamp::in(timeout() / 2);
|
||||
alarm_timestamp().relax(send_ping_at_);
|
||||
}
|
||||
}
|
||||
|
||||
void loop() override;
|
||||
|
||||
void alarm() override {
|
||||
alarm_timestamp() = fail_at_;
|
||||
if (fail_at_.is_in_past()) {
|
||||
stop();
|
||||
} else if (is_client_ && !ping_sent_) {
|
||||
if (send_ping_at_.is_in_past()) {
|
||||
auto obj = create_tl_object<ton_api::tcp_ping>(td::Random::fast_uint64());
|
||||
send(serialize_tl_object(obj, true));
|
||||
ping_sent_ = true;
|
||||
} else {
|
||||
alarm_timestamp().relax(send_ping_at_);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
182
adnl/adnl-ext-server.cpp
Normal file
182
adnl/adnl-ext-server.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-ext-server.hpp"
|
||||
#include "keys/encryptor.h"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
td::Status AdnlInboundConnection::process_packet(td::BufferSlice data) {
|
||||
TRY_RESULT(f, fetch_tl_object<ton_api::adnl_message_query>(std::move(data), true));
|
||||
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), query_id = f->query_id_](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
auto S = R.move_as_error();
|
||||
LOG(WARNING) << "failed ext query: " << S;
|
||||
} else {
|
||||
auto B = create_tl_object<ton_api::adnl_message_answer>(query_id, R.move_as_ok());
|
||||
td::actor::send_closure(SelfId, &AdnlInboundConnection::send, serialize_tl_object(B, true));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(peer_table_, &AdnlPeerTable::deliver_query, remote_id_, local_id_, std::move(f->query_),
|
||||
std::move(P));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status AdnlInboundConnection::process_init_packet(td::BufferSlice data) {
|
||||
if (data.size() < 32) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "too small init packet");
|
||||
}
|
||||
local_id_ = AdnlNodeIdShort{data.as_slice().truncate(32)};
|
||||
data.confirm_read(32);
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||
td::actor::send_closure(SelfId, &AdnlInboundConnection::inited_crypto, std::move(R));
|
||||
});
|
||||
|
||||
td::actor::send_closure(ext_server_, &AdnlExtServerImpl::decrypt_init_packet, local_id_, std::move(data),
|
||||
std::move(P));
|
||||
stop_read();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void AdnlInboundConnection::inited_crypto(td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(ERROR) << "failed to init crypto: " << R.move_as_error();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
auto S = init_crypto(R.move_as_ok().as_slice());
|
||||
if (S.is_error()) {
|
||||
LOG(ERROR) << "failed to init crypto (2): " << R.move_as_error();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
send(td::BufferSlice());
|
||||
resume_read();
|
||||
notify();
|
||||
}
|
||||
|
||||
td::Status AdnlInboundConnection::process_custom_packet(td::BufferSlice &data, bool &processed) {
|
||||
if (data.size() == 12) {
|
||||
auto F = fetch_tl_object<ton_api::tcp_ping>(data.clone(), true);
|
||||
if (F.is_ok()) {
|
||||
auto f = F.move_as_ok();
|
||||
auto obj = create_tl_object<ton_api::tcp_pong>(f->random_id_);
|
||||
send(serialize_tl_object(obj, true));
|
||||
processed = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
}
|
||||
if (1) {
|
||||
auto F = fetch_tl_object<ton_api::tcp_authentificate>(data.clone(), true);
|
||||
if (F.is_ok()) {
|
||||
if (nonce_.size() > 0 || !remote_id_.is_zero()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "duplicate authentificate");
|
||||
}
|
||||
auto f = F.move_as_ok();
|
||||
nonce_ = td::SecureString{f->nonce_.size() + 256};
|
||||
nonce_.as_mutable_slice().truncate(f->nonce_.size()).copy_from(f->nonce_.as_slice());
|
||||
td::Random::secure_bytes(nonce_.as_mutable_slice().remove_prefix(f->nonce_.size()));
|
||||
|
||||
auto obj = create_tl_object<ton_api::tcp_authentificationNonce>(
|
||||
td::BufferSlice{nonce_.as_slice().remove_prefix(f->nonce_.size())});
|
||||
send(serialize_tl_object(obj, true));
|
||||
processed = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
}
|
||||
|
||||
if (nonce_.size() != 0) {
|
||||
auto F = fetch_tl_object<ton_api::tcp_authentificationComplete>(data.clone(), true);
|
||||
if (F.is_ok()) {
|
||||
auto f = F.move_as_ok();
|
||||
if (nonce_.size() == 0 || !remote_id_.is_zero()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "duplicate authentificate");
|
||||
}
|
||||
|
||||
auto pub_key = PublicKey{f->key_};
|
||||
TRY_RESULT(enc, pub_key.create_encryptor());
|
||||
TRY_STATUS(enc->check_signature(nonce_.as_slice(), f->signature_.as_slice()));
|
||||
|
||||
remote_id_ = AdnlNodeIdShort{pub_key.compute_short_id()};
|
||||
nonce_.clear();
|
||||
processed = true;
|
||||
return td::Status::OK();
|
||||
}
|
||||
}
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void AdnlExtServerImpl::add_tcp_port(td::uint16 port) {
|
||||
auto it = listeners_.find(port);
|
||||
if (it != listeners_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
class Callback : public td::TcpListener::Callback {
|
||||
private:
|
||||
td::actor::ActorId<AdnlExtServerImpl> id_;
|
||||
|
||||
public:
|
||||
Callback(td::actor::ActorId<AdnlExtServerImpl> id) : id_(id) {
|
||||
}
|
||||
void accept(td::SocketFd fd) override {
|
||||
td::actor::send_closure(id_, &AdnlExtServerImpl::accepted, std::move(fd));
|
||||
}
|
||||
};
|
||||
|
||||
auto act = td::actor::create_actor<td::TcpListener>(td::actor::ActorOptions().with_name("listener").with_poll(), port,
|
||||
std::make_unique<Callback>(actor_id(this)));
|
||||
listeners_.emplace(port, std::move(act));
|
||||
}
|
||||
|
||||
void AdnlExtServerImpl::add_local_id(AdnlNodeIdShort id) {
|
||||
local_ids_.insert(id);
|
||||
}
|
||||
|
||||
void AdnlExtServerImpl::accepted(td::SocketFd fd) {
|
||||
td::actor::create_actor<AdnlInboundConnection>(td::actor::ActorOptions().with_name("inconn").with_poll(),
|
||||
std::move(fd), peer_table_, actor_id(this))
|
||||
.release();
|
||||
}
|
||||
|
||||
void AdnlExtServerImpl::decrypt_init_packet(AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto it = local_ids_.find(dst);
|
||||
if (it != local_ids_.end()) {
|
||||
td::actor::send_closure(peer_table_, &AdnlPeerTable::decrypt_message, dst, std::move(data), std::move(promise));
|
||||
} else {
|
||||
promise.set_error(td::Status::Error());
|
||||
}
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlExtServer> AdnlExtServerCreator::create(td::actor::ActorId<AdnlPeerTable> adnl,
|
||||
std::vector<AdnlNodeIdShort> ids,
|
||||
std::vector<td::uint16> ports) {
|
||||
return td::actor::create_actor<AdnlExtServerImpl>("extserver", adnl, std::move(ids), std::move(ports));
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
35
adnl/adnl-ext-server.h
Normal file
35
adnl/adnl-ext-server.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-peer-table.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlExtServerCreator {
|
||||
public:
|
||||
static td::actor::ActorOwn<AdnlExtServer> create(td::actor::ActorId<AdnlPeerTable> adnl,
|
||||
std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports);
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
92
adnl/adnl-ext-server.hpp
Normal file
92
adnl/adnl-ext-server.hpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-peer-table.h"
|
||||
#include "td/net/TcpListener.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/BufferedFd.h"
|
||||
#include "adnl-ext-connection.hpp"
|
||||
#include "adnl-ext-server.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlExtServerImpl;
|
||||
|
||||
class AdnlInboundConnection : public AdnlExtConnection {
|
||||
public:
|
||||
AdnlInboundConnection(td::SocketFd fd, td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<AdnlExtServerImpl> ext_server)
|
||||
: AdnlExtConnection(std::move(fd), nullptr, false), peer_table_(peer_table), ext_server_(ext_server) {
|
||||
}
|
||||
|
||||
td::Status process_packet(td::BufferSlice data) override;
|
||||
td::Status process_init_packet(td::BufferSlice data) override;
|
||||
td::Status process_custom_packet(td::BufferSlice &data, bool &processed) override;
|
||||
void inited_crypto(td::Result<td::BufferSlice> R);
|
||||
|
||||
private:
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table_;
|
||||
td::actor::ActorId<AdnlExtServerImpl> ext_server_;
|
||||
AdnlNodeIdShort local_id_;
|
||||
|
||||
td::SecureString nonce_;
|
||||
AdnlNodeIdShort remote_id_ = AdnlNodeIdShort::zero();
|
||||
};
|
||||
|
||||
class AdnlExtServerImpl : public AdnlExtServer {
|
||||
public:
|
||||
void add_tcp_port(td::uint16 port) override;
|
||||
void add_local_id(AdnlNodeIdShort id) override;
|
||||
void accepted(td::SocketFd fd);
|
||||
void decrypt_init_packet(AdnlNodeIdShort dst, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
|
||||
|
||||
void start_up() override {
|
||||
for (auto &port : ports_) {
|
||||
add_tcp_port(port);
|
||||
}
|
||||
ports_.clear();
|
||||
}
|
||||
|
||||
AdnlExtServerImpl(td::actor::ActorId<AdnlPeerTable> adnl, std::vector<AdnlNodeIdShort> ids,
|
||||
std::vector<td::uint16> ports)
|
||||
: peer_table_(adnl) {
|
||||
for (auto &id : ids) {
|
||||
add_local_id(id);
|
||||
}
|
||||
for (auto &port : ports) {
|
||||
ports_.insert(port);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table_;
|
||||
std::set<AdnlNodeIdShort> local_ids_;
|
||||
std::set<td::uint16> ports_;
|
||||
std::map<td::uint16, td::actor::ActorOwn<td::TcpListener>> listeners_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
279
adnl/adnl-local-id.cpp
Normal file
279
adnl/adnl-local-id.cpp
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
#include "adnl-local-id.h"
|
||||
#include "keys/encryptor.h"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
AdnlNodeIdFull AdnlLocalId::get_id() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
AdnlNodeIdShort AdnlLocalId::get_short_id() const {
|
||||
return short_id_;
|
||||
}
|
||||
|
||||
AdnlAddressList AdnlLocalId::get_addr_list() const {
|
||||
CHECK(!addr_list_.empty());
|
||||
return addr_list_;
|
||||
}
|
||||
|
||||
void AdnlLocalId::receive(td::BufferSlice data) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[peer_table = peer_table_, dst = short_id_, id = print_id()](td::Result<AdnlPacket> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(ADNL_WARNING) << id << ": dropping IN message: cannot decrypt: " << R.move_as_error();
|
||||
} else {
|
||||
td::actor::send_closure(peer_table, &AdnlPeerTable::receive_decrypted_packet, dst, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
|
||||
decrypt(std::move(data), std::move(P));
|
||||
}
|
||||
|
||||
void AdnlLocalId::deliver(AdnlNodeIdShort src, td::BufferSlice data) {
|
||||
auto s = std::move(data);
|
||||
for (auto &cb : cb_) {
|
||||
auto f = cb.first;
|
||||
if (f.length() <= s.length() && s.as_slice().substr(0, f.length()) == f) {
|
||||
cb.second->receive_message(src, short_id_, std::move(s));
|
||||
return;
|
||||
}
|
||||
}
|
||||
VLOG(ADNL_INFO) << this << ": dropping IN message from " << src
|
||||
<< ": no callbacks for custom message. firstint=" << td::TlParser(s.as_slice()).fetch_int();
|
||||
}
|
||||
|
||||
void AdnlLocalId::deliver_query(AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
|
||||
auto s = std::move(data);
|
||||
for (auto &cb : cb_) {
|
||||
auto f = cb.first;
|
||||
if (f.length() <= s.length() && s.as_slice().substr(0, f.length()) == f) {
|
||||
cb.second->receive_query(src, short_id_, std::move(s), std::move(promise));
|
||||
return;
|
||||
}
|
||||
}
|
||||
VLOG(ADNL_INFO) << this << ": dropping IN message from " << src
|
||||
<< ": no callbacks for custom query. firstint=" << td::TlParser(s.as_slice()).fetch_int();
|
||||
promise.set_error(td::Status::Error(ErrorCode::warning, "no callbacks for query"));
|
||||
}
|
||||
|
||||
void AdnlLocalId::subscribe(std::string prefix, std::unique_ptr<AdnlPeerTable::Callback> callback) {
|
||||
auto S = td::Slice(prefix);
|
||||
for (auto &cb : cb_) {
|
||||
auto G = td::Slice(cb.first);
|
||||
if (S.size() < G.size()) {
|
||||
LOG_CHECK(G.substr(0, S.size()) != S) << this << ": duplicate subscribe prefix";
|
||||
} else {
|
||||
LOG_CHECK(S.substr(0, G.size()) != G) << this << ": duplicate subscribe prefix";
|
||||
}
|
||||
}
|
||||
cb_.emplace_back(prefix, std::move(callback));
|
||||
}
|
||||
|
||||
void AdnlLocalId::unsubscribe(std::string prefix) {
|
||||
bool deleted = false;
|
||||
for (auto it = cb_.begin(); it != cb_.end();) {
|
||||
if (it->first == prefix) {
|
||||
it = cb_.erase(it);
|
||||
deleted = true;
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
LOG_CHECK(deleted) << this << ": cannot unsubscribe: prefix not found";
|
||||
}
|
||||
|
||||
void AdnlLocalId::update_address_list(AdnlAddressList addr_list) {
|
||||
addr_list_ = std::move(addr_list);
|
||||
addr_list_.set_reinit_date(Adnl::adnl_start_time());
|
||||
addr_list_.set_version(static_cast<td::int32>(td::Clocks::system()));
|
||||
|
||||
VLOG(ADNL_INFO) << this << ": updated addr list. New version set to " << addr_list_.version();
|
||||
|
||||
publish_address_list();
|
||||
}
|
||||
|
||||
void AdnlLocalId::publish_address_list() {
|
||||
if (dht_node_.empty() || addr_list_.empty()) {
|
||||
VLOG(ADNL_NOTICE) << this << ": skipping public addr list, because localid (or dht node) not fully initialized";
|
||||
return;
|
||||
}
|
||||
|
||||
dht::DhtKey dht_key{short_id_.pubkey_hash(), "address", 0};
|
||||
auto dht_update_rule = dht::DhtUpdateRuleSignature::create().move_as_ok();
|
||||
dht::DhtKeyDescription dht_key_description{std::move(dht_key), id_.pubkey(), std::move(dht_update_rule),
|
||||
td::BufferSlice()};
|
||||
|
||||
auto B = serialize_tl_object(dht_key_description.tl(), true);
|
||||
|
||||
auto P = td::PromiseCreator::lambda([dht_node = dht_node_, SelfId = actor_id(this), addr_list = addr_list_.tl(),
|
||||
dht_key_description = std::move(dht_key_description),
|
||||
print_id = print_id()](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
LOG(ERROR) << print_id << ": cannot sign: " << R.move_as_error();
|
||||
return;
|
||||
}
|
||||
|
||||
dht_key_description.update_signature(R.move_as_ok());
|
||||
dht_key_description.check().ensure();
|
||||
|
||||
auto ttl = static_cast<td::uint32>(td::Clocks::system() + 3600);
|
||||
dht::DhtValue dht_value{std::move(dht_key_description), serialize_tl_object(addr_list, true), ttl,
|
||||
td::BufferSlice("")};
|
||||
|
||||
auto B = serialize_tl_object(dht_value.tl(), true);
|
||||
|
||||
auto Q = td::PromiseCreator::lambda(
|
||||
[dht_node, dht_value = std::move(dht_value), print_id](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
LOG(ERROR) << print_id << ": cannot sign: " << R.move_as_error();
|
||||
return;
|
||||
}
|
||||
dht_value.update_signature(R.move_as_ok());
|
||||
dht_value.check().ensure();
|
||||
|
||||
auto E = td::PromiseCreator::lambda([print_id](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(ADNL_NOTICE) << print_id << ": failed to update addr list in DHT: " << R.move_as_error();
|
||||
} else {
|
||||
VLOG(ADNL_INFO) << print_id << ": updated dht addr list";
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(dht_node, &dht::Dht::set_value, std::move(dht_value), std::move(E));
|
||||
});
|
||||
|
||||
td::actor::send_closure(SelfId, &AdnlLocalId::sign_async, std::move(B), std::move(Q));
|
||||
});
|
||||
|
||||
td::actor::send_closure(keyring_, &keyring::Keyring::sign_message, short_id_.pubkey_hash(), std::move(B),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
AdnlLocalId::AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<dht::Dht> dht_node) {
|
||||
id_ = std::move(id);
|
||||
short_id_ = id_.compute_short_id();
|
||||
addr_list_ = std::move(addr_list);
|
||||
if (addr_list_.addrs().size() > 0) {
|
||||
addr_list_.set_version(static_cast<td::int32>(td::Clocks::system()));
|
||||
}
|
||||
peer_table_ = peer_table;
|
||||
keyring_ = keyring;
|
||||
dht_node_ = dht_node;
|
||||
|
||||
VLOG(ADNL_INFO) << this << ": created local id " << short_id_;
|
||||
}
|
||||
|
||||
void AdnlLocalId::get_self_node(td::Promise<AdnlNode> promise) {
|
||||
//addr_list_->version_ = static_cast<td::int32>(td::Clocks::system());
|
||||
promise.set_value(AdnlNode{id_, addr_list_});
|
||||
}
|
||||
|
||||
void AdnlLocalId::decrypt_message(td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::send_closure(keyring_, &keyring::Keyring::decrypt_message, short_id_.pubkey_hash(), std::move(data),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void AdnlLocalId::decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), p = std::move(promise)](td::Result<td::BufferSlice> res) mutable {
|
||||
if (res.is_error()) {
|
||||
p.set_error(res.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure_later(SelfId, &AdnlLocalId::decrypt_continue, res.move_as_ok(), std::move(p));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(keyring_, &keyring::Keyring::decrypt_message, short_id_.pubkey_hash(), std::move(data),
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void AdnlLocalId::decrypt_continue(td::BufferSlice data, td::Promise<AdnlPacket> promise) {
|
||||
auto R = fetch_tl_object<ton_api::adnl_packetContents>(std::move(data), true);
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
return;
|
||||
}
|
||||
|
||||
auto packetR = AdnlPacket::create(R.move_as_ok());
|
||||
if (packetR.is_error()) {
|
||||
promise.set_error(packetR.move_as_error());
|
||||
return;
|
||||
}
|
||||
promise.set_value(packetR.move_as_ok());
|
||||
}
|
||||
|
||||
void AdnlLocalId::sign_async(td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
|
||||
td::actor::send_closure(keyring_, &keyring::Keyring::sign_message, short_id_.pubkey_hash(), std::move(data),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void AdnlLocalId::sign_batch_async(std::vector<td::BufferSlice> data,
|
||||
td::Promise<std::vector<td::Result<td::BufferSlice>>> promise) {
|
||||
td::actor::send_closure(keyring_, &keyring::Keyring::sign_messages, short_id_.pubkey_hash(), std::move(data),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void AdnlLocalId::start_up() {
|
||||
publish_address_list();
|
||||
alarm_timestamp() = td::Timestamp::in(AdnlPeerTable::republish_addr_list_timeout() * td::Random::fast(1.0, 2.0));
|
||||
}
|
||||
|
||||
void AdnlLocalId::alarm() {
|
||||
publish_address_list();
|
||||
alarm_timestamp() = td::Timestamp::in(AdnlPeerTable::republish_addr_list_timeout() * td::Random::fast(1.0, 2.0));
|
||||
}
|
||||
|
||||
void AdnlLocalId::update_packet(AdnlPacket packet, bool update_id, bool sign, td::int32 update_addr_list_if,
|
||||
td::int32 update_priority_addr_list_if, td::Promise<AdnlPacket> promise) {
|
||||
packet.init_random();
|
||||
if (update_id) {
|
||||
packet.set_source(id_);
|
||||
}
|
||||
if (!addr_list_.empty() && update_addr_list_if < addr_list_.version()) {
|
||||
packet.set_addr_list(addr_list_);
|
||||
}
|
||||
if (!sign) {
|
||||
promise.set_result(std::move(packet));
|
||||
} else {
|
||||
auto to_sign = packet.to_sign();
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[packet = std::move(packet), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
} else {
|
||||
packet.set_signature(R.move_as_ok());
|
||||
promise.set_value(std::move(packet));
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(keyring_, &keyring::Keyring::sign_message, short_id_.pubkey_hash(), std::move(to_sign),
|
||||
std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
117
adnl/adnl-local-id.h
Normal file
117
adnl/adnl-local-id.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/BufferedUdp.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "keys/encryptor.h"
|
||||
#include "adnl-peer-table.h"
|
||||
#include "dht/dht.h"
|
||||
|
||||
#include "adnl-peer-table.h"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlLocalId : public td::actor::Actor {
|
||||
public:
|
||||
AdnlNodeIdFull get_id() const;
|
||||
AdnlNodeIdShort get_short_id() const;
|
||||
AdnlAddressList get_addr_list() const;
|
||||
void get_addr_list_async(td::Promise<AdnlAddressList> P) {
|
||||
P.set_value(get_addr_list());
|
||||
}
|
||||
|
||||
void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) {
|
||||
dht_node_ = dht_node;
|
||||
|
||||
publish_address_list();
|
||||
}
|
||||
|
||||
void decrypt(td::BufferSlice data, td::Promise<AdnlPacket> promise);
|
||||
void decrypt_continue(td::BufferSlice data, td::Promise<AdnlPacket> promise);
|
||||
void decrypt_message(td::BufferSlice data, td::Promise<td::BufferSlice> promise);
|
||||
void deliver(AdnlNodeIdShort src, td::BufferSlice data);
|
||||
void deliver_query(AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
|
||||
void receive(td::BufferSlice data);
|
||||
|
||||
void subscribe(std::string prefix, std::unique_ptr<AdnlPeerTable::Callback> callback);
|
||||
void unsubscribe(std::string prefix);
|
||||
|
||||
void update_address_list(AdnlAddressList addr_list);
|
||||
|
||||
void get_self_node(td::Promise<AdnlNode> promise);
|
||||
|
||||
void sign_async(td::BufferSlice data, td::Promise<td::BufferSlice> promise);
|
||||
void sign_batch_async(std::vector<td::BufferSlice> data,
|
||||
td::Promise<std::vector<td::Result<td::BufferSlice>>> promise);
|
||||
|
||||
AdnlLocalId(AdnlNodeIdFull id, AdnlAddressList addr_list, td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<dht::Dht> dht_node);
|
||||
|
||||
void start_up() override;
|
||||
void alarm() override;
|
||||
|
||||
void update_packet(AdnlPacket packet, bool update_id, bool sign, td::int32 update_addr_list_if,
|
||||
td::int32 update_priority_addr_list_if, td::Promise<AdnlPacket> promise);
|
||||
|
||||
struct PrintId {
|
||||
AdnlNodeIdShort id;
|
||||
};
|
||||
|
||||
PrintId print_id() const {
|
||||
return PrintId{short_id_};
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table_;
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
td::actor::ActorId<dht::Dht> dht_node_;
|
||||
std::vector<std::pair<std::string, std::unique_ptr<AdnlPeerTable::Callback>>> cb_;
|
||||
|
||||
AdnlAddressList addr_list_;
|
||||
AdnlNodeIdFull id_;
|
||||
AdnlNodeIdShort short_id_;
|
||||
|
||||
void publish_address_list();
|
||||
};
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlLocalId::PrintId &id) {
|
||||
sb << "[localid " << id.id << "]";
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlLocalId &localid) {
|
||||
sb << localid.print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlLocalId *localid) {
|
||||
sb << localid->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
54
adnl/adnl-message.cpp
Normal file
54
adnl/adnl-message.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl/adnl-message.h"
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
AdnlMessage::AdnlMessage(tl_object_ptr<ton_api::adnl_Message> message) {
|
||||
ton_api::downcast_call(
|
||||
*message.get(),
|
||||
td::overloaded(
|
||||
[&](ton_api::adnl_message_createChannel &msg) {
|
||||
message_ = adnlmessage::AdnlMessageCreateChannel{msg.key_, msg.date_};
|
||||
},
|
||||
[&](ton_api::adnl_message_confirmChannel &msg) {
|
||||
message_ = adnlmessage::AdnlMessageConfirmChannel{msg.key_, msg.peer_key_, msg.date_};
|
||||
},
|
||||
[&](ton_api::adnl_message_custom &msg) { message_ = adnlmessage::AdnlMessageCustom{std::move(msg.data_)}; },
|
||||
[&](ton_api::adnl_message_nop &msg) { message_ = adnlmessage::AdnlMessageNop{}; },
|
||||
[&](ton_api::adnl_message_reinit &msg) { message_ = adnlmessage::AdnlMessageReinit{msg.date_}; },
|
||||
[&](ton_api::adnl_message_query &msg) {
|
||||
message_ = adnlmessage::AdnlMessageQuery{msg.query_id_, std::move(msg.query_)};
|
||||
},
|
||||
[&](ton_api::adnl_message_answer &msg) {
|
||||
message_ = adnlmessage::AdnlMessageAnswer{msg.query_id_, std::move(msg.answer_)};
|
||||
},
|
||||
[&](ton_api::adnl_message_part &msg) {
|
||||
message_ = adnlmessage::AdnlMessagePart{msg.hash_, static_cast<td::uint32>(msg.total_size_),
|
||||
static_cast<td::uint32>(msg.offset_), std::move(msg.data_)};
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
296
adnl/adnl-message.h
Normal file
296
adnl/adnl-message.h
Normal file
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl/adnl.h"
|
||||
#include "adnl/adnl-query.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
namespace adnlmessage {
|
||||
|
||||
class AdnlMessageCreateChannel {
|
||||
public:
|
||||
AdnlMessageCreateChannel(pubkeys::Ed25519 key, td::int32 date) : key_(key), date_(date) {
|
||||
}
|
||||
const auto &key() const {
|
||||
return key_;
|
||||
}
|
||||
auto date() const {
|
||||
return date_;
|
||||
}
|
||||
td::uint32 size() const {
|
||||
return 40;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
return create_tl_object<ton_api::adnl_message_createChannel>(key_.raw(), date_);
|
||||
}
|
||||
|
||||
private:
|
||||
pubkeys::Ed25519 key_;
|
||||
td::int32 date_;
|
||||
};
|
||||
|
||||
class AdnlMessageConfirmChannel {
|
||||
public:
|
||||
AdnlMessageConfirmChannel(pubkeys::Ed25519 key, pubkeys::Ed25519 peer_key, td::int32 date)
|
||||
: key_(key), peer_key_(peer_key), date_(date) {
|
||||
}
|
||||
const auto &key() const {
|
||||
return key_;
|
||||
}
|
||||
const auto &peer_key() const {
|
||||
return peer_key_;
|
||||
}
|
||||
auto date() const {
|
||||
return date_;
|
||||
}
|
||||
td::uint32 size() const {
|
||||
return 72;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
return create_tl_object<ton_api::adnl_message_confirmChannel>(key_.raw(), peer_key_.raw(), date_);
|
||||
}
|
||||
|
||||
private:
|
||||
pubkeys::Ed25519 key_;
|
||||
pubkeys::Ed25519 peer_key_;
|
||||
td::int32 date_;
|
||||
};
|
||||
|
||||
class AdnlMessageCustom {
|
||||
public:
|
||||
AdnlMessageCustom(td::BufferSlice data) : data_(std::move(data)) {
|
||||
}
|
||||
auto data() const {
|
||||
return data_.clone();
|
||||
}
|
||||
td::uint32 size() const {
|
||||
return static_cast<td::uint32>(data_.size()) + 12;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
return create_tl_object<ton_api::adnl_message_custom>(data_.clone());
|
||||
}
|
||||
|
||||
private:
|
||||
td::BufferSlice data_;
|
||||
};
|
||||
|
||||
class AdnlMessageNop {
|
||||
public:
|
||||
AdnlMessageNop() {
|
||||
}
|
||||
td::uint32 size() const {
|
||||
return 4;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
return create_tl_object<ton_api::adnl_message_nop>();
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class AdnlMessageReinit {
|
||||
public:
|
||||
AdnlMessageReinit(td::int32 date) : date_(date) {
|
||||
}
|
||||
auto date() const {
|
||||
return date_;
|
||||
}
|
||||
td::uint32 size() const {
|
||||
return 8;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
return create_tl_object<ton_api::adnl_message_reinit>(date_);
|
||||
}
|
||||
|
||||
private:
|
||||
td::int32 date_;
|
||||
};
|
||||
|
||||
class AdnlMessageQuery {
|
||||
public:
|
||||
AdnlMessageQuery(AdnlQueryId query_id, td::BufferSlice data) : query_id_(query_id), data_(std::move(data)) {
|
||||
}
|
||||
const auto &query_id() const {
|
||||
return query_id_;
|
||||
}
|
||||
auto data() const {
|
||||
return data_.clone();
|
||||
}
|
||||
td::uint32 size() const {
|
||||
return static_cast<td::uint32>(data_.size()) + 44;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
return create_tl_object<ton_api::adnl_message_query>(query_id_, data_.clone());
|
||||
}
|
||||
|
||||
private:
|
||||
AdnlQueryId query_id_;
|
||||
td::BufferSlice data_;
|
||||
};
|
||||
|
||||
class AdnlMessageAnswer {
|
||||
public:
|
||||
AdnlMessageAnswer(AdnlQueryId query_id, td::BufferSlice data) : query_id_(query_id), data_(std::move(data)) {
|
||||
}
|
||||
const auto &query_id() const {
|
||||
return query_id_;
|
||||
}
|
||||
auto data() const {
|
||||
return data_.clone();
|
||||
}
|
||||
td::uint32 size() const {
|
||||
return static_cast<td::uint32>(data_.size()) + 44;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
return create_tl_object<ton_api::adnl_message_answer>(query_id_, data_.clone());
|
||||
}
|
||||
|
||||
private:
|
||||
AdnlQueryId query_id_;
|
||||
td::BufferSlice data_;
|
||||
};
|
||||
|
||||
class AdnlMessagePart {
|
||||
public:
|
||||
AdnlMessagePart(td::Bits256 hash, td::uint32 total_size, td::uint32 offset, td::BufferSlice data)
|
||||
: hash_(hash), total_size_(total_size), offset_(offset), data_(std::move(data)) {
|
||||
}
|
||||
const auto &hash() const {
|
||||
return hash_;
|
||||
}
|
||||
auto offset() const {
|
||||
return offset_;
|
||||
}
|
||||
auto total_size() const {
|
||||
return total_size_;
|
||||
}
|
||||
auto data() const {
|
||||
return data_.clone();
|
||||
}
|
||||
td::uint32 size() const {
|
||||
return static_cast<td::uint32>(data_.size()) + 48;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
return create_tl_object<ton_api::adnl_message_part>(hash_, total_size_, offset_, data_.clone());
|
||||
}
|
||||
|
||||
private:
|
||||
td::Bits256 hash_;
|
||||
td::uint32 total_size_;
|
||||
td::uint32 offset_;
|
||||
td::BufferSlice data_;
|
||||
};
|
||||
|
||||
} // namespace adnlmessage
|
||||
|
||||
class AdnlMessage {
|
||||
public:
|
||||
class Empty {
|
||||
public:
|
||||
Empty() {
|
||||
}
|
||||
td::uint32 size() const {
|
||||
UNREACHABLE();
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
UNREACHABLE();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
td::Variant<Empty, adnlmessage::AdnlMessageCreateChannel, adnlmessage::AdnlMessageConfirmChannel,
|
||||
adnlmessage::AdnlMessageCustom, adnlmessage::AdnlMessageNop, adnlmessage::AdnlMessageReinit,
|
||||
adnlmessage::AdnlMessageQuery, adnlmessage::AdnlMessageAnswer, adnlmessage::AdnlMessagePart>
|
||||
message_{Empty{}};
|
||||
|
||||
public:
|
||||
explicit AdnlMessage(tl_object_ptr<ton_api::adnl_Message> message);
|
||||
template <class T>
|
||||
AdnlMessage(T m) : message_(std::move(m)) {
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::adnl_Message> tl() const {
|
||||
tl_object_ptr<ton_api::adnl_Message> res;
|
||||
message_.visit([&](const auto &obj) { res = obj.tl(); });
|
||||
return res;
|
||||
}
|
||||
td::uint32 size() const {
|
||||
td::uint32 res;
|
||||
message_.visit([&](const auto &obj) { res = obj.size(); });
|
||||
return res;
|
||||
}
|
||||
template <class F>
|
||||
void visit(F &&f) {
|
||||
message_.visit(std::move(f));
|
||||
}
|
||||
template <class F>
|
||||
void visit(F &&f) const {
|
||||
message_.visit(std::move(f));
|
||||
}
|
||||
};
|
||||
|
||||
class AdnlMessageList {
|
||||
public:
|
||||
AdnlMessageList() {
|
||||
}
|
||||
AdnlMessageList(tl_object_ptr<ton_api::adnl_Message> message) {
|
||||
auto msg = AdnlMessage{std::move(message)};
|
||||
messages_.emplace_back(std::move(msg));
|
||||
}
|
||||
AdnlMessageList(std::vector<tl_object_ptr<ton_api::adnl_Message>> messages) {
|
||||
for (auto &message : messages) {
|
||||
messages_.push_back(AdnlMessage{std::move(message)});
|
||||
}
|
||||
}
|
||||
void push_back(AdnlMessage message) {
|
||||
messages_.push_back(std::move(message));
|
||||
}
|
||||
|
||||
td::uint32 size() const {
|
||||
return static_cast<td::uint32>(messages_.size());
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Message> one_message() const {
|
||||
CHECK(size() == 1);
|
||||
return messages_[0].tl();
|
||||
}
|
||||
std::vector<tl_object_ptr<ton_api::adnl_Message>> mult_messages() const {
|
||||
std::vector<tl_object_ptr<ton_api::adnl_Message>> vec;
|
||||
for (auto &m : messages_) {
|
||||
vec.emplace_back(m.tl());
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
static std::vector<tl_object_ptr<ton_api::adnl_Message>> empty_vector() {
|
||||
return std::vector<tl_object_ptr<ton_api::adnl_Message>>{};
|
||||
}
|
||||
auto &vector() {
|
||||
return messages_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<AdnlMessage> messages_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
114
adnl/adnl-network-manager.cpp
Normal file
114
adnl/adnl-network-manager.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-network-manager.hpp"
|
||||
#include "adnl-peer-table.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
td::actor::ActorOwn<AdnlNetworkManager> AdnlNetworkManager::create(td::uint16 port) {
|
||||
return td::actor::create_actor<AdnlNetworkManagerImpl>("NetworkManager", port);
|
||||
}
|
||||
|
||||
void AdnlNetworkManagerImpl::add_listening_udp_port(td::uint16 port) {
|
||||
class Callback : public td::UdpServer::Callback {
|
||||
public:
|
||||
Callback(td::actor::ActorShared<AdnlNetworkManagerImpl> manager) : manager_(std::move(manager)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorShared<AdnlNetworkManagerImpl> manager_;
|
||||
void on_udp_message(td::UdpMessage udp_message) override {
|
||||
td::actor::send_closure_later(manager_, &AdnlNetworkManagerImpl::receive_udp_message, std::move(udp_message));
|
||||
}
|
||||
};
|
||||
|
||||
auto X = td::UdpServer::create("udp server", port, std::make_unique<Callback>(actor_shared(this)));
|
||||
X.ensure();
|
||||
udp_servers_.emplace(port, X.move_as_ok());
|
||||
}
|
||||
|
||||
void AdnlNetworkManagerImpl::receive_udp_message(td::UdpMessage message) {
|
||||
if (!callback_) {
|
||||
LOG(ERROR) << this << ": dropping IN message [?->?]: peer table unitialized";
|
||||
return;
|
||||
}
|
||||
if (message.error.is_error()) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping ERROR message: " << message.error;
|
||||
return;
|
||||
}
|
||||
if (message.data.size() >= get_mtu()) {
|
||||
VLOG(ADNL_NOTICE) << this << ": received huge packet of size " << message.data.size();
|
||||
}
|
||||
received_messages_++;
|
||||
if (received_messages_ % 64 == 0) {
|
||||
VLOG(ADNL_DEBUG) << this << ": received " << received_messages_ << "udp messages";
|
||||
}
|
||||
|
||||
VLOG(ADNL_EXTRA_DEBUG) << this << ": received message of size " << message.data.size();
|
||||
callback_->receive_packet(message.address, std::move(message.data));
|
||||
}
|
||||
|
||||
void AdnlNetworkManagerImpl::send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
|
||||
td::uint32 priority, td::BufferSlice data) {
|
||||
auto randseed = 1; // use DST?
|
||||
while (priority > 0) {
|
||||
if (out_desc_[priority].size() > 0) {
|
||||
break;
|
||||
}
|
||||
priority--;
|
||||
}
|
||||
if (out_desc_[priority].size() == 0) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << src_id << "->" << dst_id << "]: no out desc";
|
||||
return;
|
||||
}
|
||||
|
||||
auto &dv = out_desc_[priority];
|
||||
auto &v = dv[randseed % dv.size()];
|
||||
|
||||
if (!v.is_proxy()) {
|
||||
auto it = udp_servers_.find(static_cast<td::uint16>(v.addr.get_port()));
|
||||
CHECK(it != udp_servers_.end());
|
||||
|
||||
td::UdpMessage M;
|
||||
M.address = dst_addr;
|
||||
M.data = std::move(data);
|
||||
|
||||
CHECK(M.data.size() <= get_mtu());
|
||||
|
||||
td::actor::send_closure(it->second, &td::UdpServer::send, std::move(M));
|
||||
} else {
|
||||
auto it = udp_servers_.find(out_udp_port_);
|
||||
CHECK(it != udp_servers_.end());
|
||||
|
||||
auto enc = v.proxy->encrypt(
|
||||
AdnlProxy::Packet{dst_addr.get_ipv4(), static_cast<td::uint16>(dst_addr.get_port()), std::move(data)});
|
||||
|
||||
td::UdpMessage M;
|
||||
M.address = v.addr;
|
||||
M.data = std::move(enc);
|
||||
|
||||
td::actor::send_closure(it->second, &td::UdpServer::send, std::move(M));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
107
adnl/adnl-network-manager.h
Normal file
107
adnl/adnl-network-manager.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
|
||||
#include "adnl-node-id.hpp"
|
||||
#include "adnl-proxy-types.h"
|
||||
|
||||
namespace td {
|
||||
class UdpServer;
|
||||
}
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlPeerTable;
|
||||
|
||||
class AdnlNetworkConnection : public td::actor::Actor {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
virtual void on_change_state(bool ready) = 0;
|
||||
virtual ~Callback() = default;
|
||||
};
|
||||
virtual void send(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::uint32 priority, td::BufferSlice message) = 0;
|
||||
virtual bool is_alive() const = 0;
|
||||
virtual bool is_active() const = 0;
|
||||
virtual ~AdnlNetworkConnection() = default;
|
||||
};
|
||||
|
||||
class AdnlNetworkManager : public td::actor::Actor {
|
||||
public:
|
||||
//using ConnHandle = td::uint64;
|
||||
class Callback {
|
||||
public:
|
||||
virtual ~Callback() = default;
|
||||
//virtual void receive_packet(td::IPAddress addr, ConnHandle conn_handle, td::BufferSlice data) = 0;
|
||||
virtual void receive_packet(td::IPAddress addr, td::BufferSlice data) = 0;
|
||||
};
|
||||
static td::actor::ActorOwn<AdnlNetworkManager> create(td::uint16 out_port);
|
||||
|
||||
virtual ~AdnlNetworkManager() = default;
|
||||
|
||||
virtual void install_callback(std::unique_ptr<Callback> callback) = 0;
|
||||
|
||||
virtual void add_self_addr(td::IPAddress addr, td::uint32 priority) = 0;
|
||||
virtual void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) = 0;
|
||||
virtual void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
|
||||
td::uint32 priority, td::BufferSlice data) = 0;
|
||||
//virtual void send_tcp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
|
||||
// td::uint32 priority, td::BufferSlice data) = 0;
|
||||
//virtual void send_answer_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
|
||||
// ConnHandle conn_handle, td::uint32 priority, td::BufferSlice data) = 0;
|
||||
|
||||
static constexpr td::uint32 get_mtu() {
|
||||
return 1440;
|
||||
}
|
||||
|
||||
struct PrintId {};
|
||||
PrintId print_id() const {
|
||||
return PrintId{};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManager::PrintId &id) {
|
||||
sb << "[networkmanager]";
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManager &manager) {
|
||||
sb << manager.print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManager *manager) {
|
||||
sb << manager->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
121
adnl/adnl-network-manager.hpp
Normal file
121
adnl/adnl-network-manager.hpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/BufferedUdp.h"
|
||||
#include "td/net/UdpServer.h"
|
||||
#include "td/net/TcpListener.h"
|
||||
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "adnl-network-manager.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace td {
|
||||
class UdpServer;
|
||||
}
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlPeerTable;
|
||||
|
||||
class AdnlNetworkManagerImpl : public AdnlNetworkManager {
|
||||
public:
|
||||
struct OutDesc {
|
||||
td::IPAddress addr;
|
||||
std::shared_ptr<AdnlProxy> proxy;
|
||||
|
||||
bool is_proxy() const {
|
||||
return proxy != nullptr;
|
||||
}
|
||||
bool operator==(const OutDesc &with) const {
|
||||
return addr == with.addr && is_proxy() == with.is_proxy();
|
||||
}
|
||||
};
|
||||
|
||||
AdnlNetworkManagerImpl(td::uint16 out_udp_port) : out_udp_port_(out_udp_port) {
|
||||
}
|
||||
|
||||
void install_callback(std::unique_ptr<Callback> callback) override {
|
||||
callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
void add_self_addr(td::IPAddress addr, td::uint32 priority) override {
|
||||
auto x = OutDesc{addr, nullptr};
|
||||
auto &v = out_desc_[priority];
|
||||
for (auto &y : v) {
|
||||
if (x == y) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
out_desc_[priority].push_back(std::move(x));
|
||||
add_listening_udp_port(static_cast<td::uint16>(addr.get_port()));
|
||||
}
|
||||
void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) override {
|
||||
auto x = OutDesc{addr, std::move(proxy)};
|
||||
auto &v = out_desc_[priority];
|
||||
for (auto &y : v) {
|
||||
if (x == y) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
out_desc_[priority].push_back(std::move(x));
|
||||
if (!udp_servers_.count(out_udp_port_)) {
|
||||
add_listening_udp_port(out_udp_port_);
|
||||
}
|
||||
}
|
||||
void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::uint32 priority,
|
||||
td::BufferSlice data) override;
|
||||
|
||||
void add_listening_udp_port(td::uint16 port);
|
||||
void receive_udp_message(td::UdpMessage message);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Callback> callback_;
|
||||
|
||||
std::map<td::uint32, std::vector<OutDesc>> out_desc_;
|
||||
|
||||
td::uint64 received_messages_ = 0;
|
||||
td::uint64 sent_messages_ = 0;
|
||||
|
||||
std::map<td::uint16, td::actor::ActorOwn<td::UdpServer>> udp_servers_;
|
||||
|
||||
td::uint16 out_udp_port_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManagerImpl &manager) {
|
||||
sb << manager.print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlNetworkManagerImpl *manager) {
|
||||
sb << manager->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
130
adnl/adnl-node-id.hpp
Normal file
130
adnl/adnl-node-id.hpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "keys/keys.hpp"
|
||||
#include "common/io.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlNodeIdShort {
|
||||
public:
|
||||
explicit AdnlNodeIdShort(const PublicKeyHash &hash) : hash_(hash) {
|
||||
}
|
||||
explicit AdnlNodeIdShort(PublicKeyHash &&hash) : hash_(std::move(hash)) {
|
||||
}
|
||||
AdnlNodeIdShort() {
|
||||
}
|
||||
explicit AdnlNodeIdShort(td::Slice data) : hash_(data) {
|
||||
}
|
||||
explicit AdnlNodeIdShort(td::Bits256 value) : hash_(value) {
|
||||
}
|
||||
explicit AdnlNodeIdShort(tl_object_ptr<ton_api::adnl_id_short> obj) : hash_(obj->id_) {
|
||||
}
|
||||
|
||||
const auto &pubkey_hash() const {
|
||||
return hash_;
|
||||
}
|
||||
|
||||
bool operator==(const AdnlNodeIdShort &with) const {
|
||||
return hash_ == with.hash_;
|
||||
}
|
||||
bool operator!=(const AdnlNodeIdShort &with) const {
|
||||
return hash_ != with.hash_;
|
||||
}
|
||||
bool operator<(const AdnlNodeIdShort &with) const {
|
||||
return hash_ < with.hash_;
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_id_short> tl() const {
|
||||
return create_tl_object<ton_api::adnl_id_short>(hash_.tl());
|
||||
}
|
||||
auto as_slice() {
|
||||
return hash_.as_slice();
|
||||
}
|
||||
auto as_slice() const {
|
||||
return hash_.as_slice();
|
||||
}
|
||||
auto uint256_value() const {
|
||||
return hash_.uint256_value();
|
||||
}
|
||||
auto bits256_value() const {
|
||||
return hash_.bits256_value();
|
||||
}
|
||||
static AdnlNodeIdShort zero() {
|
||||
return AdnlNodeIdShort{PublicKeyHash::zero()};
|
||||
}
|
||||
bool is_zero() const {
|
||||
return hash_.is_zero();
|
||||
}
|
||||
|
||||
private:
|
||||
PublicKeyHash hash_;
|
||||
};
|
||||
|
||||
class AdnlNodeIdFull {
|
||||
private:
|
||||
explicit AdnlNodeIdFull(const tl_object_ptr<ton_api::PublicKey> &pub) : pub_(pub) {
|
||||
}
|
||||
|
||||
public:
|
||||
explicit AdnlNodeIdFull(const PublicKey &pub) : pub_(pub) {
|
||||
}
|
||||
explicit AdnlNodeIdFull(PublicKey &&pub) : pub_(std::move(pub)) {
|
||||
}
|
||||
static td::Result<AdnlNodeIdFull> create(const tl_object_ptr<ton_api::PublicKey> &pub) {
|
||||
return AdnlNodeIdFull{pub};
|
||||
}
|
||||
AdnlNodeIdFull() {
|
||||
}
|
||||
const auto &pubkey() const {
|
||||
return pub_;
|
||||
}
|
||||
bool empty() const {
|
||||
return pub_.empty();
|
||||
}
|
||||
bool operator==(const AdnlNodeIdFull &with) const {
|
||||
return pub_ == with.pub_;
|
||||
}
|
||||
bool operator!=(const AdnlNodeIdFull &with) const {
|
||||
return pub_ != with.pub_;
|
||||
}
|
||||
auto tl() const {
|
||||
return pub_.tl();
|
||||
}
|
||||
AdnlNodeIdShort compute_short_id() const {
|
||||
return AdnlNodeIdShort{pub_.compute_short_id()};
|
||||
}
|
||||
|
||||
private:
|
||||
PublicKey pub_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline StringBuilder &operator<<(StringBuilder &stream, const ton::adnl::AdnlNodeIdShort &value) {
|
||||
return stream << value.bits256_value();
|
||||
}
|
||||
|
||||
} // namespace td
|
50
adnl/adnl-node.cpp
Normal file
50
adnl/adnl-node.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-node.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
td::Result<AdnlNode> AdnlNode::create(const tl_object_ptr<ton_api::adnl_node> &obj) {
|
||||
TRY_RESULT(id, AdnlNodeIdFull::create(obj->id_));
|
||||
TRY_RESULT(addr_list, AdnlAddressList::create(std::move(obj->addr_list_)));
|
||||
return AdnlNode{std::move(id), std::move(addr_list)};
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::adnl_nodes> AdnlNodesList::tl() const {
|
||||
std::vector<tl_object_ptr<ton_api::adnl_node>> vec;
|
||||
for (auto &node : nodes_) {
|
||||
vec.emplace_back(node.tl());
|
||||
}
|
||||
return create_tl_object<ton_api::adnl_nodes>(std::move(vec));
|
||||
}
|
||||
|
||||
td::Result<AdnlNodesList> AdnlNodesList::create(const tl_object_ptr<ton_api::adnl_nodes> &nodes) {
|
||||
AdnlNodesList res{};
|
||||
for (auto &node : nodes->nodes_) {
|
||||
TRY_RESULT(N, AdnlNode::create(node));
|
||||
res.push(std::move(N));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
74
adnl/adnl-node.h
Normal file
74
adnl/adnl-node.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "adnl-node-id.hpp"
|
||||
#include "adnl-address-list.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlNode {
|
||||
private:
|
||||
AdnlNodeIdFull pub_;
|
||||
AdnlAddressList addr_list_;
|
||||
|
||||
public:
|
||||
AdnlNode(AdnlNodeIdFull pub, AdnlAddressList addr_list) : pub_(std::move(pub)), addr_list_(std::move(addr_list)) {
|
||||
}
|
||||
AdnlNode(const AdnlNode& from) : pub_(from.pub_), addr_list_(from.addr_list_) {
|
||||
}
|
||||
static td::Result<AdnlNode> create(const tl_object_ptr<ton_api::adnl_node>& obj);
|
||||
|
||||
tl_object_ptr<ton_api::adnl_node> tl() const {
|
||||
return create_tl_object<ton_api::adnl_node>(pub_.tl(), addr_list_.tl());
|
||||
}
|
||||
AdnlNodeIdFull pub_id() const {
|
||||
return pub_;
|
||||
}
|
||||
AdnlNodeIdShort compute_short_id() const {
|
||||
return pub_.compute_short_id();
|
||||
}
|
||||
const AdnlAddressList& addr_list() const {
|
||||
return addr_list_;
|
||||
}
|
||||
};
|
||||
|
||||
class AdnlNodesList {
|
||||
private:
|
||||
std::vector<AdnlNode> nodes_;
|
||||
|
||||
public:
|
||||
const auto& nodes() const {
|
||||
return nodes_;
|
||||
}
|
||||
AdnlNodesList() {
|
||||
}
|
||||
void push(AdnlNode node) {
|
||||
nodes_.push_back(std::move(node));
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_nodes> tl() const;
|
||||
static td::Result<AdnlNodesList> create(const tl_object_ptr<ton_api::adnl_nodes>& nodes);
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
135
adnl/adnl-packet.cpp
Normal file
135
adnl/adnl-packet.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-packet.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
/*adnl.packetContents rand1:bytes flags:# from:flags.0?PublicKey from_short:flags.1?adnl.id.short
|
||||
message:flags.2?adnl.Message messages:flags.3?(vector adnl.Message)
|
||||
address:flags.6?adnl.addressList seqno:flags.8?long recv_addr_list_version:flags.9?int
|
||||
confirm_seqno:flags.10?long reinit_date:flags.11?int dst_reinit_date:flags.11?int
|
||||
signature:flags.7?bytes rand2:bytes = adnl.PacketContents;*/
|
||||
|
||||
td::Result<AdnlPacket> AdnlPacket::create(tl_object_ptr<ton_api::adnl_packetContents> packet) {
|
||||
AdnlPacket R;
|
||||
R.rand1_ = std::move(packet->rand1_);
|
||||
R.flags_ = packet->flags_;
|
||||
if (R.flags_ & Flags::f_from) {
|
||||
TRY_RESULT(F, AdnlNodeIdFull::create(packet->from_));
|
||||
R.from_ = std::move(F);
|
||||
}
|
||||
if (R.flags_ & Flags::f_from_short) {
|
||||
R.from_short_ = AdnlNodeIdShort{packet->from_short_->id_};
|
||||
} else if (packet->flags_ & Flags::f_from) {
|
||||
R.from_short_ = R.from_.compute_short_id();
|
||||
}
|
||||
if (R.flags_ & Flags::f_one_message) {
|
||||
R.messages_ = AdnlMessageList{std::move(packet->message_)};
|
||||
}
|
||||
if (R.flags_ & Flags::f_mult_messages) {
|
||||
// may override messages_ if (flags & 0x4)
|
||||
// but this message will fail in run_basic_checks()
|
||||
// so it doesn't matter
|
||||
R.messages_ = AdnlMessageList{std::move(packet->messages_)};
|
||||
}
|
||||
if (R.flags_ & Flags::f_address) {
|
||||
TRY_RESULT(addr_list, AdnlAddressList::create(std::move(packet->address_)));
|
||||
R.addr_ = std::move(addr_list);
|
||||
}
|
||||
if (R.flags_ & Flags::f_priority_address) {
|
||||
TRY_RESULT(addr_list, AdnlAddressList::create(std::move(packet->address_)));
|
||||
R.priority_addr_ = std::move(addr_list);
|
||||
}
|
||||
if (R.flags_ & Flags::f_seqno) {
|
||||
R.seqno_ = packet->seqno_;
|
||||
}
|
||||
if (R.flags_ & Flags::f_confirm_seqno) {
|
||||
R.confirm_seqno_ = packet->confirm_seqno_;
|
||||
}
|
||||
if (R.flags_ & Flags::f_recv_addr_version) {
|
||||
R.recv_addr_list_version_ = packet->recv_addr_list_version_;
|
||||
}
|
||||
if (R.flags_ & Flags::f_recv_priority_addr_version) {
|
||||
R.recv_priority_addr_list_version_ = packet->recv_priority_addr_list_version_;
|
||||
}
|
||||
if (R.flags_ & Flags::f_reinit_date) {
|
||||
R.reinit_date_ = packet->reinit_date_;
|
||||
R.dst_reinit_date_ = packet->dst_reinit_date_;
|
||||
}
|
||||
if (R.flags_ & Flags::f_signature) {
|
||||
R.signature_ = std::move(packet->signature_);
|
||||
}
|
||||
R.rand2_ = std::move(packet->rand2_);
|
||||
|
||||
TRY_STATUS(R.run_basic_checks());
|
||||
return std::move(R);
|
||||
}
|
||||
|
||||
td::Status AdnlPacket::run_basic_checks() const {
|
||||
if ((flags_ & Flags::f_all) != flags_) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad flags");
|
||||
}
|
||||
if ((flags_ & Flags::f_one_message) && (flags_ & Flags::f_mult_messages)) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "both flags 0x4 and 0x8 set");
|
||||
}
|
||||
if ((flags_ & Flags::f_from) && (flags_ & Flags::f_from_short) && from_.compute_short_id() != from_short_) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "source and short source mismatch");
|
||||
}
|
||||
if ((flags_ & Flags::f_address) && addr_.empty()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad addr list");
|
||||
}
|
||||
if ((flags_ & Flags::f_priority_address) && priority_addr_.empty()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad addr list");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::adnl_packetContents> AdnlPacket::tl() const {
|
||||
return create_tl_object<ton_api::adnl_packetContents>(
|
||||
rand1_.clone(), flags_ & ~Flags::f_priority, (flags_ & Flags::f_from) ? from_.tl() : nullptr,
|
||||
(flags_ & Flags::f_from_short) ? from_short_.tl() : nullptr,
|
||||
(flags_ & Flags::f_one_message) ? messages_.one_message() : nullptr,
|
||||
(flags_ & Flags::f_mult_messages) ? messages_.mult_messages() : messages_.empty_vector(),
|
||||
(flags_ & Flags::f_address) ? addr_.tl() : nullptr,
|
||||
(flags_ & Flags::f_priority_address) ? priority_addr_.tl() : nullptr, seqno_, confirm_seqno_,
|
||||
recv_addr_list_version_, recv_priority_addr_list_version_, reinit_date_, dst_reinit_date_, signature_.clone(),
|
||||
rand2_.clone());
|
||||
}
|
||||
|
||||
td::BufferSlice AdnlPacket::to_sign() const {
|
||||
auto obj = tl();
|
||||
obj->signature_.clear();
|
||||
obj->flags_ &= ~Flags::f_signature;
|
||||
CHECK(obj->signature_.size() == 0);
|
||||
return serialize_tl_object(obj, true);
|
||||
}
|
||||
|
||||
void AdnlPacket::init_random() {
|
||||
rand1_ = td::BufferSlice{(td::Random::fast_uint32() & 1) ? 7u : 15u};
|
||||
rand2_ = td::BufferSlice{(td::Random::fast_uint32() & 1) ? 7u : 15u};
|
||||
td::Random::secure_bytes(rand1_.as_slice());
|
||||
td::Random::secure_bytes(rand2_.as_slice());
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
211
adnl/adnl-packet.h
Normal file
211
adnl/adnl-packet.h
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl/adnl.h"
|
||||
#include "adnl/adnl-message.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
/*
|
||||
from:flags.0?PublicKey
|
||||
from_short:flags.1?adnl.id.short
|
||||
message:flags.2?adnl.Message
|
||||
messages:flags.3?(vector adnl.Message)
|
||||
address:flags.4?adnl.addressList
|
||||
priority_address:flags.5?adnl.addressList
|
||||
seqno:flags.6?long
|
||||
confirm_seqno:flags.7?long
|
||||
recv_addr_list_version:flags.8?int
|
||||
recv_priority_addr_list_version:flags.9?int
|
||||
reinit_date:flags.10?int
|
||||
dst_reinit_date:flags.10?int
|
||||
signature:flags.11?bytes
|
||||
*/
|
||||
|
||||
// total packet length:
|
||||
// for full packet:
|
||||
// 32 (dst) + 64 (encryption overhead) + 4 (magic) + 36 (pubkey) + 4 + M (sum of messages) +
|
||||
// + A1 + A2 + 8 + 8 + 4 + 4 + 4 + 4 + 68 (signature) + 16 (r1) + 16 (r2) =
|
||||
// = 272 + M + A1 + A2
|
||||
// for channel:
|
||||
// 32 (channel id) + 32 (encryption overhead) + 4 (magic) + 4 + M (sum of messages) +
|
||||
// + A1 + A2 + 8 + 8 + 4 + 4 + 16(r1) + 16(r2) = 128 + M + A1 + A2
|
||||
|
||||
class AdnlPacket {
|
||||
private:
|
||||
enum Flags : td::uint32 {
|
||||
f_from = 0x1,
|
||||
f_from_short = 0x2,
|
||||
f_one_message = 0x4,
|
||||
f_mult_messages = 0x8,
|
||||
f_address = 0x10,
|
||||
f_priority_address = 0x20,
|
||||
f_seqno = 0x40,
|
||||
f_confirm_seqno = 0x80,
|
||||
f_recv_addr_version = 0x100,
|
||||
f_recv_priority_addr_version = 0x200,
|
||||
f_reinit_date = 0x400,
|
||||
f_signature = 0x800,
|
||||
f_priority = 0x1000,
|
||||
f_all = 0x1fff
|
||||
};
|
||||
|
||||
public:
|
||||
AdnlPacket() {
|
||||
}
|
||||
static td::Result<AdnlPacket> create(tl_object_ptr<ton_api::adnl_packetContents> packet);
|
||||
tl_object_ptr<ton_api::adnl_packetContents> tl() const;
|
||||
td::BufferSlice to_sign() const;
|
||||
|
||||
td::Status run_basic_checks() const;
|
||||
|
||||
auto flags() const {
|
||||
return flags_;
|
||||
}
|
||||
bool priority() const {
|
||||
return flags_ & f_priority;
|
||||
}
|
||||
bool inited_from_short() const {
|
||||
return flags_ & (Flags::f_from | Flags::f_from_short);
|
||||
}
|
||||
bool inited_from() const {
|
||||
return flags_ & Flags::f_from;
|
||||
}
|
||||
auto from() const {
|
||||
return from_;
|
||||
}
|
||||
auto from_short() const {
|
||||
return from_short_;
|
||||
}
|
||||
const auto &messages() const {
|
||||
return messages_;
|
||||
}
|
||||
auto &messages() {
|
||||
return messages_;
|
||||
}
|
||||
bool inited_addr_list() const {
|
||||
return flags_ & Flags::f_address;
|
||||
}
|
||||
auto addr_list() const {
|
||||
return addr_;
|
||||
}
|
||||
auto priority_addr_list() const {
|
||||
return priority_addr_;
|
||||
}
|
||||
auto seqno() const {
|
||||
return seqno_;
|
||||
}
|
||||
auto confirm_seqno() const {
|
||||
return confirm_seqno_;
|
||||
}
|
||||
auto recv_addr_list_version() const {
|
||||
return recv_addr_list_version_;
|
||||
}
|
||||
auto recv_priority_addr_list_version() const {
|
||||
return recv_priority_addr_list_version_;
|
||||
}
|
||||
auto reinit_date() const {
|
||||
return reinit_date_;
|
||||
}
|
||||
auto dst_reinit_date() const {
|
||||
return dst_reinit_date_;
|
||||
}
|
||||
auto signature() const {
|
||||
return signature_.clone();
|
||||
}
|
||||
|
||||
void init_random();
|
||||
|
||||
void set_signature(td::BufferSlice signature) {
|
||||
signature_ = std::move(signature);
|
||||
flags_ |= Flags::f_signature;
|
||||
}
|
||||
void set_source(AdnlNodeIdFull src) {
|
||||
from_ = src;
|
||||
from_short_ = src.compute_short_id();
|
||||
flags_ = (flags_ | Flags::f_from) & ~Flags::f_from_short;
|
||||
}
|
||||
void set_source(AdnlNodeIdShort src) {
|
||||
if (!(flags_ & Flags::f_from)) {
|
||||
from_short_ = src;
|
||||
flags_ |= Flags::f_from_short;
|
||||
}
|
||||
}
|
||||
void add_message(AdnlMessage message) {
|
||||
messages_.push_back(std::move(message));
|
||||
if (messages_.size() == 1) {
|
||||
flags_ = (flags_ | Flags::f_one_message) & ~Flags::f_mult_messages;
|
||||
} else {
|
||||
flags_ = (flags_ | Flags::f_mult_messages) & ~Flags::f_one_message;
|
||||
}
|
||||
}
|
||||
void set_addr_list(AdnlAddressList addr_list) {
|
||||
addr_ = std::move(addr_list);
|
||||
flags_ |= Flags::f_address;
|
||||
}
|
||||
void set_priority_addr_list(AdnlAddressList addr_list) {
|
||||
priority_addr_ = std::move(addr_list);
|
||||
flags_ |= Flags::f_priority_address;
|
||||
}
|
||||
void set_seqno(td::uint64 seqno) {
|
||||
seqno_ = seqno;
|
||||
flags_ |= Flags::f_seqno;
|
||||
}
|
||||
void set_confirm_seqno(td::uint64 seqno) {
|
||||
confirm_seqno_ = seqno;
|
||||
flags_ |= Flags::f_confirm_seqno;
|
||||
}
|
||||
void set_received_addr_list_version(td::int32 version) {
|
||||
recv_addr_list_version_ = version;
|
||||
flags_ |= Flags::f_recv_addr_version;
|
||||
}
|
||||
void set_received_priority_addr_list_version(td::int32 version) {
|
||||
recv_priority_addr_list_version_ = version;
|
||||
flags_ |= Flags::f_recv_priority_addr_version;
|
||||
}
|
||||
void set_reinit_date(td::int32 date, td::int32 dst_reinit_date) {
|
||||
reinit_date_ = date;
|
||||
dst_reinit_date_ = dst_reinit_date;
|
||||
flags_ |= Flags::f_reinit_date;
|
||||
}
|
||||
|
||||
private:
|
||||
td::BufferSlice rand1_;
|
||||
td::uint32 flags_{0};
|
||||
AdnlNodeIdFull from_;
|
||||
AdnlNodeIdShort from_short_;
|
||||
AdnlMessageList messages_;
|
||||
AdnlAddressList addr_;
|
||||
AdnlAddressList priority_addr_;
|
||||
td::uint64 seqno_{0};
|
||||
td::uint64 confirm_seqno_{0};
|
||||
td::int32 recv_addr_list_version_{0};
|
||||
td::int32 recv_priority_addr_list_version_{0};
|
||||
td::int32 reinit_date_{0};
|
||||
td::int32 dst_reinit_date_{0};
|
||||
td::BufferSlice signature_;
|
||||
td::BufferSlice rand2_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
336
adnl/adnl-peer-table.cpp
Normal file
336
adnl/adnl-peer-table.cpp
Normal file
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-peer-table.hpp"
|
||||
#include "adnl-peer.h"
|
||||
#include "adnl-channel.h"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include "td/utils/tl_storers.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/tl_parsers.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/db/RocksDb.h"
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "adnl-query.h"
|
||||
#include "adnl-ext-client.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
td::int32 Adnl::adnl_start_time() {
|
||||
static td::int32 start_time = [] {
|
||||
auto init_start_time = static_cast<td::int32>(td::Clocks::system());
|
||||
CHECK(init_start_time > 0);
|
||||
return init_start_time;
|
||||
}();
|
||||
return start_time;
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<Adnl> Adnl::create(std::string db, td::actor::ActorId<keyring::Keyring> keyring) {
|
||||
adnl_start_time();
|
||||
return td::actor::ActorOwn<Adnl>(td::actor::create_actor<AdnlPeerTableImpl>("PeerTable", db, keyring));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::receive_packet(td::BufferSlice data) {
|
||||
if (data.size() < 32) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping IN message [?->?]: message too short: len=" << data.size();
|
||||
return;
|
||||
}
|
||||
|
||||
AdnlNodeIdShort dst{data.as_slice().truncate(32)};
|
||||
data.confirm_read(32);
|
||||
|
||||
auto it = local_ids_own_.find(dst);
|
||||
if (it != local_ids_own_.end()) {
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::receive, std::move(data));
|
||||
return;
|
||||
}
|
||||
|
||||
AdnlChannelIdShort dst_chan_id{dst.pubkey_hash()};
|
||||
auto it2 = channels_.find(dst_chan_id);
|
||||
if (it2 != channels_.end()) {
|
||||
td::actor::send_closure(it2->second, &AdnlChannel::receive, std::move(data));
|
||||
return;
|
||||
}
|
||||
|
||||
VLOG(ADNL_DEBUG) << this << ": dropping IN message [?->" << dst << "]: unknown dst " << dst
|
||||
<< " (len=" << (data.size() + 32) << ")";
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) {
|
||||
packet.run_basic_checks().ensure();
|
||||
|
||||
if (!packet.inited_from_short()) {
|
||||
VLOG(ADNL_INFO) << this << ": dropping IN message [?->" << dst << "]: destination not set";
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = peers_.find(packet.from_short());
|
||||
if (it == peers_.end()) {
|
||||
if (!packet.inited_from()) {
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping IN message [" << packet.from_short() << "->" << dst
|
||||
<< "]: unknown peer and no full src in packet";
|
||||
return;
|
||||
}
|
||||
if (network_manager_.empty()) {
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping IN message [" << packet.from_short() << "->" << dst
|
||||
<< "]: unknown peer and network manager uninitialized";
|
||||
return;
|
||||
}
|
||||
|
||||
it = peers_
|
||||
.emplace(packet.from_short(),
|
||||
AdnlPeer::create(network_manager_, actor_id(this), dht_node_, packet.from_short()))
|
||||
.first;
|
||||
CHECK(it != peers_.end());
|
||||
}
|
||||
|
||||
auto it2 = local_ids_own_.find(dst);
|
||||
if (it2 == local_ids_own_.end()) {
|
||||
VLOG(ADNL_ERROR) << this << ": dropping IN message [" << packet.from_short() << "->" << dst
|
||||
<< "]: unknown dst (but how did we decrypt message?)";
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(it->second, &AdnlPeer::receive_packet, dst, it2->second.get(), std::move(packet));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) {
|
||||
auto id_short = id.compute_short_id();
|
||||
VLOG(ADNL_DEBUG) << this << ": adding peer " << id_short << " for local id " << local_id;
|
||||
|
||||
auto it2 = local_ids_own_.find(local_id);
|
||||
CHECK(it2 != local_ids_own_.end());
|
||||
|
||||
auto it = peers_.find(id_short);
|
||||
if (it == peers_.end()) {
|
||||
it = peers_.emplace(id_short, AdnlPeer::create(network_manager_, actor_id(this), dht_node_, id_short)).first;
|
||||
CHECK(it != peers_.end());
|
||||
}
|
||||
td::actor::send_closure(it->second, &AdnlPeer::update_id, std::move(id));
|
||||
if (!addr_list.empty()) {
|
||||
td::actor::send_closure(it->second, &AdnlPeer::update_addr_list, local_id, it2->second.get(), std::move(addr_list));
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::add_static_nodes_from_config(AdnlNodesList nodes) {
|
||||
for (auto &it : nodes.nodes()) {
|
||||
add_static_node(it);
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) {
|
||||
auto it = peers_.find(dst);
|
||||
|
||||
if (it == peers_.end()) {
|
||||
it = peers_.emplace(dst, AdnlPeer::create(network_manager_, actor_id(this), dht_node_, dst)).first;
|
||||
}
|
||||
|
||||
auto it2 = local_ids_own_.find(src);
|
||||
if (it2 == local_ids_own_.end()) {
|
||||
LOG(ERROR) << this << ": dropping OUT message [" << src << "->" << dst << "]: unknown src";
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure(it->second, &AdnlPeer::send_one_message, src, it2->second.get(), std::move(message));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id,
|
||||
td::BufferSlice data) {
|
||||
if (data.size() > get_mtu()) {
|
||||
LOG(ERROR) << this << ": dropping OUT message [" << src << "->" << dst
|
||||
<< "]: message too big: size=" << data.size();
|
||||
return;
|
||||
}
|
||||
send_message_in(src, dst, adnlmessage::AdnlMessageAnswer{query_id, std::move(data)});
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name,
|
||||
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) {
|
||||
if (data.size() > huge_packet_max_size()) {
|
||||
VLOG(ADNL_WARNING) << "dropping too big packet [" << src << "->" << dst << "]: size=" << data.size();
|
||||
VLOG(ADNL_WARNING) << "DUMP: " << td::buffer_to_hex(data.as_slice().truncate(128));
|
||||
return;
|
||||
}
|
||||
auto it = peers_.find(dst);
|
||||
|
||||
if (it == peers_.end()) {
|
||||
it = peers_.emplace(dst, AdnlPeer::create(network_manager_, actor_id(this), dht_node_, dst)).first;
|
||||
}
|
||||
|
||||
auto it2 = local_ids_own_.find(src);
|
||||
if (it2 == local_ids_own_.end()) {
|
||||
LOG(ERROR) << this << ": dropping OUT message [" << src << "->" << dst << "]: unknown src";
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure(it->second, &AdnlPeer::send_query, src, it2->second.get(), name, std::move(promise), timeout,
|
||||
std::move(data));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) {
|
||||
auto a = id.compute_short_id();
|
||||
VLOG(ADNL_INFO) << "adnl: adding local id " << a;
|
||||
|
||||
auto it = local_ids_own_.find(a);
|
||||
|
||||
if (it != local_ids_own_.end()) {
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::update_address_list, std::move(addr_list));
|
||||
} else {
|
||||
local_ids_own_[a] = td::actor::create_actor<AdnlLocalId>("localid", std::move(id), std::move(addr_list),
|
||||
actor_id(this), keyring_, dht_node_);
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) {
|
||||
VLOG(ADNL_INFO) << "adnl: deleting local id " << id;
|
||||
local_ids_own_.erase(id);
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) {
|
||||
auto it = local_ids_own_.find(dst);
|
||||
LOG_CHECK(it != local_ids_own_.end()) << "dst=" << dst;
|
||||
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::subscribe, prefix, std::move(callback));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::unsubscribe(AdnlNodeIdShort dst, std::string prefix) {
|
||||
auto it = local_ids_own_.find(dst);
|
||||
|
||||
if (it != local_ids_own_.end()) {
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::unsubscribe, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::register_dht_node(td::actor::ActorId<dht::Dht> dht_node) {
|
||||
dht_node_ = dht_node;
|
||||
|
||||
for (auto it = peers_.begin(); it != peers_.end(); it++) {
|
||||
td::actor::send_closure(it->second, &AdnlPeer::update_dht_node, dht_node_);
|
||||
}
|
||||
for (auto it = local_ids_own_.begin(); it != local_ids_own_.end(); it++) {
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::update_dht_node, dht_node_);
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::register_network_manager(td::actor::ActorId<AdnlNetworkManager> network_manager) {
|
||||
network_manager_ = std::move(network_manager);
|
||||
|
||||
class Cb : public AdnlNetworkManager::Callback {
|
||||
public:
|
||||
void receive_packet(td::IPAddress addr, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &AdnlPeerTableImpl::receive_packet, std::move(data));
|
||||
}
|
||||
Cb(td::actor::ActorId<AdnlPeerTableImpl> id) : id_(id) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<AdnlPeerTableImpl> id_;
|
||||
};
|
||||
|
||||
auto cb = std::make_unique<Cb>(actor_id(this));
|
||||
td::actor::send_closure(network_manager_, &AdnlNetworkManager::install_callback, std::move(cb));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) {
|
||||
auto it = local_ids_own_.find(id);
|
||||
if (it == local_ids_own_.end()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::get_addr_list_async, std::move(promise));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) {
|
||||
auto it = local_ids_own_.find(id);
|
||||
if (it == local_ids_own_.end()) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready));
|
||||
return;
|
||||
}
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::get_self_node, std::move(promise));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) {
|
||||
auto success = channels_.emplace(id, channel).second;
|
||||
CHECK(success);
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::unregister_channel(AdnlChannelIdShort id) {
|
||||
auto erased = channels_.erase(id);
|
||||
CHECK(erased == 1);
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::start_up() {
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node,
|
||||
td::Promise<td::Unit> promise) {
|
||||
td::actor::send_closure(db_, &AdnlDb::update, local_id, peer_id, std::move(node), std::move(promise));
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::get_addr_list_from_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
|
||||
td::Promise<AdnlDbItem> promise) {
|
||||
td::actor::send_closure(db_, &AdnlDb::get, local_id, peer_id, std::move(promise));
|
||||
}
|
||||
|
||||
AdnlPeerTableImpl::AdnlPeerTableImpl(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring) {
|
||||
keyring_ = keyring;
|
||||
static_nodes_manager_ = AdnlStaticNodesManager::create();
|
||||
|
||||
db_ = AdnlDb::create(db_root + "/adnl");
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) {
|
||||
auto it = local_ids_own_.find(dst);
|
||||
if (it != local_ids_own_.end()) {
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::deliver, src, std::move(data));
|
||||
}
|
||||
}
|
||||
void AdnlPeerTableImpl::deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto it = local_ids_own_.find(dst);
|
||||
if (it != local_ids_own_.end()) {
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::deliver_query, src, std::move(data), std::move(promise));
|
||||
} else {
|
||||
LOG(WARNING) << "deliver query: unknown dst " << dst;
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot deliver: unknown DST"));
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::decrypt_message(AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto it = local_ids_own_.find(dst);
|
||||
if (it != local_ids_own_.end()) {
|
||||
td::actor::send_closure(it->second, &AdnlLocalId::decrypt_message, std::move(data), std::move(promise));
|
||||
} else {
|
||||
LOG(WARNING) << "decrypt message: unknown dst " << dst;
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot decrypt: unknown DST"));
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerTableImpl::create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports,
|
||||
td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) {
|
||||
promise.set_value(AdnlExtServerCreator::create(actor_id(this), std::move(ids), std::move(ports)));
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
124
adnl/adnl-peer-table.h
Normal file
124
adnl/adnl-peer-table.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/BufferedUdp.h"
|
||||
|
||||
#include "adnl.h"
|
||||
#include "utils.hpp"
|
||||
#include "adnl/adnl-query.h"
|
||||
#include "adnl/adnl-db.h"
|
||||
#include "common/io.hpp"
|
||||
|
||||
#include "adnl-packet.h"
|
||||
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
constexpr int VERBOSITY_NAME(ADNL_ERROR) = verbosity_WARNING;
|
||||
constexpr int VERBOSITY_NAME(ADNL_WARNING) = verbosity_INFO;
|
||||
constexpr int VERBOSITY_NAME(ADNL_NOTICE) = verbosity_DEBUG;
|
||||
constexpr int VERBOSITY_NAME(ADNL_INFO) = verbosity_DEBUG;
|
||||
constexpr int VERBOSITY_NAME(ADNL_DEBUG) = verbosity_DEBUG + 1;
|
||||
constexpr int VERBOSITY_NAME(ADNL_EXTRA_DEBUG) = verbosity_DEBUG + 10;
|
||||
|
||||
class AdnlChannelIdShortImpl {
|
||||
public:
|
||||
explicit AdnlChannelIdShortImpl(PublicKeyHash value) {
|
||||
value_ = value.bits256_value();
|
||||
}
|
||||
explicit AdnlChannelIdShortImpl(td::Bits256 value) {
|
||||
value_ = value;
|
||||
}
|
||||
AdnlChannelIdShortImpl() {
|
||||
}
|
||||
td::Bits256 bits256_value() const {
|
||||
return value_;
|
||||
}
|
||||
auto tl() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool operator<(const AdnlChannelIdShortImpl &with) const {
|
||||
return value_ < with.value_;
|
||||
}
|
||||
bool operator==(const AdnlChannelIdShortImpl &with) const {
|
||||
return value_ == with.value_;
|
||||
}
|
||||
bool operator!=(const AdnlChannelIdShortImpl &with) const {
|
||||
return value_ != with.value_;
|
||||
}
|
||||
td::Slice as_slice() const {
|
||||
return td::as_slice(value_);
|
||||
}
|
||||
|
||||
private:
|
||||
td::Bits256 value_;
|
||||
};
|
||||
|
||||
using AdnlChannelIdShort = AdnlChannelIdShortImpl;
|
||||
|
||||
class AdnlLocalId;
|
||||
class AdnlChannel;
|
||||
|
||||
class AdnlPeerTable : public Adnl {
|
||||
public:
|
||||
static constexpr double republish_addr_list_timeout() {
|
||||
return 60.0;
|
||||
}
|
||||
|
||||
virtual void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) = 0;
|
||||
|
||||
virtual void receive_packet(td::BufferSlice data) = 0;
|
||||
virtual void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket packet) = 0;
|
||||
virtual void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) = 0;
|
||||
|
||||
virtual void register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) = 0;
|
||||
virtual void unregister_channel(AdnlChannelIdShort id) = 0;
|
||||
|
||||
virtual void add_static_node(AdnlNode node) = 0;
|
||||
virtual void del_static_node(AdnlNodeIdShort id) = 0;
|
||||
virtual void get_static_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) = 0;
|
||||
|
||||
virtual void write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node,
|
||||
td::Promise<td::Unit> promise) = 0;
|
||||
virtual void get_addr_list_from_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
|
||||
td::Promise<AdnlDbItem> promise) = 0;
|
||||
|
||||
virtual void deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) = 0;
|
||||
virtual void deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void decrypt_message(AdnlNodeIdShort dst, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &stream, const ton::adnl::AdnlChannelIdShort &value) {
|
||||
return stream << value.bits256_value();
|
||||
}
|
||||
|
||||
} // namespace td
|
137
adnl/adnl-peer-table.hpp
Normal file
137
adnl/adnl-peer-table.hpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "adnl-peer-table.h"
|
||||
#include "adnl-peer.h"
|
||||
#include "keys/encryptor.h"
|
||||
//#include "adnl-decryptor.h"
|
||||
#include "adnl-local-id.h"
|
||||
#include "adnl-query.h"
|
||||
#include "utils.hpp"
|
||||
#include "adnl-static-nodes.h"
|
||||
#include "adnl-ext-server.h"
|
||||
#include "adnl-address-list.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlPeerTableImpl : public AdnlPeerTable {
|
||||
public:
|
||||
AdnlPeerTableImpl(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring);
|
||||
|
||||
void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) override;
|
||||
void add_static_nodes_from_config(AdnlNodesList nodes) override;
|
||||
|
||||
void receive_packet(td::BufferSlice data) override;
|
||||
void receive_decrypted_packet(AdnlNodeIdShort dst, AdnlPacket data) override;
|
||||
void send_message_in(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message) override;
|
||||
void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override {
|
||||
if (data.size() > huge_packet_max_size()) {
|
||||
VLOG(ADNL_WARNING) << "dropping too big packet [" << src << "->" << dst << "]: size=" << data.size();
|
||||
VLOG(ADNL_WARNING) << "DUMP: " << td::buffer_to_hex(data.as_slice().truncate(128));
|
||||
return;
|
||||
}
|
||||
send_message_in(src, dst, AdnlMessage{adnlmessage::AdnlMessageCustom{std::move(data)}});
|
||||
}
|
||||
void answer_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlQueryId query_id, td::BufferSlice data) override;
|
||||
void send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name, td::Promise<td::BufferSlice> promise,
|
||||
td::Timestamp timeout, td::BufferSlice data) override;
|
||||
void send_query_ex(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name, td::Promise<td::BufferSlice> promise,
|
||||
td::Timestamp timeout, td::BufferSlice data, td::uint64 max_answer_size) override {
|
||||
send_query(src, dst, name, std::move(promise), timeout, std::move(data));
|
||||
}
|
||||
void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) override;
|
||||
void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) override;
|
||||
void subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) override;
|
||||
void unsubscribe(AdnlNodeIdShort dst, std::string prefix) override;
|
||||
void register_dht_node(td::actor::ActorId<dht::Dht> dht_node) override;
|
||||
void register_network_manager(td::actor::ActorId<AdnlNetworkManager> network_manager) override;
|
||||
void get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) override;
|
||||
void get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) override;
|
||||
void start_up() override;
|
||||
void register_channel(AdnlChannelIdShort id, td::actor::ActorId<AdnlChannel> channel) override;
|
||||
void unregister_channel(AdnlChannelIdShort id) override;
|
||||
|
||||
void write_new_addr_list_to_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id, AdnlDbItem node,
|
||||
td::Promise<td::Unit> promise) override;
|
||||
void get_addr_list_from_db(AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id,
|
||||
td::Promise<AdnlDbItem> promise) override;
|
||||
|
||||
void add_static_node(AdnlNode node) override {
|
||||
CHECK(!static_nodes_manager_.empty());
|
||||
td::actor::send_closure(static_nodes_manager_, &AdnlStaticNodesManager::add_node, std::move(node));
|
||||
}
|
||||
void del_static_node(AdnlNodeIdShort id) override {
|
||||
td::actor::send_closure(static_nodes_manager_, &AdnlStaticNodesManager::del_node, id);
|
||||
}
|
||||
void get_static_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) override {
|
||||
td::actor::send_closure(static_nodes_manager_, &AdnlStaticNodesManager::get_node, id, std::move(promise));
|
||||
}
|
||||
void deliver(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) override;
|
||||
void deliver_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) override;
|
||||
void decrypt_message(AdnlNodeIdShort dst, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override;
|
||||
|
||||
void create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports,
|
||||
td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) override;
|
||||
|
||||
struct PrintId {};
|
||||
PrintId print_id() const {
|
||||
return PrintId{};
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager_;
|
||||
td::actor::ActorId<dht::Dht> dht_node_;
|
||||
td::actor::ActorOwn<AdnlStaticNodesManager> static_nodes_manager_;
|
||||
|
||||
void deliver_one_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, AdnlMessage message);
|
||||
|
||||
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlPeer>> peers_;
|
||||
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlLocalId>> local_ids_own_;
|
||||
std::map<AdnlChannelIdShort, td::actor::ActorId<AdnlChannel>> channels_;
|
||||
|
||||
td::actor::ActorOwn<AdnlDb> db_;
|
||||
|
||||
td::actor::ActorOwn<AdnlExtServer> ext_server_;
|
||||
|
||||
//std::map<td::uint64, td::actor::ActorId<AdnlQuery>> out_queries_;
|
||||
//td::uint64 last_query_id_ = 1;
|
||||
};
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlPeerTableImpl::PrintId &id) {
|
||||
sb << "[peertable]";
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const AdnlPeerTableImpl &manager) {
|
||||
sb << manager.print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
878
adnl/adnl-peer.cpp
Normal file
878
adnl/adnl-peer.cpp
Normal file
|
@ -0,0 +1,878 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-peer.h"
|
||||
#include "adnl-peer.hpp"
|
||||
#include "adnl-local-id.h"
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
static_assert(AdnlPeerPairImpl::get_mtu() + AdnlPeerPairImpl::packet_header_max_size() <= AdnlNetworkManager::get_mtu(),
|
||||
"wrong mtu configuration");
|
||||
|
||||
void AdnlPeerPairImpl::start_up() {
|
||||
auto P1 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<AdnlDbItem> R) {
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_db, std::move(R));
|
||||
});
|
||||
td::actor::send_closure(peer_table_, &AdnlPeerTable::get_addr_list_from_db, local_id_, peer_id_short_, std::move(P1));
|
||||
auto P2 = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<AdnlNode> R) {
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_static_nodes, std::move(R));
|
||||
});
|
||||
td::actor::send_closure(peer_table_, &AdnlPeerTable::get_static_node, peer_id_short_, std::move(P2));
|
||||
|
||||
if (!dht_node_.empty()) {
|
||||
discover();
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::alarm() {
|
||||
if (next_dht_query_at_ && next_dht_query_at_.is_in_past()) {
|
||||
next_dht_query_at_ = td::Timestamp::never();
|
||||
discover();
|
||||
}
|
||||
if (next_db_update_at_ && next_db_update_at_.is_in_past()) {
|
||||
if (received_from_db_ && received_from_static_nodes_ && !peer_id_.empty()) {
|
||||
AdnlDbItem item;
|
||||
item.id = peer_id_;
|
||||
item.addr_list = addr_list_;
|
||||
item.priority_addr_list = priority_addr_list_;
|
||||
|
||||
td::actor::send_closure(peer_table_, &AdnlPeerTable::write_new_addr_list_to_db, local_id_, peer_id_short_,
|
||||
std::move(item), [](td::Unit) {});
|
||||
}
|
||||
next_db_update_at_ = td::Timestamp::in(td::Random::fast(60.0, 120.0));
|
||||
}
|
||||
if (retry_send_at_ && retry_send_at_.is_in_past()) {
|
||||
retry_send_at_ = td::Timestamp::never();
|
||||
send_messages_in(std::move(pending_messages_), false);
|
||||
}
|
||||
alarm_timestamp().relax(next_dht_query_at_);
|
||||
alarm_timestamp().relax(next_db_update_at_);
|
||||
alarm_timestamp().relax(retry_send_at_);
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::discover() {
|
||||
CHECK(!dht_query_active_);
|
||||
CHECK(!dht_node_.empty());
|
||||
dht_query_active_ = true;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id = print_id(),
|
||||
peer_id = peer_id_short_](td::Result<dht::DhtValue> kv) {
|
||||
if (kv.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_dht,
|
||||
kv.move_as_error_prefix("failed to get from dht: "));
|
||||
return;
|
||||
}
|
||||
auto k = kv.move_as_ok();
|
||||
auto pub = AdnlNodeIdFull{k.key().public_key()};
|
||||
CHECK(pub.compute_short_id() == peer_id);
|
||||
|
||||
auto addr_list = fetch_tl_object<ton_api::adnl_addressList>(k.value().clone(), true);
|
||||
if (addr_list.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_dht,
|
||||
addr_list.move_as_error_prefix("bad dht value: "));
|
||||
return;
|
||||
}
|
||||
|
||||
auto F = AdnlAddressList::create(addr_list.move_as_ok());
|
||||
if (F.is_error()) {
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_dht, F.move_as_error_prefix("bad dht value: "));
|
||||
return;
|
||||
}
|
||||
|
||||
AdnlNode node{pub, F.move_as_ok()};
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::got_data_from_dht, std::move(node));
|
||||
});
|
||||
|
||||
td::actor::send_closure(dht_node_, &dht::Dht::get_value, dht::DhtKey{peer_id_short_.pubkey_hash(), "address", 0},
|
||||
std::move(P));
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
|
||||
auto d = Adnl::adnl_start_time();
|
||||
if (packet.dst_reinit_date() > d) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping IN message: too new our reinit date " << packet.dst_reinit_date();
|
||||
return;
|
||||
}
|
||||
if (packet.reinit_date() > td::Clocks::system() + 60) {
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping IN message: too new peer reinit date " << packet.reinit_date();
|
||||
return;
|
||||
}
|
||||
if (packet.reinit_date() > reinit_date_) {
|
||||
reinit(packet.reinit_date());
|
||||
}
|
||||
if (packet.reinit_date() > 0 && packet.reinit_date() < reinit_date_) {
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping IN message: old peer reinit date " << packet.reinit_date();
|
||||
return;
|
||||
}
|
||||
if (packet.dst_reinit_date() > 0 && packet.dst_reinit_date() < d) {
|
||||
if (!packet.addr_list().empty()) {
|
||||
update_addr_list(packet.addr_list());
|
||||
}
|
||||
if (!packet.priority_addr_list().empty()) {
|
||||
update_addr_list(packet.priority_addr_list());
|
||||
}
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping IN message old our reinit date " << packet.reinit_date() << " date=" << d;
|
||||
auto M = AdnlMessage{adnlmessage::AdnlMessageNop{}};
|
||||
send_message(std::move(M));
|
||||
return;
|
||||
}
|
||||
if (packet.seqno() > 0) {
|
||||
if (received_packet(static_cast<td::uint32>(packet.seqno()))) {
|
||||
VLOG(ADNL_INFO) << this << ": dropping IN message: old seqno: " << packet.seqno() << " (current max " << in_seqno_
|
||||
<< ")";
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (packet.confirm_seqno() > 0) {
|
||||
if (packet.confirm_seqno() > out_seqno_) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping IN message: new ack seqno: " << packet.confirm_seqno()
|
||||
<< " (current max sent " << out_seqno_ << ")";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// accepted
|
||||
// delivering
|
||||
|
||||
add_received_packet(static_cast<td::uint32>(packet.seqno()));
|
||||
|
||||
if (packet.confirm_seqno() > ack_seqno_) {
|
||||
ack_seqno_ = packet.confirm_seqno();
|
||||
}
|
||||
|
||||
if (packet.recv_addr_list_version() > peer_recv_addr_list_version_) {
|
||||
peer_recv_addr_list_version_ = packet.recv_addr_list_version();
|
||||
}
|
||||
|
||||
if (packet.recv_priority_addr_list_version() > peer_recv_priority_addr_list_version_) {
|
||||
peer_recv_priority_addr_list_version_ = packet.recv_priority_addr_list_version();
|
||||
}
|
||||
|
||||
if (!packet.addr_list().empty()) {
|
||||
update_addr_list(packet.addr_list());
|
||||
}
|
||||
if (!packet.priority_addr_list().empty()) {
|
||||
update_addr_list(packet.priority_addr_list());
|
||||
}
|
||||
|
||||
received_messages_++;
|
||||
if (received_messages_ % 64 == 0) {
|
||||
VLOG(ADNL_INFO) << this << ": received " << received_messages_ << " messages";
|
||||
}
|
||||
for (auto &M : packet.messages().vector()) {
|
||||
deliver_message(std::move(M));
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::receive_packet_from_channel(AdnlChannelIdShort id, AdnlPacket packet) {
|
||||
if (id != channel_in_id_) {
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping IN message: outdated channel id" << id;
|
||||
return;
|
||||
}
|
||||
channel_ready_ = true;
|
||||
receive_packet_checked(std::move(packet));
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::receive_packet(AdnlPacket packet) {
|
||||
packet.run_basic_checks().ensure();
|
||||
|
||||
if (!encryptor_) {
|
||||
VLOG(ADNL_NOTICE) << this << "dropping IN message: unitialized id";
|
||||
return;
|
||||
}
|
||||
|
||||
auto S = encryptor_->check_signature(packet.to_sign().as_slice(), packet.signature().as_slice());
|
||||
if (S.is_error()) {
|
||||
VLOG(ADNL_NOTICE) << this << "dropping IN message: bad signature: " << S;
|
||||
return;
|
||||
}
|
||||
|
||||
receive_packet_checked(std::move(packet));
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::deliver_message(AdnlMessage message) {
|
||||
message.visit([&](const auto &obj) { this->process_message(obj); });
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::send_messages_in(std::vector<AdnlMessage> messages, bool allow_postpone) {
|
||||
auto connR = get_conn();
|
||||
if (connR.is_error()) {
|
||||
if (!allow_postpone) {
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping OUT messages: cannot get conn: " << connR.move_as_error();
|
||||
return;
|
||||
}
|
||||
VLOG(ADNL_INFO) << this << ": delaying OUT messages: cannot get conn: " << connR.move_as_error();
|
||||
if (!retry_send_at_) {
|
||||
retry_send_at_.relax(td::Timestamp::in(10.0));
|
||||
alarm_timestamp().relax(retry_send_at_);
|
||||
}
|
||||
for (auto &m : messages) {
|
||||
pending_messages_.push_back(std::move(m));
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto conn = connR.move_as_ok();
|
||||
|
||||
size_t ptr = 0;
|
||||
bool first = true;
|
||||
do {
|
||||
size_t s = (channel_ready_ ? channel_packet_header_max_size() : packet_header_max_size());
|
||||
if (first) {
|
||||
s += 2 * addr_list_max_size();
|
||||
}
|
||||
|
||||
AdnlPacket packet;
|
||||
packet.set_seqno(++out_seqno_);
|
||||
packet.set_confirm_seqno(in_seqno_);
|
||||
|
||||
if (first) {
|
||||
if (!channel_inited_) {
|
||||
auto M = adnlmessage::AdnlMessageCreateChannel{channel_pub_, channel_pk_date_};
|
||||
s += M.size();
|
||||
packet.add_message(std::move(M));
|
||||
} else if (!channel_ready_) {
|
||||
auto M = adnlmessage::AdnlMessageConfirmChannel{channel_pub_, peer_channel_pub_, channel_pk_date_};
|
||||
s += M.size();
|
||||
packet.add_message(std::move(M));
|
||||
}
|
||||
}
|
||||
|
||||
if (!addr_list_.empty()) {
|
||||
packet.set_received_addr_list_version(addr_list_.version());
|
||||
}
|
||||
if (!priority_addr_list_.empty()) {
|
||||
packet.set_received_priority_addr_list_version(priority_addr_list_.version());
|
||||
}
|
||||
|
||||
while (ptr < messages.size()) {
|
||||
auto &M = messages[ptr];
|
||||
CHECK(M.size() <= get_mtu());
|
||||
if (s + M.size() <= AdnlNetworkManager::get_mtu()) {
|
||||
s += M.size();
|
||||
packet.add_message(std::move(M));
|
||||
ptr++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!channel_ready_) {
|
||||
packet.set_reinit_date(Adnl::adnl_start_time(), reinit_date_);
|
||||
packet.set_source(local_id_);
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
if (!channel_inited_) {
|
||||
auto M = adnlmessage::AdnlMessageCreateChannel{channel_pub_, channel_pk_date_};
|
||||
if (s + M.size() <= AdnlNetworkManager::get_mtu()) {
|
||||
s += M.size();
|
||||
packet.add_message(std::move(M));
|
||||
}
|
||||
} else if (!channel_ready_) {
|
||||
auto M = adnlmessage::AdnlMessageConfirmChannel{channel_pub_, peer_channel_pub_, channel_pk_date_};
|
||||
if (s + M.size() <= AdnlNetworkManager::get_mtu()) {
|
||||
s += M.size();
|
||||
packet.add_message(std::move(M));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packet.run_basic_checks().ensure();
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), conn, id = print_id(),
|
||||
via_channel = channel_ready_](td::Result<AdnlPacket> res) {
|
||||
if (res.is_error()) {
|
||||
LOG(ERROR) << id << ": dropping OUT message: error while creating packet: " << res.move_as_error();
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::send_packet_continue, res.move_as_ok(), conn, via_channel);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(
|
||||
local_actor_, &AdnlLocalId::update_packet, std::move(packet),
|
||||
!channel_ready_ && ack_seqno_ == 0 && in_seqno_ == 0, !channel_ready_,
|
||||
(first || s + addr_list_max_size() <= AdnlNetworkManager::get_mtu()) ? peer_recv_addr_list_version_
|
||||
: 0x7fffffff,
|
||||
(first || s + 2 * addr_list_max_size() <= AdnlNetworkManager::get_mtu()) ? peer_recv_priority_addr_list_version_
|
||||
: 0x7fffffff,
|
||||
std::move(P));
|
||||
first = false;
|
||||
} while (ptr < messages.size());
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::send_messages(std::vector<AdnlMessage> messages) {
|
||||
std::vector<AdnlMessage> new_vec;
|
||||
for (auto &M : messages) {
|
||||
if (M.size() <= get_mtu()) {
|
||||
new_vec.push_back(std::move(M));
|
||||
} else {
|
||||
auto B = serialize_tl_object(M.tl(), true);
|
||||
CHECK(B.size() <= huge_packet_max_size());
|
||||
|
||||
auto hash = sha256_bits256(B.as_slice());
|
||||
|
||||
auto size = static_cast<td::uint32>(B.size());
|
||||
td::uint32 offset = 0;
|
||||
td::uint32 part_size = Adnl::get_mtu();
|
||||
while (offset < size) {
|
||||
auto data = B.clone();
|
||||
if (data.size() > part_size) {
|
||||
data.truncate(part_size);
|
||||
}
|
||||
B.confirm_read(data.size());
|
||||
|
||||
new_vec.push_back(AdnlMessage{adnlmessage::AdnlMessagePart{hash, size, offset, std::move(data)}});
|
||||
offset += part_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
send_messages_in(std::move(new_vec), true);
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::send_packet_continue(AdnlPacket packet, td::actor::ActorId<AdnlNetworkConnection> conn,
|
||||
bool via_channel) {
|
||||
packet.run_basic_checks().ensure();
|
||||
auto B = serialize_tl_object(packet.tl(), true);
|
||||
if (via_channel) {
|
||||
if (channel_ready_) {
|
||||
td::actor::send_closure(channel_, &AdnlChannel::send_message, priority_, conn, std::move(B));
|
||||
} else {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << local_id_ << "->" << peer_id_short_
|
||||
<< "]: channel destroyed in process";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!encryptor_) {
|
||||
VLOG(ADNL_INFO) << this << ": dropping OUT message [" << local_id_ << "->" << peer_id_short_
|
||||
<< "]: empty encryptor";
|
||||
return;
|
||||
}
|
||||
|
||||
auto res = encryptor_->encrypt(B.as_slice());
|
||||
if (res.is_error()) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping OUT message [" << local_id_ << "->" << peer_id_short_
|
||||
<< "]: failed to encrypt: " << res.move_as_error();
|
||||
return;
|
||||
}
|
||||
auto X = res.move_as_ok();
|
||||
auto enc = td::BufferSlice(X.size() + 32);
|
||||
td::MutableSlice S = enc.as_slice();
|
||||
S.copy_from(peer_id_short_.as_slice());
|
||||
S.remove_prefix(32);
|
||||
S.copy_from(X.as_slice());
|
||||
|
||||
td::actor::send_closure(conn, &AdnlNetworkConnection::send, local_id_, peer_id_short_, priority_, std::move(enc));
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::send_query(std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
|
||||
td::BufferSlice data) {
|
||||
AdnlQueryId id = AdnlQuery::random_query_id();
|
||||
CHECK(out_queries_.count(id) == 0);
|
||||
|
||||
auto P = [SelfId = actor_id(this)](AdnlQueryId id) {
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::delete_query, id);
|
||||
};
|
||||
|
||||
out_queries_[id] = AdnlQuery::create(std::move(promise), std::move(P), name, timeout, id);
|
||||
|
||||
send_message(adnlmessage::AdnlMessageQuery{id, std::move(data)});
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::alarm_query(AdnlQueryId id) {
|
||||
out_queries_.erase(id);
|
||||
}
|
||||
|
||||
AdnlPeerPairImpl::AdnlPeerPairImpl(td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<AdnlLocalId> local_actor, td::actor::ActorId<AdnlPeer> peer,
|
||||
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
|
||||
AdnlNodeIdShort peer_id) {
|
||||
network_manager_ = network_manager;
|
||||
peer_table_ = peer_table;
|
||||
local_actor_ = local_actor;
|
||||
peer_ = peer;
|
||||
dht_node_ = dht_node;
|
||||
|
||||
local_id_ = local_id;
|
||||
peer_id_short_ = peer_id;
|
||||
|
||||
channel_pk_ = privkeys::Ed25519::random();
|
||||
channel_pub_ = channel_pk_.pub();
|
||||
channel_pk_date_ = static_cast<td::int32>(td::Clocks::system());
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::create_channel(pubkeys::Ed25519 pub, td::uint32 date) {
|
||||
if (channel_inited_ && peer_channel_pub_ == pub) {
|
||||
return;
|
||||
}
|
||||
if (channel_inited_ && date <= peer_channel_date_) {
|
||||
return;
|
||||
}
|
||||
if (channel_inited_) {
|
||||
td::actor::send_closure(peer_table_, &AdnlPeerTable::unregister_channel, channel_in_id_);
|
||||
channel_.reset();
|
||||
channel_inited_ = false;
|
||||
channel_ready_ = false;
|
||||
}
|
||||
CHECK(!channel_ready_);
|
||||
|
||||
peer_channel_pub_ = pub;
|
||||
peer_channel_date_ = date;
|
||||
|
||||
auto R = AdnlChannel::create(channel_pk_, peer_channel_pub_, local_id_, peer_id_short_, channel_out_id_,
|
||||
channel_in_id_, actor_id(this));
|
||||
if (R.is_ok()) {
|
||||
channel_ = R.move_as_ok();
|
||||
channel_inited_ = true;
|
||||
|
||||
td::actor::send_closure_later(peer_table_, &AdnlPeerTable::register_channel, channel_in_id_, channel_.get());
|
||||
} else {
|
||||
VLOG(ADNL_WARNING) << this << ": failed to create channel: " << R.move_as_error();
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageCreateChannel &message) {
|
||||
create_channel(message.key(), message.date());
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageConfirmChannel &message) {
|
||||
if (message.peer_key() != channel_pub_) {
|
||||
VLOG(ADNL_NOTICE) << this << ": received adnl.message.confirmChannel with bad peer_key";
|
||||
return;
|
||||
}
|
||||
create_channel(message.key(), message.date());
|
||||
if (!channel_inited_ || peer_channel_pub_ != message.key()) {
|
||||
VLOG(ADNL_NOTICE) << this << ": received adnl.message.confirmChannel with old key";
|
||||
return;
|
||||
}
|
||||
channel_ready_ = true;
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageCustom &message) {
|
||||
td::actor::send_closure(local_actor_, &AdnlLocalId::deliver, peer_id_short_, message.data());
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageNop &message) {
|
||||
// nop
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageReinit &message) {
|
||||
reinit(message.date());
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageQuery &message) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), query_id = message.query_id()](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(WARNING) << "failed to answer query: " << R.move_as_error();
|
||||
} else {
|
||||
auto data = R.move_as_ok();
|
||||
if (data.size() > Adnl::huge_packet_max_size()) {
|
||||
LOG(WARNING) << "dropping too big answer query: size=" << data.size();
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &AdnlPeerPairImpl::send_message,
|
||||
AdnlMessage{adnlmessage::AdnlMessageAnswer{query_id, std::move(data)}});
|
||||
}
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(local_actor_, &AdnlLocalId::deliver_query, peer_id_short_, message.data(), std::move(P));
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessageAnswer &message) {
|
||||
auto Q = out_queries_.find(message.query_id());
|
||||
|
||||
if (Q == out_queries_.end()) {
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping IN answer: unknown query id " << message.query_id();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.data().size() > Adnl::huge_packet_max_size()) {
|
||||
VLOG(ADNL_NOTICE) << this << ": dropping IN answer: too big answer size";
|
||||
return;
|
||||
}
|
||||
|
||||
td::actor::send_closure_later(Q->second, &AdnlQuery::result, message.data());
|
||||
out_queries_.erase(Q);
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::process_message(const adnlmessage::AdnlMessagePart &message) {
|
||||
auto size = message.total_size();
|
||||
if (size > huge_packet_max_size()) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping too big huge message: size=" << size;
|
||||
return;
|
||||
}
|
||||
if (message.hash().is_zero()) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping huge message with zero hash";
|
||||
return;
|
||||
}
|
||||
if (message.hash() != huge_message_hash_) {
|
||||
huge_message_hash_.set_zero();
|
||||
huge_message_.clear();
|
||||
huge_message_offset_ = 0;
|
||||
if (message.offset() == 0) {
|
||||
huge_message_hash_ = message.hash();
|
||||
huge_message_ = td::BufferSlice{size};
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto data = message.data();
|
||||
if (data.size() + message.offset() > size) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping huge message with bad part";
|
||||
return;
|
||||
}
|
||||
if (size != huge_message_.size()) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping huge message part with inconsistent size";
|
||||
return;
|
||||
}
|
||||
if (message.offset() == huge_message_offset_) {
|
||||
auto S = huge_message_.as_slice();
|
||||
S.remove_prefix(huge_message_offset_);
|
||||
S.copy_from(data.as_slice());
|
||||
huge_message_offset_ += static_cast<td::uint32>(data.size());
|
||||
|
||||
if (huge_message_offset_ == huge_message_.size()) {
|
||||
//td::actor::send_closure(local_actor_, &AdnlLocalId::deliver, peer_id_short_, std::move(huge_message_));
|
||||
if (sha256_bits256(huge_message_.as_slice()) != huge_message_hash_) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping huge message: hash mismatch";
|
||||
return;
|
||||
}
|
||||
huge_message_hash_.set_zero();
|
||||
huge_message_offset_ = 0;
|
||||
auto MR = fetch_tl_object<ton_api::adnl_Message>(std::move(huge_message_), true);
|
||||
if (MR.is_error()) {
|
||||
VLOG(ADNL_WARNING) << this << ": dropping huge message part with bad data";
|
||||
return;
|
||||
}
|
||||
auto M = AdnlMessage{MR.move_as_ok()};
|
||||
deliver_message(std::move(M));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::delete_query(AdnlQueryId id) {
|
||||
auto Q = out_queries_.find(id);
|
||||
|
||||
if (Q != out_queries_.end()) {
|
||||
out_queries_.erase(Q);
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::reinit(td::int32 date) {
|
||||
if (reinit_date_ == 0) {
|
||||
reinit_date_ = date;
|
||||
}
|
||||
if (reinit_date_ < date) {
|
||||
if (channel_inited_) {
|
||||
td::actor::send_closure(peer_table_, &AdnlPeerTable::unregister_channel, channel_in_id_);
|
||||
}
|
||||
|
||||
in_seqno_ = 0;
|
||||
out_seqno_ = 0;
|
||||
ack_seqno_ = 0;
|
||||
recv_seqno_mask_ = 0;
|
||||
|
||||
channel_ready_ = false;
|
||||
channel_inited_ = false;
|
||||
|
||||
peer_recv_addr_list_version_ = 0;
|
||||
|
||||
huge_message_offset_ = 0;
|
||||
huge_message_hash_.set_zero();
|
||||
huge_message_.clear();
|
||||
|
||||
channel_.release();
|
||||
|
||||
reinit_date_ = date;
|
||||
}
|
||||
}
|
||||
|
||||
td::Result<td::actor::ActorId<AdnlNetworkConnection>> AdnlPeerPairImpl::get_conn() {
|
||||
if (!priority_addr_list_.empty() && priority_addr_list_.expire_at() < td::Clocks::system()) {
|
||||
priority_addr_list_ = AdnlAddressList{};
|
||||
priority_conns_.clear();
|
||||
}
|
||||
|
||||
if (conns_.size() == 0 && priority_conns_.size() == 0) {
|
||||
return td::Status::Error(ErrorCode::notready, PSTRING()
|
||||
<< "empty network information: version=" << addr_list_.version()
|
||||
<< " reinit_date=" << addr_list_.reinit_date()
|
||||
<< " real_reinit_date=" << reinit_date_);
|
||||
}
|
||||
|
||||
for (auto &conn : priority_conns_) {
|
||||
if (conn.ready()) {
|
||||
return conn.conn.get();
|
||||
}
|
||||
}
|
||||
for (auto &conn : conns_) {
|
||||
if (conn.ready()) {
|
||||
return conn.conn.get();
|
||||
}
|
||||
}
|
||||
return td::Status::Error(ErrorCode::notready, "no active connections");
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::update_addr_list(AdnlAddressList addr_list) {
|
||||
if (addr_list.empty()) {
|
||||
return;
|
||||
}
|
||||
CHECK(addr_list.size() > 0);
|
||||
|
||||
if (addr_list.reinit_date() > td::Clocks::system() + 60) {
|
||||
VLOG(ADNL_WARNING) << "dropping addr list with too new reinit date";
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr_list.reinit_date() > reinit_date_) {
|
||||
reinit(addr_list.reinit_date());
|
||||
} else if (addr_list.reinit_date() < reinit_date_) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool priority = addr_list.priority() > 0;
|
||||
|
||||
if ((priority ? priority_addr_list_ : addr_list_).version() >= addr_list.version()) {
|
||||
if (priority && priority_addr_list_.version() == addr_list.version()) {
|
||||
auto expire_at = addr_list.expire_at();
|
||||
if (expire_at > priority_addr_list_.expire_at()) {
|
||||
priority_addr_list_.set_expire_at(expire_at);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
VLOG(ADNL_INFO) << this << ": updating addr list to version " << addr_list.version() << " size=" << addr_list.size();
|
||||
|
||||
const auto addrs = addr_list.addrs();
|
||||
std::vector<Conn> conns;
|
||||
conns.resize(std::min(addr_list.size(), 3u));
|
||||
auto &old_conns = priority ? priority_conns_ : conns_;
|
||||
|
||||
for (size_t i = 0; i < conns.size(); i++) {
|
||||
auto &addr = addrs[i];
|
||||
auto hash = addr->get_hash();
|
||||
if (i < old_conns.size() && old_conns[i].addr->get_hash() == hash) {
|
||||
conns[i] = std::move(old_conns[i]);
|
||||
} else {
|
||||
conns[i] = Conn{addr, actor_id(this), network_manager_};
|
||||
}
|
||||
}
|
||||
|
||||
old_conns = std::move(conns);
|
||||
(priority ? priority_addr_list_ : addr_list_) = addr_list;
|
||||
}
|
||||
|
||||
void AdnlPeerImpl::update_id(AdnlNodeIdFull id) {
|
||||
CHECK(id.compute_short_id() == peer_id_short_);
|
||||
if (!peer_id_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
peer_id_ = std::move(id);
|
||||
|
||||
for (auto &it : peer_pairs_) {
|
||||
td::actor::send_closure(it.second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::Conn::create_conn(td::actor::ActorId<AdnlPeerPairImpl> peer,
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager) {
|
||||
auto id = addr->get_hash();
|
||||
|
||||
conn = addr->create_connection(network_manager, std::make_unique<ConnCallback>(peer, id));
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::conn_change_state(AdnlConnectionIdShort id, bool ready) {
|
||||
if (ready) {
|
||||
if (pending_messages_.size() > 0) {
|
||||
send_messages_in(std::move(pending_messages_), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlPeerPair> AdnlPeerPair::create(td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<AdnlLocalId> local_actor,
|
||||
td::actor::ActorId<AdnlPeer> peer_actor,
|
||||
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
|
||||
AdnlNodeIdShort peer_id) {
|
||||
auto X = td::actor::create_actor<AdnlPeerPairImpl>("peerpair", network_manager, peer_table, local_actor, peer_actor,
|
||||
dht_node, local_id, peer_id);
|
||||
return td::actor::ActorOwn<AdnlPeerPair>(std::move(X));
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlPeer> AdnlPeer::create(td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort peer_id) {
|
||||
auto X = td::actor::create_actor<AdnlPeerImpl>("peer", network_manager, peer_table, dht_node, peer_id);
|
||||
return td::actor::ActorOwn<AdnlPeer>(std::move(X));
|
||||
}
|
||||
|
||||
void AdnlPeerImpl::receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket packet) {
|
||||
if (packet.inited_from()) {
|
||||
update_id(packet.from());
|
||||
}
|
||||
|
||||
auto it = peer_pairs_.find(dst);
|
||||
if (it == peer_pairs_.end()) {
|
||||
auto X =
|
||||
AdnlPeerPair::create(network_manager_, peer_table_, dst_actor, actor_id(this), dht_node_, dst, peer_id_short_);
|
||||
peer_pairs_.emplace(dst, std::move(X));
|
||||
it = peer_pairs_.find(dst);
|
||||
CHECK(it != peer_pairs_.end());
|
||||
|
||||
if (!peer_id_.empty()) {
|
||||
td::actor::send_closure(it->second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
|
||||
}
|
||||
}
|
||||
|
||||
td::actor::send_closure(it->second.get(), &AdnlPeerPair::receive_packet_checked, std::move(packet));
|
||||
}
|
||||
|
||||
void AdnlPeerImpl::send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
|
||||
std::vector<AdnlMessage> messages) {
|
||||
auto it = peer_pairs_.find(src);
|
||||
if (it == peer_pairs_.end()) {
|
||||
auto X =
|
||||
AdnlPeerPair::create(network_manager_, peer_table_, src_actor, actor_id(this), dht_node_, src, peer_id_short_);
|
||||
peer_pairs_.emplace(src, std::move(X));
|
||||
it = peer_pairs_.find(src);
|
||||
CHECK(it != peer_pairs_.end());
|
||||
|
||||
if (!peer_id_.empty()) {
|
||||
td::actor::send_closure(it->second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
|
||||
}
|
||||
}
|
||||
|
||||
td::actor::send_closure(it->second, &AdnlPeerPair::send_messages, std::move(messages));
|
||||
}
|
||||
|
||||
void AdnlPeerImpl::send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
|
||||
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) {
|
||||
auto it = peer_pairs_.find(src);
|
||||
if (it == peer_pairs_.end()) {
|
||||
auto X =
|
||||
AdnlPeerPair::create(network_manager_, peer_table_, src_actor, actor_id(this), dht_node_, src, peer_id_short_);
|
||||
peer_pairs_.emplace(src, std::move(X));
|
||||
it = peer_pairs_.find(src);
|
||||
CHECK(it != peer_pairs_.end());
|
||||
|
||||
if (!peer_id_.empty()) {
|
||||
td::actor::send_closure(it->second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
|
||||
}
|
||||
}
|
||||
|
||||
td::actor::send_closure(it->second, &AdnlPeerPair::send_query, name, std::move(promise), timeout, std::move(data));
|
||||
}
|
||||
|
||||
void AdnlPeerImpl::del_local_id(AdnlNodeIdShort local_id) {
|
||||
peer_pairs_.erase(local_id);
|
||||
}
|
||||
|
||||
void AdnlPeerImpl::update_dht_node(td::actor::ActorId<dht::Dht> dht_node) {
|
||||
dht_node_ = dht_node;
|
||||
for (auto it = peer_pairs_.begin(); it != peer_pairs_.end(); it++) {
|
||||
td::actor::send_closure(it->second, &AdnlPeerPair::update_dht_node, dht_node_);
|
||||
}
|
||||
}
|
||||
|
||||
void AdnlPeerImpl::update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
|
||||
AdnlAddressList addr_list) {
|
||||
auto it = peer_pairs_.find(local_id);
|
||||
if (it == peer_pairs_.end()) {
|
||||
auto X = AdnlPeerPair::create(network_manager_, peer_table_, local_actor, actor_id(this), dht_node_, local_id,
|
||||
peer_id_short_);
|
||||
peer_pairs_.emplace(local_id, std::move(X));
|
||||
it = peer_pairs_.find(local_id);
|
||||
CHECK(it != peer_pairs_.end());
|
||||
|
||||
if (!peer_id_.empty()) {
|
||||
td::actor::send_closure(it->second.get(), &AdnlPeerPair::update_peer_id, peer_id_);
|
||||
}
|
||||
}
|
||||
|
||||
td::actor::send_closure(it->second, &AdnlPeerPair::update_addr_list, std::move(addr_list));
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::got_data_from_db(td::Result<AdnlDbItem> R) {
|
||||
received_from_db_ = false;
|
||||
if (R.is_error()) {
|
||||
return;
|
||||
}
|
||||
auto value = R.move_as_ok();
|
||||
if (!value.id.empty()) {
|
||||
update_peer_id(value.id);
|
||||
}
|
||||
update_addr_list(value.addr_list);
|
||||
update_addr_list(value.priority_addr_list);
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::got_data_from_static_nodes(td::Result<AdnlNode> R) {
|
||||
received_from_static_nodes_ = false;
|
||||
if (R.is_error()) {
|
||||
return;
|
||||
}
|
||||
auto value = R.move_as_ok();
|
||||
if (!value.pub_id().empty()) {
|
||||
update_peer_id(value.pub_id());
|
||||
}
|
||||
update_addr_list(value.addr_list());
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::got_data_from_dht(td::Result<AdnlNode> R) {
|
||||
CHECK(dht_query_active_);
|
||||
dht_query_active_ = false;
|
||||
next_dht_query_at_ = td::Timestamp::in(td::Random::fast(60.0, 120.0));
|
||||
if (R.is_error()) {
|
||||
VLOG(ADNL_INFO) << this << ": dht query failed: " << R.move_as_error();
|
||||
return;
|
||||
}
|
||||
auto value = R.move_as_ok();
|
||||
if (!value.pub_id().empty()) {
|
||||
update_peer_id(value.pub_id());
|
||||
}
|
||||
update_addr_list(value.addr_list());
|
||||
}
|
||||
|
||||
void AdnlPeerPairImpl::update_peer_id(AdnlNodeIdFull id) {
|
||||
if (peer_id_.empty()) {
|
||||
peer_id_ = std::move(id);
|
||||
auto R = peer_id_.pubkey().create_encryptor();
|
||||
if (R.is_ok()) {
|
||||
encryptor_ = R.move_as_ok();
|
||||
} else {
|
||||
VLOG(ADNL_WARNING) << this << ": failed to create encryptor: " << R.move_as_error();
|
||||
}
|
||||
}
|
||||
CHECK(!peer_id_.empty());
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
101
adnl/adnl-peer.h
Normal file
101
adnl/adnl-peer.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/BufferedUdp.h"
|
||||
|
||||
#include "dht/dht.h"
|
||||
#include "adnl-peer-table.h"
|
||||
#include "utils.hpp"
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlPeerTable;
|
||||
class AdnlNetworkManager;
|
||||
class AdnlLocalId;
|
||||
class AdnlNetworkConnection;
|
||||
|
||||
class AdnlPeer;
|
||||
|
||||
class AdnlPeerPair : public td::actor::Actor {
|
||||
public:
|
||||
virtual void receive_packet_from_channel(AdnlChannelIdShort id, AdnlPacket packet) = 0;
|
||||
virtual void receive_packet_checked(AdnlPacket packet) = 0;
|
||||
virtual void receive_packet(AdnlPacket packet) = 0;
|
||||
|
||||
virtual void send_messages(std::vector<AdnlMessage> message) = 0;
|
||||
inline void send_message(AdnlMessage message) {
|
||||
std::vector<AdnlMessage> vec;
|
||||
vec.push_back(std::move(message));
|
||||
send_messages(std::move(vec));
|
||||
}
|
||||
static constexpr td::uint32 get_mtu() {
|
||||
return Adnl::get_mtu() + 128;
|
||||
}
|
||||
virtual void send_query(std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
|
||||
td::BufferSlice data) = 0;
|
||||
virtual void alarm_query(AdnlQueryId query_id) = 0;
|
||||
virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) = 0;
|
||||
virtual void update_peer_id(AdnlNodeIdFull id) = 0;
|
||||
virtual void update_addr_list(AdnlAddressList addr_list) = 0;
|
||||
|
||||
static td::actor::ActorOwn<AdnlPeerPair> create(td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<AdnlLocalId> local_actor,
|
||||
td::actor::ActorId<AdnlPeer> peer_actor,
|
||||
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id,
|
||||
AdnlNodeIdShort peer_id);
|
||||
};
|
||||
|
||||
class AdnlPeer : public td::actor::Actor {
|
||||
public:
|
||||
virtual void receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket message) = 0;
|
||||
virtual void send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
|
||||
std::vector<AdnlMessage> messages) = 0;
|
||||
virtual void send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
|
||||
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) = 0;
|
||||
void send_one_message(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, AdnlMessage message) {
|
||||
std::vector<AdnlMessage> vec;
|
||||
vec.push_back(std::move(message));
|
||||
send_messages(src, src_actor, std::move(vec));
|
||||
}
|
||||
|
||||
void send_message(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, td::BufferSlice data) {
|
||||
auto M = AdnlMessage{adnlmessage::AdnlMessageCustom{std::move(data)}};
|
||||
send_one_message(src, src_actor, std::move(M));
|
||||
}
|
||||
|
||||
static td::actor::ActorOwn<AdnlPeer> create(td::actor::ActorId<AdnlNetworkManager> network_manager,
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort peer_id);
|
||||
|
||||
virtual void del_local_id(AdnlNodeIdShort local_id) = 0;
|
||||
virtual void update_id(AdnlNodeIdFull id) = 0;
|
||||
virtual void update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
|
||||
AdnlAddressList addr_list) = 0;
|
||||
virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) = 0;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
318
adnl/adnl-peer.hpp
Normal file
318
adnl/adnl-peer.hpp
Normal file
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "adnl-peer.h"
|
||||
#include "adnl-peer-table.h"
|
||||
#include "adnl-network-manager.h"
|
||||
#include "keys/encryptor.h"
|
||||
#include "adnl-channel.h"
|
||||
#include "adnl-query.h"
|
||||
|
||||
#include "crypto/Ed25519.h"
|
||||
#include "td/utils/DecTree.h"
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
using AdnlConnectionIdShort = AdnlAddressImpl::Hash;
|
||||
|
||||
class AdnlPeerPairImpl : public AdnlPeerPair {
|
||||
public:
|
||||
static constexpr td::uint32 packet_header_max_size() {
|
||||
return 272;
|
||||
}
|
||||
static constexpr td::uint32 channel_packet_header_max_size() {
|
||||
return 128;
|
||||
}
|
||||
static constexpr td::uint32 addr_list_max_size() {
|
||||
return 128;
|
||||
}
|
||||
static constexpr td::uint32 get_mtu() {
|
||||
return Adnl::get_mtu() + 128;
|
||||
}
|
||||
static constexpr td::uint32 huge_packet_max_size() {
|
||||
return Adnl::huge_packet_max_size() + 128;
|
||||
}
|
||||
|
||||
AdnlPeerPairImpl(td::actor::ActorId<AdnlNetworkManager> network_manager, td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<AdnlLocalId> local_actor, td::actor::ActorId<AdnlPeer> peer,
|
||||
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort local_id, AdnlNodeIdShort peer_id);
|
||||
void start_up() override;
|
||||
void alarm() override;
|
||||
|
||||
void discover();
|
||||
|
||||
void receive_packet_from_channel(AdnlChannelIdShort id, AdnlPacket packet) override;
|
||||
void receive_packet_checked(AdnlPacket packet) override;
|
||||
void receive_packet(AdnlPacket packet) override;
|
||||
void deliver_message(AdnlMessage message);
|
||||
|
||||
void send_messages_in(std::vector<AdnlMessage> messages, bool allow_postpone);
|
||||
void send_messages(std::vector<AdnlMessage> messages) override;
|
||||
void send_packet_continue(AdnlPacket packet, td::actor::ActorId<AdnlNetworkConnection> conn, bool via_channel);
|
||||
void send_query(std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
|
||||
td::BufferSlice data) override;
|
||||
|
||||
void alarm_query(AdnlQueryId id) override;
|
||||
|
||||
void discover_query_result(td::Result<dht::DhtValue> B, bool dummy);
|
||||
|
||||
void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) override {
|
||||
dht_node_ = dht_node;
|
||||
}
|
||||
|
||||
void update_addr_list(AdnlAddressList addr_list) override;
|
||||
void update_peer_id(AdnlNodeIdFull id) override;
|
||||
|
||||
void got_data_from_db(td::Result<AdnlDbItem> R);
|
||||
void got_data_from_static_nodes(td::Result<AdnlNode> R);
|
||||
void got_data_from_dht(td::Result<AdnlNode> R);
|
||||
|
||||
//void conn_ready(AdnlConnectionIdShort id, td::Result<td::actor::ActorOwn<AdnlNetworkConnection>> R);
|
||||
|
||||
void process_message(const adnlmessage::AdnlMessageCreateChannel &message);
|
||||
void process_message(const adnlmessage::AdnlMessageConfirmChannel &message);
|
||||
void process_message(const adnlmessage::AdnlMessageCustom &message);
|
||||
void process_message(const adnlmessage::AdnlMessageNop &message);
|
||||
void process_message(const adnlmessage::AdnlMessageReinit &message);
|
||||
void process_message(const adnlmessage::AdnlMessageQuery &message);
|
||||
void process_message(const adnlmessage::AdnlMessageAnswer &message);
|
||||
void process_message(const adnlmessage::AdnlMessagePart &message);
|
||||
void process_message(const AdnlMessage::Empty &message) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void conn_change_state(AdnlConnectionIdShort conn_id, bool ready);
|
||||
|
||||
void delete_query(AdnlQueryId id);
|
||||
|
||||
struct PrintId {
|
||||
AdnlNodeIdShort peer_id;
|
||||
AdnlNodeIdShort local_id;
|
||||
};
|
||||
|
||||
PrintId print_id() const {
|
||||
return PrintId{peer_id_short_, local_id_};
|
||||
}
|
||||
|
||||
private:
|
||||
void reinit(td::int32 date);
|
||||
td::Result<td::actor::ActorId<AdnlNetworkConnection>> get_conn();
|
||||
void create_channel(pubkeys::Ed25519 pub, td::uint32 date);
|
||||
|
||||
bool received_packet(td::uint32 seqno) const {
|
||||
CHECK(seqno > 0);
|
||||
if (seqno + 64 <= in_seqno_) {
|
||||
return true;
|
||||
}
|
||||
if (seqno > in_seqno_) {
|
||||
return false;
|
||||
}
|
||||
return recv_seqno_mask_ & (1ull << (in_seqno_ - seqno));
|
||||
}
|
||||
|
||||
void add_received_packet(td::uint32 seqno) {
|
||||
CHECK(!received_packet(seqno));
|
||||
if (seqno <= in_seqno_) {
|
||||
recv_seqno_mask_ |= (1ull << (in_seqno_ - seqno));
|
||||
} else {
|
||||
auto old = in_seqno_;
|
||||
in_seqno_ = seqno;
|
||||
if (in_seqno_ - old >= 64) {
|
||||
recv_seqno_mask_ = 1;
|
||||
} else {
|
||||
recv_seqno_mask_ = recv_seqno_mask_ << (in_seqno_ - old);
|
||||
recv_seqno_mask_ |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Conn {
|
||||
class ConnCallback : public AdnlNetworkConnection::Callback {
|
||||
public:
|
||||
void on_change_state(bool ready) override {
|
||||
td::actor::send_closure(root_, &AdnlPeerPairImpl::conn_change_state, conn_id_, ready);
|
||||
}
|
||||
ConnCallback(td::actor::ActorId<AdnlPeerPairImpl> root, AdnlConnectionIdShort conn_id)
|
||||
: root_(root), conn_id_(conn_id) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<AdnlPeerPairImpl> root_;
|
||||
AdnlConnectionIdShort conn_id_;
|
||||
};
|
||||
|
||||
AdnlAddress addr;
|
||||
td::actor::ActorOwn<AdnlNetworkConnection> conn;
|
||||
|
||||
Conn(AdnlAddress addr, td::actor::ActorId<AdnlPeerPairImpl> peer,
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager)
|
||||
: addr(std::move(addr)) {
|
||||
create_conn(peer, network_manager);
|
||||
}
|
||||
Conn() {
|
||||
}
|
||||
|
||||
bool ready() {
|
||||
return !conn.empty() && conn.get_actor_unsafe().is_active();
|
||||
}
|
||||
|
||||
void create_conn(td::actor::ActorId<AdnlPeerPairImpl> peer, td::actor::ActorId<AdnlNetworkManager> network_manager);
|
||||
};
|
||||
|
||||
std::vector<AdnlMessage> pending_messages_;
|
||||
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager_;
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table_;
|
||||
td::actor::ActorId<AdnlLocalId> local_actor_;
|
||||
td::actor::ActorId<AdnlPeer> peer_;
|
||||
td::actor::ActorId<dht::Dht> dht_node_;
|
||||
|
||||
td::uint32 priority_ = 0;
|
||||
|
||||
td::int32 reinit_date_ = 0;
|
||||
|
||||
bool channel_ready_ = false;
|
||||
bool channel_inited_ = false;
|
||||
AdnlChannelIdShort channel_in_id_;
|
||||
AdnlChannelIdShort channel_out_id_;
|
||||
privkeys::Ed25519 channel_pk_;
|
||||
pubkeys::Ed25519 channel_pub_;
|
||||
td::int32 channel_pk_date_;
|
||||
td::actor::ActorOwn<AdnlChannel> channel_;
|
||||
|
||||
td::uint64 in_seqno_ = 0;
|
||||
td::uint64 out_seqno_ = 0;
|
||||
td::uint64 ack_seqno_ = 0;
|
||||
td::uint64 recv_seqno_mask_ = 0;
|
||||
|
||||
td::uint32 peer_channel_date_ = 0;
|
||||
pubkeys::Ed25519 peer_channel_pub_;
|
||||
td::int32 peer_recv_addr_list_version_ = -1;
|
||||
td::int32 peer_recv_priority_addr_list_version_ = -1;
|
||||
|
||||
td::Bits256 huge_message_hash_ = td::Bits256::zero();
|
||||
td::BufferSlice huge_message_;
|
||||
td::uint32 huge_message_offset_ = 0;
|
||||
|
||||
AdnlAddressList addr_list_;
|
||||
AdnlAddressList priority_addr_list_;
|
||||
|
||||
std::vector<Conn> conns_;
|
||||
std::vector<Conn> priority_conns_;
|
||||
|
||||
AdnlNodeIdFull peer_id_;
|
||||
AdnlNodeIdShort peer_id_short_;
|
||||
AdnlNodeIdShort local_id_;
|
||||
|
||||
std::unique_ptr<Encryptor> encryptor_;
|
||||
|
||||
std::map<AdnlQueryId, td::actor::ActorId<AdnlQuery>> out_queries_;
|
||||
|
||||
td::uint32 received_messages_ = 0;
|
||||
bool received_from_db_ = false;
|
||||
bool received_from_static_nodes_ = false;
|
||||
bool dht_query_active_ = false;
|
||||
|
||||
td::Timestamp next_dht_query_at_ = td::Timestamp::never();
|
||||
td::Timestamp next_db_update_at_ = td::Timestamp::never();
|
||||
td::Timestamp retry_send_at_ = td::Timestamp::never();
|
||||
};
|
||||
|
||||
class AdnlPeerImpl : public AdnlPeer {
|
||||
public:
|
||||
void receive_packet(AdnlNodeIdShort dst, td::actor::ActorId<AdnlLocalId> dst_actor, AdnlPacket packet) override;
|
||||
void send_messages(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor,
|
||||
std::vector<AdnlMessage> messages) override;
|
||||
void send_query(AdnlNodeIdShort src, td::actor::ActorId<AdnlLocalId> src_actor, std::string name,
|
||||
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) override;
|
||||
|
||||
void del_local_id(AdnlNodeIdShort local_id) override;
|
||||
void update_id(AdnlNodeIdFull id) override;
|
||||
void update_addr_list(AdnlNodeIdShort local_id, td::actor::ActorId<AdnlLocalId> local_actor,
|
||||
AdnlAddressList addr_list) override;
|
||||
void update_dht_node(td::actor::ActorId<dht::Dht> dht_node) override;
|
||||
//void check_signature(td::BufferSlice data, td::BufferSlice signature, td::Promise<td::Unit> promise) override;
|
||||
|
||||
AdnlPeerImpl(td::actor::ActorId<AdnlNetworkManager> network_manager, td::actor::ActorId<AdnlPeerTable> peer_table,
|
||||
td::actor::ActorId<dht::Dht> dht_node, AdnlNodeIdShort peer_id)
|
||||
: peer_id_short_(peer_id), dht_node_(dht_node), peer_table_(peer_table), network_manager_(network_manager) {
|
||||
}
|
||||
|
||||
struct PrintId {
|
||||
AdnlNodeIdShort peer_id;
|
||||
};
|
||||
|
||||
PrintId print_id() const {
|
||||
return PrintId{peer_id_short_};
|
||||
}
|
||||
|
||||
private:
|
||||
AdnlNodeIdShort peer_id_short_;
|
||||
AdnlNodeIdFull peer_id_;
|
||||
std::map<AdnlNodeIdShort, td::actor::ActorOwn<AdnlPeerPair>> peer_pairs_;
|
||||
td::actor::ActorId<dht::Dht> dht_node_;
|
||||
td::actor::ActorId<AdnlPeerTable> peer_table_;
|
||||
td::actor::ActorId<AdnlNetworkManager> network_manager_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerImpl::PrintId &id) {
|
||||
sb << "[peer " << id.peer_id << "]";
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerImpl &peer) {
|
||||
sb << peer.print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerImpl *peer) {
|
||||
sb << peer->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerPairImpl::PrintId &id) {
|
||||
sb << "[peerpair " << id.peer_id << "-" << id.local_id << "]";
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerPairImpl &peer) {
|
||||
sb << peer.print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::adnl::AdnlPeerPairImpl *peer) {
|
||||
sb << peer->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
87
adnl/adnl-proxy-types.cpp
Normal file
87
adnl/adnl-proxy-types.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-proxy-types.hpp"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "td/utils/Time.h"
|
||||
#include "common/errorcode.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
td::BufferSlice AdnlProxyFast::encrypt(Packet packet) const {
|
||||
auto date = static_cast<td::uint32>(td::Clocks::system());
|
||||
auto signature = create_hash_tl_object<ton_api::adnl_proxyToFastHash>(
|
||||
packet.ip, packet.port, date, sha256_bits256(packet.data.as_slice()), shared_secret_);
|
||||
|
||||
auto obj = create_serialize_tl_object<ton_api::adnl_proxyToFast>(packet.ip, packet.port, date, signature);
|
||||
td::BufferSlice res{32 + obj.size() + packet.data.size()};
|
||||
auto S = res.as_slice();
|
||||
S.copy_from(td::Bits256::zero().as_slice());
|
||||
S.remove_prefix(32);
|
||||
S.copy_from(obj.as_slice());
|
||||
S.remove_prefix(obj.size());
|
||||
S.copy_from(packet.data.as_slice());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Result<AdnlProxy::Packet> AdnlProxyFast::decrypt(td::BufferSlice packet) const {
|
||||
if (packet.size() < 36) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "too short packet");
|
||||
}
|
||||
|
||||
td::Bits256 v;
|
||||
v.as_slice().copy_from(packet.as_slice().truncate(32));
|
||||
if (!v.is_zero()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "non-zero DST");
|
||||
}
|
||||
packet.confirm_read(32);
|
||||
|
||||
TRY_RESULT(R, fetch_tl_prefix<ton_api::adnl_proxyToFast>(packet, true));
|
||||
|
||||
if (R->date_ < td::Clocks::system() - 8) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "too old date");
|
||||
}
|
||||
|
||||
auto signature = create_hash_tl_object<ton_api::adnl_proxyToFastHash>(
|
||||
R->ip_, R->port_, R->date_, sha256_bits256(packet.as_slice()), shared_secret_);
|
||||
if (signature != R->signature_) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "bad signature");
|
||||
}
|
||||
|
||||
return Packet{static_cast<td::uint32>(R->ip_), static_cast<td::uint16>(R->port_), std::move(packet)};
|
||||
}
|
||||
|
||||
td::Result<std::shared_ptr<AdnlProxy>> AdnlProxy::create(const ton_api::adnl_Proxy &proxy_type) {
|
||||
std::shared_ptr<AdnlProxy> R;
|
||||
ton_api::downcast_call(
|
||||
const_cast<ton_api::adnl_Proxy &>(proxy_type),
|
||||
td::overloaded([&](const ton_api::adnl_proxy_none &x) { R = std::make_shared<AdnlProxyNone>(); },
|
||||
[&](const ton_api::adnl_proxy_fast &x) {
|
||||
R = std::make_shared<AdnlProxyFast>(x.shared_secret_.as_slice());
|
||||
}));
|
||||
return R;
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
45
adnl/adnl-proxy-types.h
Normal file
45
adnl/adnl-proxy-types.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlProxy {
|
||||
public:
|
||||
struct Packet {
|
||||
td::uint32 ip;
|
||||
td::uint16 port;
|
||||
td::BufferSlice data;
|
||||
};
|
||||
virtual ~AdnlProxy() = default;
|
||||
virtual td::BufferSlice encrypt(Packet packet) const = 0;
|
||||
virtual td::Result<Packet> decrypt(td::BufferSlice packet) const = 0;
|
||||
virtual tl_object_ptr<ton_api::adnl_Proxy> tl() const = 0;
|
||||
|
||||
static td::Result<std::shared_ptr<AdnlProxy>> create(const ton_api::adnl_Proxy &proxy_type);
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
62
adnl/adnl-proxy-types.hpp
Normal file
62
adnl/adnl-proxy-types.hpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl-proxy-types.h"
|
||||
|
||||
#include "common/checksum.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlProxyNone : public AdnlProxy {
|
||||
public:
|
||||
AdnlProxyNone() {
|
||||
}
|
||||
td::BufferSlice encrypt(Packet packet) const override {
|
||||
return std::move(packet.data);
|
||||
}
|
||||
td::Result<Packet> decrypt(td::BufferSlice packet) const override {
|
||||
return Packet{0, 0, std::move(packet)};
|
||||
}
|
||||
tl_object_ptr<ton_api::adnl_Proxy> tl() const override {
|
||||
return create_tl_object<ton_api::adnl_proxy_none>();
|
||||
}
|
||||
};
|
||||
|
||||
class AdnlProxyFast : public AdnlProxy {
|
||||
public:
|
||||
AdnlProxyFast(td::Slice shared_secret)
|
||||
: shared_secret_(sha256_bits256(shared_secret)), shared_secret_raw_(shared_secret) {
|
||||
}
|
||||
td::BufferSlice encrypt(Packet packet) const override;
|
||||
td::Result<Packet> decrypt(td::BufferSlice packet) const override;
|
||||
tl_object_ptr<ton_api::adnl_Proxy> tl() const override {
|
||||
return create_tl_object<ton_api::adnl_proxy_fast>(shared_secret_raw_.clone_as_buffer_slice());
|
||||
}
|
||||
|
||||
private:
|
||||
td::Bits256 shared_secret_;
|
||||
td::SharedSlice shared_secret_raw_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
265
adnl/adnl-proxy.cpp
Normal file
265
adnl/adnl-proxy.cpp
Normal file
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
#include "td/net/UdpServer.h"
|
||||
#include "td/utils/port/signals.h"
|
||||
#include "td/utils/OptionsParser.h"
|
||||
#include "td/utils/FileLog.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/port/user.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "common/checksum.h"
|
||||
#include "common/errorcode.h"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
#include "adnl-proxy-types.h"
|
||||
#include <map>
|
||||
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class Receiver : public td::actor::Actor {
|
||||
public:
|
||||
void start_up() override;
|
||||
void receive_common(td::BufferSlice data);
|
||||
void receive_from_client(td::BufferSlice data);
|
||||
void receive_to_client(td::BufferSlice data);
|
||||
|
||||
Receiver(td::uint16 in_port, td::uint16 out_port, std::shared_ptr<AdnlProxy> proxy, td::IPAddress client_addr)
|
||||
: in_port_(in_port), out_port_(out_port), proxy_(std::move(proxy)), addr_(client_addr) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::uint16 in_port_;
|
||||
td::uint16 out_port_;
|
||||
std::shared_ptr<ton::adnl::AdnlProxy> proxy_;
|
||||
td::IPAddress addr_;
|
||||
td::actor::ActorOwn<td::UdpServer> out_udp_server_;
|
||||
td::actor::ActorOwn<td::UdpServer> in_udp_server_;
|
||||
};
|
||||
|
||||
void Receiver::start_up() {
|
||||
class Callback : public td::UdpServer::Callback {
|
||||
public:
|
||||
Callback(td::actor::ActorId<Receiver> manager, td::uint32 mode) : manager_(std::move(manager)), mode_(mode) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<Receiver> manager_;
|
||||
const td::uint32 mode_;
|
||||
void on_udp_message(td::UdpMessage udp_message) override {
|
||||
if (udp_message.error.is_error()) {
|
||||
LOG(DEBUG) << udp_message.error;
|
||||
return;
|
||||
}
|
||||
if (mode_ == 0) {
|
||||
td::actor::send_closure_later(manager_, &Receiver::receive_common, std::move(udp_message.data));
|
||||
} else if (mode_ == 1) {
|
||||
td::actor::send_closure_later(manager_, &Receiver::receive_from_client, std::move(udp_message.data));
|
||||
} else {
|
||||
td::actor::send_closure_later(manager_, &Receiver::receive_to_client, std::move(udp_message.data));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (in_port_ == out_port_) {
|
||||
auto X = td::UdpServer::create("udp server", in_port_, std::make_unique<Callback>(actor_id(this), 0));
|
||||
X.ensure();
|
||||
in_udp_server_ = X.move_as_ok();
|
||||
} else {
|
||||
auto X = td::UdpServer::create("udp server", in_port_, std::make_unique<Callback>(actor_id(this), 1));
|
||||
X.ensure();
|
||||
in_udp_server_ = X.move_as_ok();
|
||||
X = td::UdpServer::create("udp server", out_port_, std::make_unique<Callback>(actor_id(this), 2));
|
||||
X.ensure();
|
||||
out_udp_server_ = X.move_as_ok();
|
||||
}
|
||||
}
|
||||
|
||||
void Receiver::receive_common(td::BufferSlice data) {
|
||||
if (data.size() <= 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
td::Bits256 id;
|
||||
id.as_slice().copy_from(data.as_slice().truncate(32));
|
||||
|
||||
if (id.is_zero()) {
|
||||
receive_from_client(std::move(data));
|
||||
} else {
|
||||
receive_to_client(std::move(data));
|
||||
}
|
||||
}
|
||||
|
||||
void Receiver::receive_from_client(td::BufferSlice data) {
|
||||
auto F = proxy_->decrypt(std::move(data));
|
||||
if (F.is_error()) {
|
||||
return;
|
||||
}
|
||||
auto f = F.move_as_ok();
|
||||
|
||||
td::IPAddress a;
|
||||
if (a.init_ipv4_port(td::IPAddress::ipv4_to_str(f.ip), f.port).is_error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
td::UdpMessage M;
|
||||
M.address = a;
|
||||
M.data = std::move(f.data);
|
||||
|
||||
td::actor::send_closure(out_udp_server_.empty() ? in_udp_server_.get() : out_udp_server_.get(), &td::UdpServer::send,
|
||||
std::move(M));
|
||||
}
|
||||
|
||||
void Receiver::receive_to_client(td::BufferSlice data) {
|
||||
LOG(DEBUG) << "proxying to " << addr_;
|
||||
td::UdpMessage M;
|
||||
M.address = addr_;
|
||||
M.data = std::move(data);
|
||||
|
||||
td::actor::send_closure(in_udp_server_.empty() ? out_udp_server_.get() : in_udp_server_.get(), &td::UdpServer::send,
|
||||
std::move(M));
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
SET_VERBOSITY_LEVEL(verbosity_INFO);
|
||||
|
||||
td::set_default_failure_signal_handler().ensure();
|
||||
|
||||
std::vector<td::actor::ActorOwn<ton::adnl::Receiver>> x;
|
||||
std::unique_ptr<td::LogInterface> logger_;
|
||||
SCOPE_EXIT {
|
||||
td::log_interface = td::default_log_interface;
|
||||
};
|
||||
|
||||
std::string config = "/var/ton-work/etc/adnl-proxy.conf.json";
|
||||
|
||||
td::OptionsParser p;
|
||||
p.set_description("validator or full node for TON network");
|
||||
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
|
||||
int v = VERBOSITY_NAME(FATAL) + (td::to_integer<int>(arg));
|
||||
SET_VERBOSITY_LEVEL(v);
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('h', "help", "prints_help", [&]() {
|
||||
char b[10240];
|
||||
td::StringBuilder sb(td::MutableSlice{b, 10000});
|
||||
sb << p;
|
||||
std::cout << sb.as_cslice().c_str();
|
||||
std::exit(2);
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('c', "config", "config file", [&](td::Slice arg) {
|
||||
config = arg.str();
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
|
||||
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
close(0);
|
||||
setsid();
|
||||
#endif
|
||||
}).ensure();
|
||||
return td::Status::OK();
|
||||
});
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
|
||||
auto F = std::make_unique<td::FileLog>();
|
||||
TRY_STATUS(F->init(fname.str()));
|
||||
logger_ = std::move(F);
|
||||
td::log_interface = logger_.get();
|
||||
return td::Status::OK();
|
||||
});
|
||||
#endif
|
||||
td::uint32 threads = 7;
|
||||
p.add_option('t', "threads", PSTRING() << "number of threads (default=" << threads << ")", [&](td::Slice fname) {
|
||||
td::int32 v;
|
||||
try {
|
||||
v = std::stoi(fname.str());
|
||||
} catch (...) {
|
||||
return td::Status::Error(ton::ErrorCode::error, "bad value for --threads: not a number");
|
||||
}
|
||||
if (v < 1 || v > 256) {
|
||||
return td::Status::Error(ton::ErrorCode::error, "bad value for --threads: should be in range [1..256]");
|
||||
}
|
||||
threads = v;
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('u', "user", "change user", [&](td::Slice user) { return td::change_user(user); });
|
||||
|
||||
p.run(argc, argv).ensure();
|
||||
|
||||
td::actor::Scheduler scheduler({threads});
|
||||
|
||||
auto R = [&]() -> td::Status {
|
||||
TRY_RESULT_PREFIX(conf_data, td::read_file(config), "failed to read: ");
|
||||
TRY_RESULT_PREFIX(conf_json, td::json_decode(conf_data.as_slice()), "failed to parse json: ");
|
||||
|
||||
ton::ton_api::engine_adnlProxy_config conf;
|
||||
TRY_STATUS_PREFIX(ton::ton_api::from_json(conf, conf_json.get_object()), "json does not fit TL scheme: ");
|
||||
|
||||
if (!conf.ports_.size()) {
|
||||
return td::Status::Error("empty config");
|
||||
}
|
||||
|
||||
for (auto &y : conf.ports_) {
|
||||
auto in_port = static_cast<td::uint16>(y->in_port_);
|
||||
auto out_port = static_cast<td::uint16>(y->out_port_);
|
||||
if (!y->proxy_type_) {
|
||||
return td::Status::Error("empty proxy type");
|
||||
}
|
||||
TRY_RESULT(proxy, ton::adnl::AdnlProxy::create(*y->proxy_type_.get()));
|
||||
td::IPAddress a;
|
||||
a.init_ipv4_port(td::IPAddress::ipv4_to_str(y->dst_ip_), static_cast<td::uint16>(y->dst_port_)).ensure();
|
||||
|
||||
scheduler.run_in_context([&] {
|
||||
x.push_back(td::actor::create_actor<ton::adnl::Receiver>("adnl-proxy", in_port, out_port, std::move(proxy), a));
|
||||
});
|
||||
}
|
||||
|
||||
return td::Status::OK();
|
||||
}();
|
||||
|
||||
if (R.is_error()) {
|
||||
LOG(FATAL) << "bad config: " << R.move_as_error();
|
||||
}
|
||||
|
||||
while (scheduler.run(1)) {
|
||||
}
|
||||
}
|
44
adnl/adnl-query.cpp
Normal file
44
adnl/adnl-query.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-query.h"
|
||||
#include "common/errorcode.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
void AdnlQuery::alarm() {
|
||||
promise_.set_error(td::Status::Error(ErrorCode::timeout, "adnl query timeout"));
|
||||
stop();
|
||||
}
|
||||
void AdnlQuery::result(td::BufferSlice data) {
|
||||
promise_.set_value(std::move(data));
|
||||
stop();
|
||||
}
|
||||
|
||||
AdnlQueryId AdnlQuery::random_query_id() {
|
||||
AdnlQueryId q_id;
|
||||
td::Random::secure_bytes(q_id.as_slice());
|
||||
return q_id;
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
67
adnl/adnl-query.h
Normal file
67
adnl/adnl-query.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "common/bitstring.h"
|
||||
#include "td/utils/buffer.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlPeerPair;
|
||||
|
||||
using AdnlQueryId = td::Bits256;
|
||||
|
||||
class AdnlQuery : public td::actor::Actor {
|
||||
public:
|
||||
static td::actor::ActorId<AdnlQuery> create(td::Promise<td::BufferSlice> promise,
|
||||
std::function<void(AdnlQueryId)> destroy, std::string name,
|
||||
td::Timestamp timeout, AdnlQueryId id) {
|
||||
return td::actor::create_actor<AdnlQuery>("query", name, std::move(promise), std::move(destroy), timeout, id)
|
||||
.release();
|
||||
}
|
||||
static AdnlQueryId random_query_id();
|
||||
AdnlQuery(std::string name, td::Promise<td::BufferSlice> promise, std::function<void(AdnlQueryId)> destroy,
|
||||
td::Timestamp timeout, AdnlQueryId id)
|
||||
: name_(std::move(name)), timeout_(timeout), promise_(std::move(promise)), destroy_(std::move(destroy)), id_(id) {
|
||||
}
|
||||
void alarm() override;
|
||||
void result(td::BufferSlice data);
|
||||
void start_up() override {
|
||||
alarm_timestamp() = timeout_;
|
||||
}
|
||||
void tear_down() override {
|
||||
destroy_(id_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
td::Timestamp timeout_;
|
||||
td::Promise<td::BufferSlice> promise_;
|
||||
std::function<void(AdnlQueryId)> destroy_;
|
||||
AdnlQueryId id_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
55
adnl/adnl-static-nodes.cpp
Normal file
55
adnl/adnl-static-nodes.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-static-nodes.h"
|
||||
#include "adnl-static-nodes.hpp"
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
void AdnlStaticNodesManagerImpl::add_node(AdnlNode node) {
|
||||
auto id_short = node.compute_short_id();
|
||||
VLOG(ADNL_INFO) << "[staticnodes] adding static node " << id_short;
|
||||
|
||||
nodes_.emplace(id_short, std::move(node));
|
||||
}
|
||||
|
||||
void AdnlStaticNodesManagerImpl::del_node(AdnlNodeIdShort id) {
|
||||
nodes_.erase(id);
|
||||
}
|
||||
|
||||
td::Result<AdnlNode> AdnlStaticNodesManagerImpl::get_node(AdnlNodeIdShort id) {
|
||||
auto it = nodes_.find(id);
|
||||
if (it == nodes_.end()) {
|
||||
return td::Status::Error(ErrorCode::notready, "static node not found");
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<AdnlStaticNodesManager> AdnlStaticNodesManager::create() {
|
||||
auto X = td::actor::create_actor<AdnlStaticNodesManagerImpl>("staticnodesmanager");
|
||||
return td::actor::ActorOwn<AdnlStaticNodesManager>(std::move(X));
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
43
adnl/adnl-static-nodes.h
Normal file
43
adnl/adnl-static-nodes.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
#include "adnl-peer-table.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlStaticNodesManager : public td::actor::Actor {
|
||||
public:
|
||||
virtual void add_node(AdnlNode node) = 0;
|
||||
virtual void del_node(AdnlNodeIdShort id) = 0;
|
||||
virtual td::Result<AdnlNode> get_node(AdnlNodeIdShort id) = 0;
|
||||
|
||||
static td::actor::ActorOwn<AdnlStaticNodesManager> create();
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
42
adnl/adnl-static-nodes.hpp
Normal file
42
adnl/adnl-static-nodes.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "adnl-static-nodes.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlStaticNodesManagerImpl : public AdnlStaticNodesManager {
|
||||
public:
|
||||
void add_node(AdnlNode node) override;
|
||||
void del_node(AdnlNodeIdShort id) override;
|
||||
td::Result<AdnlNode> get_node(AdnlNodeIdShort id) override;
|
||||
AdnlStaticNodesManagerImpl() {
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<AdnlNodeIdShort, AdnlNode> nodes_;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
38
adnl/adnl-test-loopback-implementation.cpp
Normal file
38
adnl/adnl-test-loopback-implementation.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl-test-loopback-implementation.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
AdnlAddressList TestLoopbackNetworkManager::generate_dummy_addr_list(bool empty) {
|
||||
auto obj = ton::create_tl_object<ton::ton_api::adnl_address_udp>(1, 1);
|
||||
auto objv = std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>>();
|
||||
objv.push_back(std::move(obj));
|
||||
td::uint32 now = Adnl::adnl_start_time();
|
||||
auto addrR = ton::adnl::AdnlAddressList::create(
|
||||
ton::create_tl_object<ton::ton_api::adnl_addressList>(std::move(objv), empty ? 0 : now, empty ? 0 : now, 0, 0));
|
||||
addrR.ensure();
|
||||
return addrR.move_as_ok();
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
86
adnl/adnl-test-loopback-implementation.h
Normal file
86
adnl/adnl-test-loopback-implementation.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl/adnl.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class TestLoopbackNetworkManager : public ton::adnl::AdnlNetworkManager {
|
||||
public:
|
||||
void install_callback(std::unique_ptr<Callback> callback) override {
|
||||
CHECK(!callback_);
|
||||
callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
void add_self_addr(td::IPAddress addr, td::uint32 priority) override {
|
||||
}
|
||||
void add_proxy_addr(td::IPAddress addr, std::shared_ptr<AdnlProxy> proxy, td::uint32 priority) override {
|
||||
}
|
||||
void send_udp_packet(ton::adnl::AdnlNodeIdShort src_id, ton::adnl::AdnlNodeIdShort dst_id, td::IPAddress dst_addr,
|
||||
td::uint32 priority, td::BufferSlice data) override {
|
||||
if (allowed_sources_.count(src_id) == 0 || allowed_destinations_.count(dst_id) == 0) {
|
||||
// just drop
|
||||
return;
|
||||
}
|
||||
if (loss_probability_ > 0 && td::Random::fast(0, 10000) < loss_probability_ * 10000) {
|
||||
return;
|
||||
}
|
||||
CHECK(callback_);
|
||||
callback_->receive_packet(dst_addr, std::move(data));
|
||||
}
|
||||
|
||||
void add_node_id(AdnlNodeIdShort id, bool allow_send, bool allow_receive) {
|
||||
if (allow_send) {
|
||||
allowed_sources_.insert(id);
|
||||
} else {
|
||||
allowed_sources_.erase(id);
|
||||
}
|
||||
if (allow_receive) {
|
||||
allowed_destinations_.insert(id);
|
||||
} else {
|
||||
allowed_destinations_.erase(id);
|
||||
}
|
||||
}
|
||||
|
||||
void set_loss_probability(double p) {
|
||||
CHECK(p >= 0 && p <= 1);
|
||||
loss_probability_ = p;
|
||||
}
|
||||
|
||||
TestLoopbackNetworkManager() {
|
||||
}
|
||||
|
||||
static AdnlAddressList generate_dummy_addr_list(bool empty = false);
|
||||
|
||||
private:
|
||||
std::set<AdnlNodeIdShort> allowed_sources_;
|
||||
std::set<AdnlNodeIdShort> allowed_destinations_;
|
||||
std::unique_ptr<Callback> callback_;
|
||||
double loss_probability_ = 0.0;
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
120
adnl/adnl.h
Normal file
120
adnl/adnl.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
#include "adnl-node-id.hpp"
|
||||
#include "adnl-node.h"
|
||||
#include "common/errorcode.h"
|
||||
#include "keyring/keyring.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace dht {
|
||||
class Dht;
|
||||
}
|
||||
|
||||
namespace adnl {
|
||||
|
||||
class AdnlNetworkManager;
|
||||
|
||||
class AdnlExtServer : public td::actor::Actor {
|
||||
public:
|
||||
virtual void add_local_id(AdnlNodeIdShort id) = 0;
|
||||
virtual void add_tcp_port(td::uint16 port) = 0;
|
||||
virtual ~AdnlExtServer() = default;
|
||||
};
|
||||
|
||||
class AdnlSenderInterface : public td::actor::Actor {
|
||||
public:
|
||||
virtual ~AdnlSenderInterface() = default;
|
||||
|
||||
virtual void send_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) = 0;
|
||||
|
||||
virtual void send_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name,
|
||||
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data) = 0;
|
||||
virtual void send_query_ex(AdnlNodeIdShort src, AdnlNodeIdShort dst, std::string name,
|
||||
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice data,
|
||||
td::uint64 max_answer_size) = 0;
|
||||
};
|
||||
|
||||
class Adnl : public AdnlSenderInterface {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
virtual void receive_message(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data) = 0;
|
||||
virtual void receive_query(AdnlNodeIdShort src, AdnlNodeIdShort dst, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual ~Callback() = default;
|
||||
};
|
||||
|
||||
static constexpr td::uint32 get_mtu() {
|
||||
return 1024;
|
||||
}
|
||||
static constexpr td::uint32 huge_packet_max_size() {
|
||||
return 1024 * 8;
|
||||
}
|
||||
|
||||
// adds node to peer table
|
||||
// used mostly from DHT to avoid loops
|
||||
virtual void add_peer(AdnlNodeIdShort local_id, AdnlNodeIdFull id, AdnlAddressList addr_list) = 0;
|
||||
|
||||
// adds address list for nodes from config
|
||||
virtual void add_static_nodes_from_config(AdnlNodesList nodes) = 0;
|
||||
|
||||
// adds local id. After that you can send/receive messages from/to this id
|
||||
virtual void add_id(AdnlNodeIdFull id, AdnlAddressList addr_list) = 0;
|
||||
virtual void del_id(AdnlNodeIdShort id, td::Promise<td::Unit> promise) = 0;
|
||||
|
||||
// subscribe to (some) messages(+queries) to this local id
|
||||
virtual void subscribe(AdnlNodeIdShort dst, std::string prefix, std::unique_ptr<Callback> callback) = 0;
|
||||
virtual void unsubscribe(AdnlNodeIdShort dst, std::string prefix) = 0;
|
||||
|
||||
// register (main) dht node
|
||||
// it will be used to send queries to DHT from adnl
|
||||
// there are two types of queries:
|
||||
// - discover node addr list for unknown node
|
||||
// - update local node information
|
||||
virtual void register_dht_node(td::actor::ActorId<dht::Dht> dht_node) = 0;
|
||||
virtual void register_network_manager(td::actor::ActorId<AdnlNetworkManager> network_manager) = 0;
|
||||
|
||||
// get local id information
|
||||
// for example when you need to sent it further
|
||||
virtual void get_addr_list(AdnlNodeIdShort id, td::Promise<AdnlAddressList> promise) = 0;
|
||||
virtual void get_self_node(AdnlNodeIdShort id, td::Promise<AdnlNode> promise) = 0;
|
||||
|
||||
virtual void create_ext_server(std::vector<AdnlNodeIdShort> ids, std::vector<td::uint16> ports,
|
||||
td::Promise<td::actor::ActorOwn<AdnlExtServer>> promise) = 0;
|
||||
|
||||
static td::actor::ActorOwn<Adnl> create(std::string db, td::actor::ActorId<keyring::Keyring> keyring);
|
||||
|
||||
static std::string int_to_bytestring(td::int32 id) {
|
||||
return std::string(reinterpret_cast<char *>(&id), 4);
|
||||
}
|
||||
|
||||
static td::int32 adnl_start_time();
|
||||
};
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
using Adnl = adnl::Adnl;
|
||||
|
||||
} // namespace ton
|
240
adnl/test/adnl-test-ping.cpp
Normal file
240
adnl/test/adnl-test-ping.cpp
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl/adnl-network-manager.h"
|
||||
#include "adnl/adnl-peer-table.h"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "keys/encryptor.h"
|
||||
#include "td/utils/Time.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/OptionsParser.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
template <std::size_t size>
|
||||
std::ostream &operator<<(std::ostream &stream, const td::UInt<size> &x) {
|
||||
for (size_t i = 0; i < size / 8; i++) {
|
||||
stream << td::format::hex_digit((x.raw[i] >> 4) & 15) << td::format::hex_digit(x.raw[i] & 15);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
class AdnlNode : public td::actor::Actor {
|
||||
private:
|
||||
std::vector<td::UInt256> ping_ids_;
|
||||
|
||||
td::actor::ActorOwn<ton::AdnlNetworkManager> network_manager_;
|
||||
td::actor::ActorOwn<ton::AdnlPeerTable> peer_table_;
|
||||
|
||||
td::UInt256 local_id_;
|
||||
bool local_id_set_ = false;
|
||||
|
||||
std::string host_ = "127.0.0.1";
|
||||
td::uint32 ip_ = 0x7f000001;
|
||||
td::uint16 port_ = 2380;
|
||||
|
||||
void receive_message(td::UInt256 src, td::UInt256 dst, td::BufferSlice data) {
|
||||
std::cout << "MESSAGE FROM " << src << " to " << dst << " of size " << std::to_string(data.size()) << "\n";
|
||||
}
|
||||
|
||||
void receive_query(td::UInt256 src, td::UInt256 dst, td::uint64 query_id, td::BufferSlice data) {
|
||||
std::cout << "QUERY " << std::to_string(query_id) << " FROM " << src << " to " << dst << " of size "
|
||||
<< std::to_string(data.size()) << "\n";
|
||||
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::answer_query, dst, src, query_id,
|
||||
ton::create_tl_object<ton::ton_api::testObject>());
|
||||
}
|
||||
|
||||
std::unique_ptr<ton::AdnlPeerTable::Callback> make_callback() {
|
||||
class Callback : public ton::AdnlPeerTable::Callback {
|
||||
public:
|
||||
void receive_message(td::UInt256 src, td::UInt256 dst, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &AdnlNode::receive_message, src, dst, std::move(data));
|
||||
}
|
||||
void receive_query(td::UInt256 src, td::UInt256 dst, td::uint64 query_id, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &AdnlNode::receive_query, src, dst, query_id, std::move(data));
|
||||
}
|
||||
Callback(td::actor::ActorId<AdnlNode> id) : id_(std::move(id)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<AdnlNode> id_;
|
||||
};
|
||||
|
||||
return std::make_unique<Callback>(td::actor::actor_id(this));
|
||||
}
|
||||
|
||||
public:
|
||||
void start_up() override {
|
||||
alarm_timestamp() = td::Timestamp::in(1);
|
||||
}
|
||||
AdnlNode() {
|
||||
network_manager_ = ton::AdnlNetworkManager::create();
|
||||
peer_table_ = ton::AdnlPeerTable::create();
|
||||
td::actor::send_closure(network_manager_, &ton::AdnlNetworkManager::register_peer_table, peer_table_.get());
|
||||
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::register_network_manager, network_manager_.get());
|
||||
}
|
||||
void listen_udp(td::uint16 port) {
|
||||
td::actor::send_closure(network_manager_, &ton::AdnlNetworkManager::add_listening_udp_port, "0.0.0.0", port);
|
||||
port_ = port;
|
||||
}
|
||||
void set_host(td::IPAddress ip, std::string host) {
|
||||
ip_ = ip.get_ipv4();
|
||||
host_ = host;
|
||||
}
|
||||
void send_pings_to(td::UInt256 id) {
|
||||
std::cout << "send pings to " << id << "\n";
|
||||
ping_ids_.push_back(id);
|
||||
}
|
||||
void add_local_id(ton::tl_object_ptr<ton::ton_api::adnl_id_Pk> pk_) {
|
||||
auto pub_ = ton::get_public_key(pk_);
|
||||
local_id_ = ton::adnl_short_id(pub_);
|
||||
std::cout << "local_id = '" << local_id_ << "'\n";
|
||||
auto x = ton::create_tl_object<ton::ton_api::adnl_address_udp>(ip_, port_);
|
||||
auto v = std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>>();
|
||||
v.push_back(ton::move_tl_object_as<ton::ton_api::adnl_Address>(x));
|
||||
auto y =
|
||||
ton::create_tl_object<ton::ton_api::adnl_addressList>(std::move(v), static_cast<td::int32>(td::Time::now()));
|
||||
|
||||
LOG(INFO) << "local_addr_list: " << ton::ton_api::to_string(y);
|
||||
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::add_id, std::move(pk_), std::move(y));
|
||||
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::subscribe, local_id_, "", make_callback());
|
||||
local_id_set_ = true;
|
||||
}
|
||||
|
||||
void add_foreign(ton::tl_object_ptr<ton::ton_api::adnl_id_Full> id,
|
||||
ton::tl_object_ptr<ton::ton_api::adnl_addressList> addr_list) {
|
||||
std::cout << ton::adnl_short_id(id) << "\n";
|
||||
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::add_peer, std::move(id), std::move(addr_list));
|
||||
}
|
||||
|
||||
void alarm() override {
|
||||
std::cout << "alarm\n";
|
||||
if (local_id_set_) {
|
||||
for (auto it = ping_ids_.begin(); it != ping_ids_.end(); it++) {
|
||||
auto P = td::PromiseCreator::lambda([](td::Result<td::BufferSlice> result) {
|
||||
if (result.is_error()) {
|
||||
std::cout << "received error " << result.move_as_error().to_string() << "\n";
|
||||
} else {
|
||||
auto message = result.move_as_ok();
|
||||
std::cout << "received answer to query\n";
|
||||
}
|
||||
});
|
||||
td::actor::send_closure(peer_table_, &ton::AdnlPeerTable::send_query, local_id_, *it, std::move(P),
|
||||
td::Timestamp::in(5), ton::create_tl_object<ton::ton_api::getTestObject>());
|
||||
}
|
||||
}
|
||||
|
||||
alarm_timestamp() = td::Timestamp::in(1);
|
||||
}
|
||||
};
|
||||
|
||||
td::Result<td::UInt256> get_uint256(std::string str) {
|
||||
if (str.size() != 64) {
|
||||
return td::Status::Error("uint256 must have 64 bytes");
|
||||
}
|
||||
td::UInt256 res;
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
td::actor::ActorOwn<AdnlNode> x;
|
||||
|
||||
td::OptionsParser p;
|
||||
p.set_description("test basic adnl functionality");
|
||||
p.add_option('h', "help", "prints_help", [&]() {
|
||||
char b[10240];
|
||||
td::StringBuilder sb({b, 10000});
|
||||
sb << p;
|
||||
std::cout << sb.as_cslice().c_str();
|
||||
std::exit(2);
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('p', "port", "sets udp port", [&](td::Slice port) {
|
||||
td::actor::send_closure(x, &AdnlNode::listen_udp, static_cast<td::uint16>(std::stoi(port.str())));
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('a', "host", "sets local ip", [&](td::Slice ip) {
|
||||
td::IPAddress addr;
|
||||
auto R = addr.init_host_port(ip.str(), 0);
|
||||
if (R.is_error()) {
|
||||
return R;
|
||||
}
|
||||
td::actor::send_closure(x, &AdnlNode::set_host, addr, ip.str());
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('i', "id", "sets local id", [&](td::Slice id) {
|
||||
td::actor::send_closure(x, &AdnlNode::add_local_id,
|
||||
ton::create_tl_object<ton::ton_api::adnl_id_pk_unenc>(id.str()));
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('P', "peer", "adds peer id@host:port", [&](td::Slice id) {
|
||||
auto pos = id.rfind('@');
|
||||
if (pos == static_cast<size_t>(-1)) {
|
||||
return td::Status::Error("--peer expected randomtag@host:port as argument");
|
||||
}
|
||||
auto s1 = id.substr(0, pos);
|
||||
auto f_id = ton::create_tl_object<ton::ton_api::adnl_id_unenc>(s1.str());
|
||||
td::IPAddress addr;
|
||||
auto R = addr.init_host_port(td::CSlice(id.substr(pos + 1).str()));
|
||||
if (R.is_error()) {
|
||||
return R.move_as_error();
|
||||
}
|
||||
|
||||
auto f_addr = ton::create_tl_object<ton::ton_api::adnl_address_udp>(addr.get_ipv4(), addr.get_port());
|
||||
std::vector<ton::tl_object_ptr<ton::ton_api::adnl_Address>> vv;
|
||||
vv.push_back(ton::move_tl_object_as<ton::ton_api::adnl_Address>(f_addr));
|
||||
|
||||
auto f_addr_list =
|
||||
ton::create_tl_object<ton::ton_api::adnl_addressList>(std::move(vv), static_cast<int>(td::Time::now()));
|
||||
|
||||
td::actor::send_closure(x, &AdnlNode::add_foreign, ton::move_tl_object_as<ton::ton_api::adnl_id_Full>(f_id),
|
||||
std::move(f_addr_list));
|
||||
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('n', "node", "node to send pings to", [&](td::Slice node) {
|
||||
auto R = get_uint256(node.str());
|
||||
if (R.is_error()) {
|
||||
return R.move_as_error();
|
||||
}
|
||||
|
||||
td::actor::send_closure(x, &AdnlNode::send_pings_to, R.move_as_ok());
|
||||
return td::Status::OK();
|
||||
});
|
||||
|
||||
td::actor::Scheduler scheduler({2});
|
||||
scheduler.run_in_context([&] {
|
||||
x = td::actor::create_actor<AdnlNode>(td::actor::ActorInfoCreator::Options().with_name("A").with_poll());
|
||||
});
|
||||
scheudler.run();
|
||||
return 0;
|
||||
}
|
27
adnl/utils.cpp
Normal file
27
adnl/utils.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "utils.hpp"
|
||||
#include "tl/tl_object_store.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "keys/encryptor.h"
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
#include "adnl-node-id.hpp"
|
||||
|
||||
namespace ton {} // namespace ton
|
45
adnl/utils.hpp
Normal file
45
adnl/utils.hpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/base64.h"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
|
||||
#include "common/errorcode.h"
|
||||
#include "common/checksum.h"
|
||||
#include "adnl-node-id.hpp"
|
||||
#include "common/status.h"
|
||||
#include "adnl-node.h"
|
||||
#include "adnl-address-list.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace adnl {
|
||||
|
||||
inline bool adnl_node_is_older(AdnlNode &a, AdnlNode &b) {
|
||||
return a.addr_list().version() < b.addr_list().version();
|
||||
}
|
||||
|
||||
} // namespace adnl
|
||||
|
||||
} // namespace ton
|
22
blockchain-explorer/CMakeLists.txt
Normal file
22
blockchain-explorer/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
|
||||
find_package(MHD)
|
||||
|
||||
if (MHD_FOUND)
|
||||
|
||||
set(BLOCHAIN_EXPLORER_SOURCE
|
||||
blockchain-explorer.cpp
|
||||
blockchain-explorer.hpp
|
||||
blockchain-explorer-http.cpp
|
||||
blockchain-explorer-http.hpp
|
||||
blockchain-explorer-query.cpp
|
||||
blockchain-explorer-query.hpp
|
||||
)
|
||||
|
||||
add_executable(blockchain-explorer ${BLOCHAIN_EXPLORER_SOURCE})
|
||||
target_include_directories(blockchain-explorer PUBLIC ${MHD_INCLUDE_DIRS})
|
||||
target_link_libraries(blockchain-explorer tdutils tdactor adnllite tl_lite_api tl-lite-utils
|
||||
ton_crypto ton_block ${MHD_LIBRARY})
|
||||
|
||||
endif()
|
695
blockchain-explorer/blockchain-explorer-http.cpp
Normal file
695
blockchain-explorer/blockchain-explorer-http.cpp
Normal file
|
@ -0,0 +1,695 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "blockchain-explorer-http.hpp"
|
||||
#include "block/block-db.h"
|
||||
#include "block/block.h"
|
||||
#include "block/block-parse.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cellops.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
#include "block/mc-config.h"
|
||||
#include "ton/ton-shard.h"
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(AddressCell addr_c) {
|
||||
ton::WorkchainId wc;
|
||||
ton::StdSmcAddress addr;
|
||||
if (!block::tlb::t_MsgAddressInt.extract_std_address(addr_c.root, wc, addr)) {
|
||||
abort("<cannot unpack addr>");
|
||||
return *this;
|
||||
}
|
||||
block::StdAddress caddr{wc, addr};
|
||||
*this << "<a href=\"" << AccountLink{caddr, ton::BlockIdExt{}} << "\">" << caddr.rserialize(true) << "</a>";
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(MessageCell msg) {
|
||||
if (msg.root.is_null()) {
|
||||
abort("<message not found");
|
||||
return *this;
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVmOrd(), msg.root};
|
||||
block::gen::CommonMsgInfo info;
|
||||
td::Ref<vm::CellSlice> src, dest;
|
||||
*this << "<div id=\"msg" << msg.root->get_hash() << "\">";
|
||||
*this << "<div class=\"table-responsive my-3\">\n"
|
||||
<< "<table class=\"table-sm table-striped\">\n"
|
||||
<< "<tr><th>hash</th><td>" << msg.root->get_hash().to_hex() << "</td></tr>\n";
|
||||
switch (block::gen::t_CommonMsgInfo.get_tag(cs)) {
|
||||
case block::gen::CommonMsgInfo::ext_in_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
if (!tlb::unpack(cs, info)) {
|
||||
abort("<cannot unpack inbound external message>");
|
||||
return *this;
|
||||
}
|
||||
*this << "<tr><th>type</th><td>external</td></tr>\n"
|
||||
<< "<tr><th>source</th><td>NONE</td></tr>\n"
|
||||
<< "<tr><th>destination</th><td>" << AddressCell{info.dest} << "</td></tr>\n";
|
||||
break;
|
||||
}
|
||||
case block::gen::CommonMsgInfo::ext_out_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_ext_out_msg_info info;
|
||||
if (!tlb::unpack(cs, info)) {
|
||||
abort("<cannot unpack outbound external message>");
|
||||
return *this;
|
||||
}
|
||||
*this << "<tr><th>type</th><td>external OUT</td></tr>\n"
|
||||
<< "<tr><th>source</th><td>" << AddressCell{info.src} << "</td></tr>\n"
|
||||
<< "<tr><th>destination</th><td>NONE</td></tr>\n"
|
||||
<< "<tr><th>lt</th><td>" << info.created_lt << "</td></tr>\n"
|
||||
<< "<tr><th>time</th><td>" << info.created_at << "</td></tr>\n";
|
||||
break;
|
||||
}
|
||||
case block::gen::CommonMsgInfo::int_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_int_msg_info info;
|
||||
if (!tlb::unpack(cs, info)) {
|
||||
abort("cannot unpack internal message");
|
||||
return *this;
|
||||
}
|
||||
td::RefInt256 value;
|
||||
td::Ref<vm::Cell> extra;
|
||||
if (!block::unpack_CurrencyCollection(info.value, value, extra)) {
|
||||
abort("cannot unpack message value");
|
||||
return *this;
|
||||
}
|
||||
*this << "<tr><th>type</th><td>internal</td></tr>\n"
|
||||
<< "<tr><th>source</th><td>" << AddressCell{info.src} << "</td></tr>\n"
|
||||
<< "<tr><th>destination</th><td>" << AddressCell{info.dest} << "</td></tr>\n"
|
||||
<< "<tr><th>lt</th><td>" << info.created_lt << "</td></tr>\n"
|
||||
<< "<tr><th>time</th><td>" << info.created_at << "</td></tr>\n"
|
||||
<< "<tr><th>value</th><td>" << value << "</td></tr>\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
abort("cannot unpack message");
|
||||
return *this;
|
||||
}
|
||||
|
||||
*this << "</table></div>\n";
|
||||
*this << RawData<block::gen::Message>{msg.root, block::gen::t_Anything} << "</div>";
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(ton::BlockIdExt block_id) {
|
||||
return *this << "<a href=\"" << BlockLink{block_id} << "\">" << block_id.id.to_str() << "</a>";
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(ton::BlockId block_id) {
|
||||
return *this << "<a href=\"" << prefix_ << "search?workchain=" << block_id.workchain
|
||||
<< "&shard=" << ton::shard_to_str(block_id.shard) << "&seqno=" << block_id.seqno << "\">"
|
||||
<< block_id.to_str() << "</a>";
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(BlockSearch bs) {
|
||||
*this << "<form class=\"container\" action=\"" << prefix_ << "search\" method=\"get\">"
|
||||
<< "<div class=\"row\">"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>workchain</label>"
|
||||
<< "<input type=\"text\" class=\"form-control mr-2\" name=\"workchain\" value=\""
|
||||
<< (bs.block_id.is_valid() ? std::to_string(bs.block_id.id.workchain) : "") << "\">"
|
||||
<< "</div>\n"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>shard/account</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"shard\" value=\""
|
||||
<< (bs.block_id.is_valid() ? ton::shard_to_str(bs.block_id.id.shard) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>seqno</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"seqno\" value=\""
|
||||
<< (bs.block_id.is_valid() ? std::to_string(bs.block_id.id.seqno) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label class=\"d-none d-lg-block\"> </label>"
|
||||
<< "<div><button type=\"submit\" class=\"btn btn-primary mr-2\">Submit</button></div>"
|
||||
<< "</div></div><div class=\"row\">"
|
||||
<< "<div class=\"form-group col-md-6\">"
|
||||
<< "<label>logical time</label>"
|
||||
<< "<input type=\"text\" class=\"form-control mr-2\" name=\"lt\">"
|
||||
<< "</div>\n"
|
||||
<< "<div class=\"form-group col-md-6\">"
|
||||
<< "<label>unix time</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"utime\"></div>"
|
||||
<< "</div><div class=\"row\">"
|
||||
<< "<div class=\"form-group col-md-6\">"
|
||||
<< "<label>root hash</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"roothash\" value=\""
|
||||
//<< (!bs.block_id.id.is_valid() || bs.block_id.root_hash.is_zero() ? "" : bs.block_id.root_hash.to_hex())
|
||||
<< "\"></div>"
|
||||
<< "<div class=\"col-md-6\">"
|
||||
<< "<label>file hash</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"filehash\" value=\""
|
||||
//<< (!bs.block_id.id.is_valid() || bs.block_id.file_hash.is_zero() ? "" : bs.block_id.file_hash.to_hex())
|
||||
<< "\"></div>"
|
||||
<< "</div></form>\n";
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(AccountSearch bs) {
|
||||
*this << "<form class=\"container\" action=\"" << prefix_ << "account\" method=\"get\">"
|
||||
<< "<div class=\"row\">"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>workchain</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"workchain\" value=\""
|
||||
<< (bs.block_id.is_valid() ? std::to_string(bs.block_id.id.workchain) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>shard</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"shard\" value=\""
|
||||
<< (bs.block_id.is_valid() ? ton::shard_to_str(bs.block_id.id.shard) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>seqno</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"seqno\" value=\""
|
||||
<< (bs.block_id.is_valid() ? std::to_string(bs.block_id.id.seqno) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label class=\"d-none d-lg-block\"> </label>"
|
||||
<< "<div><button type=\"submit\" class=\"btn btn-primary mr-2\">Submit</button>"
|
||||
<< "<button class=\"btn btn-outline-primary\" type=\"reset\">Reset</button></div>"
|
||||
<< "</div></div><div class=\"row\">"
|
||||
<< "<div class=\"form-group col-md-6\">"
|
||||
<< "<label>root hash</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"roothash\" value=\""
|
||||
<< (!bs.block_id.id.is_valid() || bs.block_id.root_hash.is_zero() ? "" : bs.block_id.root_hash.to_hex())
|
||||
<< "\"></div>"
|
||||
<< "<div class=\"form-group col-md-6\">"
|
||||
<< "<label>file hash</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"filehash\" value=\""
|
||||
<< (!bs.block_id.id.is_valid() || bs.block_id.file_hash.is_zero() ? "" : bs.block_id.file_hash.to_hex())
|
||||
<< "\"></div>"
|
||||
<< "</div><div class=\"row\">"
|
||||
<< "<div class=\"form-group col-md-12\">"
|
||||
<< "<label>account id</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"account\" value=\""
|
||||
<< (bs.addr.addr.is_zero() ? "" : bs.addr.rserialize(true)) << "\"></div>"
|
||||
<< "</div>\n"
|
||||
<< "</form>\n";
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(TransactionSearch bs) {
|
||||
*this << "<form class=\"container\" action=\"" << prefix_ << "transaction\" method=\"get\">"
|
||||
<< "<div class=\"row\">"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>workchain</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"workchain\" value=\""
|
||||
<< (bs.block_id.is_valid() ? std::to_string(bs.block_id.id.workchain) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>shard</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"shard\" value=\""
|
||||
<< (bs.block_id.is_valid() ? ton::shard_to_str(bs.block_id.id.shard) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label>seqno</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"seqno\" value=\""
|
||||
<< (bs.block_id.is_valid() ? std::to_string(bs.block_id.id.seqno) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-lg-3 col-md-4\">"
|
||||
<< "<label class=\"d-none d-lg-block\"> </label>"
|
||||
<< "<div><button type=\"submit\" class=\"btn btn-primary mr-2\">Submit</button>"
|
||||
<< "<button class=\"btn btn-outline-primary\" type=\"reset\">Reset</button></div>"
|
||||
<< "</div></div><div class=\"row\">"
|
||||
<< "<div class=\"form-group col-md-6\">"
|
||||
<< "<label>root hash</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"roothash\" value=\""
|
||||
<< (!bs.block_id.id.is_valid() || bs.block_id.root_hash.is_zero() ? "" : bs.block_id.root_hash.to_hex())
|
||||
<< "\"></div>"
|
||||
<< "<div class=\"form-group col-md-6\">"
|
||||
<< "<label>file hash</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"filehash\" value=\""
|
||||
<< (!bs.block_id.id.is_valid() || bs.block_id.file_hash.is_zero() ? "" : bs.block_id.file_hash.to_hex())
|
||||
<< "\"></div>"
|
||||
<< "</div><div class=\"row\">"
|
||||
<< "<div class=\"form-group col-md-12\">"
|
||||
<< "<label>account id</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"account\" value=\""
|
||||
<< (bs.addr.addr.is_zero() ? "" : bs.addr.rserialize(true)) << "\"></div>"
|
||||
<< "</div><div class=\"row\">"
|
||||
<< "<div class=\"form-group col-md-3\">"
|
||||
<< "<label>transaction lt</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"lt\" value=\""
|
||||
<< (bs.lt ? std::to_string(bs.lt) : "") << "\"></div>"
|
||||
<< "<div class=\"form-group col-md-9\">"
|
||||
<< "<label>transaction hash</label>"
|
||||
<< "<input type =\"text\" class=\"form-control mr-2\" name=\"hash\" value=\""
|
||||
<< (bs.hash.is_zero() ? "" : bs.hash.to_hex()) << "\"></div>"
|
||||
<< "</div>\n"
|
||||
<< "</form>\n";
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(TransactionCell trans_c) {
|
||||
if (trans_c.root.is_null()) {
|
||||
abort("transaction not found");
|
||||
return *this;
|
||||
}
|
||||
block::gen::Transaction::Record trans;
|
||||
if (!tlb::unpack_cell(trans_c.root, trans)) {
|
||||
abort("cannot unpack");
|
||||
return *this;
|
||||
}
|
||||
*this << "<div class=\"table-responsive my-3\">\n"
|
||||
<< "<table class=\"table-sm table-striped\">\n"
|
||||
<< "<tr><th>block</th><td><a href=\"" << BlockLink{trans_c.block_id} << "\">"
|
||||
<< trans_c.block_id.id.to_str() << "</a></td></tr>"
|
||||
<< "<tr><th>workchain</th><td>" << trans_c.addr.workchain << "</td></tr>"
|
||||
<< "<tr><th>account hex</th><td>" << trans_c.addr.addr.to_hex() << "</td></tr>"
|
||||
<< "<tr><th>account</th><td>" << trans_c.addr.rserialize(true) << "</td></tr>"
|
||||
<< "<tr><th>hash</th><td>" << trans_c.root->get_hash().to_hex() << "</td></tr>\n"
|
||||
<< "<tr><th>lt</th><td>" << trans.lt << "</td></tr>\n"
|
||||
<< "<tr><th>time</th><td>" << trans.now << "</td></tr>\n"
|
||||
<< "<tr><th>out messages</th><td>";
|
||||
vm::Dictionary dict{trans.r1.out_msgs, 15};
|
||||
for (td::int32 i = 0; i < trans.outmsg_cnt; i++) {
|
||||
auto out_msg = dict.lookup_ref(td::BitArray<15>{i});
|
||||
*this << " <a href=\"" << MessageLink{out_msg} << "\">" << i << "</a>";
|
||||
}
|
||||
*this << "</td></tr>\n"
|
||||
<< "<tr><th>in message</th><td>";
|
||||
auto in_msg = trans.r1.in_msg->prefetch_ref();
|
||||
if (in_msg.is_null()) {
|
||||
*this << "NONE";
|
||||
} else {
|
||||
*this << "<a href=\"" << MessageLink{in_msg} << "\">" << in_msg->get_hash() << "</a>";
|
||||
}
|
||||
*this << "</td></tr>\n"
|
||||
<< "<tr><th>prev transaction</th><td>";
|
||||
|
||||
auto prev_lt = trans.prev_trans_lt;
|
||||
auto prev_hash = trans.prev_trans_hash;
|
||||
if (prev_lt > 0) {
|
||||
*this << "<a href=\"" << TransactionLink{trans_c.addr, prev_lt, prev_hash} << "\">lt=" << prev_lt
|
||||
<< " hash=" << prev_hash.to_hex() << "</a>";
|
||||
} else {
|
||||
*this << "NONE";
|
||||
}
|
||||
*this << "</td></tr></table></div>\n";
|
||||
if (in_msg.not_null()) {
|
||||
*this << "<hr />" << MessageCell{in_msg};
|
||||
}
|
||||
for (int x = 0; x < trans.outmsg_cnt && x < 100; x++) {
|
||||
auto out_msg = dict.lookup_ref(td::BitArray<15>{x});
|
||||
*this << "<hr />" << MessageCell{out_msg};
|
||||
}
|
||||
*this << "<hr />";
|
||||
|
||||
return *this << RawData<block::gen::Transaction>{trans_c.root} << "</div>";
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(AccountCell acc_c) {
|
||||
*this << "<div>";
|
||||
auto block_id = acc_c.block_id;
|
||||
if (!block_id.is_valid_full()) {
|
||||
abort(PSTRING() << "shard block id " << block_id.to_str() << " in answer is invalid");
|
||||
return *this;
|
||||
}
|
||||
if (!ton::shard_contains(block_id.shard_full(), ton::extract_addr_prefix(acc_c.addr.workchain, acc_c.addr.addr))) {
|
||||
abort(PSTRING() << "received data from shard block " << block_id.to_str()
|
||||
<< " that cannot contain requested account " << acc_c.addr.workchain << ":"
|
||||
<< acc_c.addr.addr.to_hex());
|
||||
return *this;
|
||||
}
|
||||
if (acc_c.q_roots.size() != 2) {
|
||||
abort(PSTRING() << "account state proof must have exactly two roots");
|
||||
return *this;
|
||||
}
|
||||
ton::LogicalTime last_trans_lt = 0;
|
||||
ton::Bits256 last_trans_hash;
|
||||
last_trans_hash.set_zero();
|
||||
try {
|
||||
auto state_root = vm::MerkleProof::virtualize(acc_c.q_roots[1], 1);
|
||||
if (state_root.is_null()) {
|
||||
abort("account state proof is invalid");
|
||||
return *this;
|
||||
}
|
||||
block::gen::ShardStateUnsplit::Record sstate;
|
||||
if (!(tlb::unpack_cell(std::move(state_root), sstate))) {
|
||||
abort("cannot unpack state header");
|
||||
return *this;
|
||||
}
|
||||
vm::AugmentedDictionary accounts_dict{vm::load_cell_slice_ref(sstate.accounts), 256, block::tlb::aug_ShardAccounts};
|
||||
auto acc_csr = accounts_dict.lookup(acc_c.addr.addr);
|
||||
if (acc_csr.not_null()) {
|
||||
if (acc_c.root.is_null()) {
|
||||
abort(PSTRING() << "account state proof shows that account state for " << acc_c.addr.workchain << ":"
|
||||
<< acc_c.addr.addr.to_hex() << " must be non-empty, but it actually is empty");
|
||||
return *this;
|
||||
}
|
||||
block::gen::ShardAccount::Record acc_info;
|
||||
if (!tlb::csr_unpack(std::move(acc_csr), acc_info)) {
|
||||
abort("cannot unpack ShardAccount from proof");
|
||||
return *this;
|
||||
}
|
||||
if (acc_info.account->get_hash().bits().compare(acc_c.root->get_hash().bits(), 256)) {
|
||||
abort(PSTRING() << "account state hash mismatch: Merkle proof expects "
|
||||
<< acc_info.account->get_hash().bits().to_hex(256) << " but received data has "
|
||||
<< acc_c.root->get_hash().bits().to_hex(256));
|
||||
return *this;
|
||||
}
|
||||
last_trans_hash = acc_info.last_trans_hash;
|
||||
last_trans_lt = acc_info.last_trans_lt;
|
||||
} else if (acc_c.root.not_null()) {
|
||||
abort(PSTRING() << "account state proof shows that account state for " << acc_c.addr.workchain << ":"
|
||||
<< acc_c.addr.addr.to_hex() << " must be empty, but it is not");
|
||||
return *this;
|
||||
}
|
||||
} catch (vm::VmError err) {
|
||||
abort(PSTRING() << "error while traversing account proof : " << err.get_msg());
|
||||
return *this;
|
||||
} catch (vm::VmVirtError err) {
|
||||
abort(PSTRING() << "virtualization error while traversing account proof : " << err.get_msg());
|
||||
return *this;
|
||||
}
|
||||
|
||||
*this << "<div class=\"table-responsive my-3\">\n"
|
||||
<< "<table class=\"table-sm table-striped\">\n";
|
||||
*this << "<tr><th>block</th><td><a href=\"" << BlockLink{acc_c.block_id} << "\">"
|
||||
<< block_id.id.to_str() << "</a></td></tr>";
|
||||
*this << "<tr><th>workchain</th><td>" << acc_c.addr.workchain << "</td></tr>";
|
||||
*this << "<tr><th>account hex</th><td>" << acc_c.addr.addr.to_hex() << "</td></tr>";
|
||||
*this << "<tr><th>account</th><td>" << acc_c.addr.rserialize(true) << "</td></tr>";
|
||||
if (last_trans_lt > 0) {
|
||||
*this << "<tr><th>last transaction</th><td>"
|
||||
<< "<a href=\"" << TransactionLink{acc_c.addr, last_trans_lt, last_trans_hash} << "\">lt=" << last_trans_lt
|
||||
<< " hash=" << last_trans_hash.to_hex() << "</a></td></tr>\n";
|
||||
} else {
|
||||
*this << "<tr><th>last transaction</th><td>no transactions</td></tr>";
|
||||
}
|
||||
*this << "</table></div>\n";
|
||||
|
||||
*this << "<p><a class=\"btn btn-primary\" href=\"" << prefix_ << "account?account=" << acc_c.addr.rserialize(true)
|
||||
<< "\">go to current state</a></p>\n";
|
||||
|
||||
if (acc_c.root.not_null()) {
|
||||
*this << RawData<block::gen::Account>{acc_c.root};
|
||||
} else {
|
||||
*this << "<div class=\"alert alert-info\">account state is empty</div>";
|
||||
}
|
||||
return *this << "</div>";
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(BlockHeaderCell head_c) {
|
||||
*this << "<div>";
|
||||
vm::CellSlice cs{vm::NoVm{}, head_c.root};
|
||||
auto block_id = head_c.block_id;
|
||||
try {
|
||||
auto virt_root = vm::MerkleProof::virtualize(head_c.root, 1);
|
||||
if (virt_root.is_null()) {
|
||||
abort("invalid merkle proof");
|
||||
return *this;
|
||||
}
|
||||
ton::RootHash vhash{virt_root->get_hash().bits()};
|
||||
std::vector<ton::BlockIdExt> prev;
|
||||
ton::BlockIdExt mc_blkid;
|
||||
bool after_split;
|
||||
auto res = block::unpack_block_prev_blk_ext(virt_root, block_id, prev, mc_blkid, after_split);
|
||||
if (res.is_error()) {
|
||||
abort(PSTRING() << "cannot unpack header for block " << block_id.to_str() << ": " << res);
|
||||
return *this;
|
||||
}
|
||||
block::gen::Block::Record blk;
|
||||
block::gen::BlockInfo::Record info;
|
||||
if (!(tlb::unpack_cell(virt_root, blk) && tlb::unpack_cell(blk.info, info))) {
|
||||
abort(PSTRING() << "cannot unpack header for block " << block_id.to_str());
|
||||
return *this;
|
||||
}
|
||||
bool before_split = info.before_split;
|
||||
*this << "<div class=\"table-responsive my-3\">\n"
|
||||
<< "<table class=\"table-sm table-striped\">\n"
|
||||
<< "<tr><th>block</th><td>" << block_id.id.to_str() << "</td></tr>\n"
|
||||
<< "<tr><th>roothash</th><td>" << block_id.root_hash.to_hex() << "</td></tr>\n"
|
||||
<< "<tr><th>filehash</th><td>" << block_id.file_hash.to_hex() << "</td></tr>\n"
|
||||
<< "<tr><th>time</th><td>" << info.gen_utime << "</td></tr>\n"
|
||||
<< "<tr><th>lt</th><td>" << info.start_lt << " .. " << info.end_lt
|
||||
<< "</td></tr>\n"
|
||||
<< "<tr><th>global_id</th><td>" << blk.global_id << "</td></tr>\n"
|
||||
<< "<tr><th>version</th><td>" << info.version << "</td></tr>\n"
|
||||
<< "<tr><th>not_master</th><td>" << info.not_master << "</td></tr>\n"
|
||||
<< "<tr><th>after_merge</th><td>" << info.after_merge << "</td></tr>\n"
|
||||
<< "<tr><th>after_split</th><td>" << info.after_split << "</td></tr>\n"
|
||||
<< "<tr><th>before_split</th><td>" << info.before_split << "</td></tr>\n"
|
||||
<< "<tr><th>want_merge</th><td>" << info.want_merge << "</td></tr>\n"
|
||||
<< "<tr><th>want_split</th><td>" << info.want_split << "</td></tr>\n"
|
||||
<< "<tr><th>validator_list_hash_short</th><td>"
|
||||
<< info.gen_validator_list_hash_short << "</td></tr>\n"
|
||||
<< "<tr><th>catchain_seqno</th><td>" << info.gen_catchain_seqno << "</td></tr>\n"
|
||||
<< "<tr><th>min_ref_mc_seqno</th><td>" << info.min_ref_mc_seqno
|
||||
<< "</td></tr>\n";
|
||||
for (auto id : prev) {
|
||||
*this << "<tr><th>prev block</th><td>" << id << "</td></tr>\n";
|
||||
}
|
||||
if (!before_split) {
|
||||
*this << "<tr><th>next block</th><td>"
|
||||
<< ton::BlockId{block_id.id.workchain, block_id.id.shard, block_id.id.seqno + 1} << "</td></tr>\n";
|
||||
} else {
|
||||
*this << "<tr><th>next block</th><td>"
|
||||
<< ton::BlockId{block_id.id.workchain, ton::shard_child(block_id.id.shard, true), block_id.id.seqno + 1}
|
||||
<< "</td></tr>\n";
|
||||
*this << "<tr><th>next block</th><td>"
|
||||
<< ton::BlockId{block_id.id.workchain, ton::shard_child(block_id.id.shard, false), block_id.id.seqno + 1}
|
||||
<< "</td></tr>\n";
|
||||
}
|
||||
*this << "<tr><th>masterchain block</th><td>" << mc_blkid << "</td></tr>\n"
|
||||
<< "</table></div>";
|
||||
} catch (vm::VmError err) {
|
||||
abort(PSTRING() << "error processing header : " << err.get_msg());
|
||||
return *this;
|
||||
} catch (vm::VmVirtError err) {
|
||||
abort(PSTRING() << "error processing header : " << err.get_msg());
|
||||
return *this;
|
||||
}
|
||||
|
||||
return *this << "<p><a class=\"btn btn-primary mr-2\" href=\"" << BlockDownloadLink{block_id} << "\" download=\""
|
||||
<< block_id.file_hash << ".boc\">download block</a>"
|
||||
<< "<a class=\"btn btn-primary\" href=\"" << BlockViewLink{block_id} << "\">view block</a>\n"
|
||||
<< "</p></div>";
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(BlockShardsCell shards_c) {
|
||||
block::ShardConfig sh_conf;
|
||||
if (!sh_conf.unpack(vm::load_cell_slice_ref(shards_c.root))) {
|
||||
abort("cannot extract shard block list from shard configuration");
|
||||
return *this;
|
||||
} else {
|
||||
auto ids = sh_conf.get_shard_hash_ids(true);
|
||||
|
||||
auto workchain = ton::masterchainId;
|
||||
*this << "<div class=\"table-responsive my-3\">\n"
|
||||
<< "<table class=\"table\">\n<tbody>\n"
|
||||
<< "<thead>\n"
|
||||
<< "<tr>\n"
|
||||
<< "<th scope=\"col\">shard</th>"
|
||||
<< "<th scope=\"col\">seqno</th>"
|
||||
<< "<th scope=\"col\">created</th>"
|
||||
<< "<th scope=\"col\">wantsplit</th>"
|
||||
<< "<th scope=\"col\">wantmerge</th>"
|
||||
<< "<th scope=\"col\">beforesplit</th>"
|
||||
<< "<th scope=\"col\">beforemerge</th>"
|
||||
<< "</tr>\n"
|
||||
<< "</thead>\n";
|
||||
for (auto id : ids) {
|
||||
auto ref = sh_conf.get_shard_hash(ton::ShardIdFull(id));
|
||||
|
||||
if (id.workchain != workchain) {
|
||||
if (workchain != ton::masterchainId) {
|
||||
*this << "<tr></tr>\n";
|
||||
}
|
||||
workchain = id.workchain;
|
||||
}
|
||||
*this << "<tr>";
|
||||
ton::ShardIdFull shard{id.workchain, id.shard};
|
||||
if (ref.not_null()) {
|
||||
*this << "<td>" << shard.to_str() << "</td><td><a href=\"" << HttpAnswer::BlockLink{ref->top_block_id()}
|
||||
<< "\">" << ref->top_block_id().id.seqno << "</a></td><td>" << ref->created_at() << "</td>"
|
||||
<< "<td>" << ref->want_split_ << "</td>"
|
||||
<< "<td>" << ref->want_merge_ << "</td>"
|
||||
<< "<td>" << ref->before_split_ << "</td>"
|
||||
<< "<td>" << ref->before_merge_ << "</td>";
|
||||
} else {
|
||||
*this << "<td>" << shard.to_str() << "</td>";
|
||||
}
|
||||
*this << "</tr>";
|
||||
}
|
||||
return *this << "</tbody></table></div>";
|
||||
}
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(AccountLink account) {
|
||||
*this << prefix_ << "account?";
|
||||
if (account.block_id.is_valid()) {
|
||||
block_id_link(account.block_id);
|
||||
*this << "&";
|
||||
}
|
||||
return *this << "account=" << account.account_id.rserialize(true);
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(MessageLink msg) {
|
||||
return *this << "#msg" << msg.root->get_hash();
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(TransactionLink trans) {
|
||||
return *this << prefix_ << "transaction?"
|
||||
<< "account=" << trans.account_id.rserialize(true) << "<=" << trans.lt << "&hash=" << trans.hash;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(TransactionLinkShort trans) {
|
||||
*this << prefix_ << "transaction2?";
|
||||
block_id_link(trans.block_id);
|
||||
return *this << "&account=" << trans.account_id.rserialize(true) << "<=" << trans.lt;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(BlockLink block) {
|
||||
*this << prefix_ << "block?";
|
||||
block_id_link(block.block_id);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(BlockViewLink block) {
|
||||
*this << prefix_ << "viewblock?";
|
||||
block_id_link(block.block_id);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(BlockDownloadLink block) {
|
||||
*this << prefix_ << "download?";
|
||||
block_id_link(block.block_id);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(TransactionList trans) {
|
||||
*this << "<div class=\"table-responsive my-3\">\n"
|
||||
<< "<table class=\"table\">\n<tbody>\n"
|
||||
<< "<thead>\n"
|
||||
<< "<tr>\n"
|
||||
<< "<th scope=\"col\">seq</th>"
|
||||
<< "<th scope=\"col\">account</th>"
|
||||
<< "<th scope=\"col\">lt</th>"
|
||||
<< "<th scope=\"col\">hash</th>"
|
||||
<< "<th scope=\"col\">link</th>"
|
||||
<< "</tr>\n"
|
||||
<< "</thead>\n";
|
||||
td::uint32 idx = 0;
|
||||
for (auto& x : trans.vec) {
|
||||
*this << "<tr><td><a href=\"" << TransactionLink{x.addr, x.lt, x.hash} << "\">" << ++idx << "</a></td>"
|
||||
<< "<td><a href=\"" << AccountLink{x.addr, trans.block_id} << "\">" << x.addr.rserialize(true) << "</a></td>"
|
||||
<< "<td>" << x.lt << "</td>"
|
||||
<< "<td>" << x.hash.to_hex() << "</td>"
|
||||
<< "<td><a href=\"" << TransactionLink{x.addr, x.lt, x.hash} << "\">view</a></td></tr>";
|
||||
}
|
||||
if (trans.vec.size() == trans.req_count_) {
|
||||
*this << "<tr><td>" << ++idx << "</td>"
|
||||
<< "<td>more</td>"
|
||||
<< "<td>more</td>"
|
||||
<< "<td>more</td></tr>";
|
||||
}
|
||||
return *this << "</tbody></table></div>";
|
||||
}
|
||||
|
||||
HttpAnswer& HttpAnswer::operator<<(Error error) {
|
||||
return *this << "<div class=\"alert alert-danger\">" << error.error.to_string() << "</div>";
|
||||
}
|
||||
|
||||
void HttpAnswer::block_id_link(ton::BlockIdExt block_id) {
|
||||
*this << "workchain=" << block_id.id.workchain << "&shard=" << ton::shard_to_str(block_id.id.shard)
|
||||
<< "&seqno=" << block_id.id.seqno << "&roothash=" << block_id.root_hash << "&filehash=" << block_id.file_hash;
|
||||
}
|
||||
|
||||
std::string HttpAnswer::abort(td::Status error) {
|
||||
if (error_.is_ok()) {
|
||||
error_ = std::move(error);
|
||||
}
|
||||
return header() + "<div class=\"alert alert-danger\">" + error_.to_string() + "</div>" + footer();
|
||||
}
|
||||
|
||||
std::string HttpAnswer::abort(std::string error) {
|
||||
return abort(td::Status::Error(404, error));
|
||||
}
|
||||
|
||||
std::string HttpAnswer::header() {
|
||||
sb_->clear();
|
||||
*this << "<!DOCTYPE html>\n"
|
||||
<< "<html lang=\"en\"><head><meta charset=\"utf-8\"><title>" << title_ << "</title>\n"
|
||||
<< "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" />\n"
|
||||
<< "<meta name=\"format-detection\" content=\"telephone=no\" />\n"
|
||||
<< "<!-- Latest compiled and minified CSS -->\n"
|
||||
<< "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">\n"
|
||||
<< "<!-- jQuery library -->"
|
||||
<< "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js\"></script>\n"
|
||||
<< "<!-- Popper JS -->\n"
|
||||
<< "<script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js\"></script>\n"
|
||||
<< "<!-- Latest compiled JavaScript -->\n"
|
||||
<< "<script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js\"></script>\n"
|
||||
<< "</head><body>\n"
|
||||
<< "<div class=\"container-fluid\">\n"
|
||||
<< "<nav class=\"navbar navbar-expand px-0 mt-1 flex-wrap\">\n"
|
||||
<< "<ul class=\"navbar-nav ml-1 mr-5 my-1\">\n"
|
||||
<< "<li class=\"nav-item\"><a class=\"nav-link\" href=\"" << prefix_ << "status\">status</a></li>\n"
|
||||
<< "<li class=\"nav-item\"><a class=\"nav-link\" href=\"" << prefix_ << "last\">last</a></li>\n"
|
||||
<< "</ul>";
|
||||
*this << "<form class=\"my-1 my-lg-0 flex-grow-1\" action=\"" << prefix_ << "account\" method=\"get\">"
|
||||
<< "<div class=\"input-group ml-auto\" style=\"max-width:540px;\">"
|
||||
<< "<input class=\"form-control mr-2 rounded\" type=\"search\" placeholder=\"account\" aria-label=\"account\" "
|
||||
<< "name=\"account\">";
|
||||
*this << "<div class=\"input-group-append\"><button class=\"btn btn-outline-primary rounded\" type=\"submit\">view</button></div>"
|
||||
<< "</div></form>"
|
||||
<< "</nav>\n";
|
||||
|
||||
*this << "<p>\n"
|
||||
<< "<a class=\"btn btn-primary mt-1\" data-toggle=\"collapse\" href=\"#blocksearch\" role=\"button\" "
|
||||
"aria-expanded=\"false\" aria-controls=\"blocksearch\">\n"
|
||||
<< "Search block\n"
|
||||
<< "</a>\n"
|
||||
<< "<a class=\"btn btn-primary mt-1\" data-toggle=\"collapse\" href=\"#accountsearch\" role=\"button\" "
|
||||
"aria-expanded=\"false\" aria-controls=\"accountsearch\">\n"
|
||||
<< "Search account\n"
|
||||
<< "</a>\n"
|
||||
<< "<a class=\"btn btn-primary mt-1\" data-toggle=\"collapse\" href=\"#transactionsearch\" role=\"button\" "
|
||||
"aria-expanded=\"false\" aria-controls=\"transactionsearch\">\n"
|
||||
<< "Search transaction\n"
|
||||
<< "</a>\n"
|
||||
<< "</p>\n";
|
||||
|
||||
*this << "<div id=\"searchgroup\">\n"
|
||||
<< "<div class=\"collapse\" data-parent=\"#searchgroup\" id=\"blocksearch\">\n"
|
||||
<< "<div class=\"card card-body\">\n"
|
||||
<< BlockSearch{block_id_} << "</div></div>\n";
|
||||
*this << "<div class=\"collapse\" data-parent=\"#searchgroup\" id=\"accountsearch\">\n"
|
||||
<< "<div class=\"card card-body\">\n"
|
||||
<< AccountSearch{block_id_, account_id_} << "</div></div>\n";
|
||||
*this << "<div class=\"collapse\" data-parent=\"#searchgroup\" id=\"transactionsearch\">\n"
|
||||
<< "<div class=\"card card-body\">\n"
|
||||
<< TransactionSearch{block_id_, account_id_, 0, ton::Bits256::zero()} << "</div></div></div>\n";
|
||||
|
||||
return sb_->as_cslice().c_str();
|
||||
}
|
||||
|
||||
std::string HttpAnswer::footer() {
|
||||
return PSTRING() << "</div></body></html>";
|
||||
}
|
||||
|
||||
std::string HttpAnswer::finish() {
|
||||
if (error_.is_ok()) {
|
||||
std::string data = sb_->as_cslice().c_str();
|
||||
return header() + data + footer();
|
||||
} else {
|
||||
return header() + "<div class=\"alert alert-danger\">" + error_.to_string() + "</div>" + footer();
|
||||
}
|
||||
}
|
222
blockchain-explorer/blockchain-explorer-http.hpp
Normal file
222
blockchain-explorer/blockchain-explorer-http.hpp
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ton/ton-types.h"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cellops.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "block/block.h"
|
||||
|
||||
class HttpAnswer {
|
||||
public:
|
||||
struct MessageCell {
|
||||
td::Ref<vm::Cell> root;
|
||||
};
|
||||
struct AddressCell {
|
||||
td::Ref<vm::CellSlice> root;
|
||||
};
|
||||
struct TransactionCell {
|
||||
block::StdAddress addr;
|
||||
ton::BlockIdExt block_id;
|
||||
td::Ref<vm::Cell> root;
|
||||
};
|
||||
struct AccountCell {
|
||||
block::StdAddress addr;
|
||||
ton::BlockIdExt block_id;
|
||||
td::Ref<vm::Cell> root;
|
||||
std::vector<td::Ref<vm::Cell>> q_roots;
|
||||
};
|
||||
struct BlockHeaderCell {
|
||||
ton::BlockIdExt block_id;
|
||||
td::Ref<vm::Cell> root;
|
||||
};
|
||||
struct BlockShardsCell {
|
||||
ton::BlockIdExt block_id;
|
||||
td::Ref<vm::Cell> root;
|
||||
};
|
||||
|
||||
struct AccountLink {
|
||||
block::StdAddress account_id;
|
||||
ton::BlockIdExt block_id;
|
||||
};
|
||||
struct MessageLink {
|
||||
td::Ref<vm::Cell> root;
|
||||
};
|
||||
struct TransactionLink {
|
||||
block::StdAddress account_id;
|
||||
ton::LogicalTime lt;
|
||||
ton::Bits256 hash;
|
||||
};
|
||||
struct TransactionLinkShort {
|
||||
ton::BlockIdExt block_id;
|
||||
block::StdAddress account_id;
|
||||
ton::LogicalTime lt;
|
||||
};
|
||||
struct BlockLink {
|
||||
ton::BlockIdExt block_id;
|
||||
};
|
||||
struct BlockViewLink {
|
||||
ton::BlockIdExt block_id;
|
||||
};
|
||||
struct BlockDownloadLink {
|
||||
ton::BlockIdExt block_id;
|
||||
};
|
||||
struct BlockSearch {
|
||||
ton::BlockIdExt block_id;
|
||||
};
|
||||
struct AccountSearch {
|
||||
ton::BlockIdExt block_id;
|
||||
block::StdAddress addr;
|
||||
};
|
||||
struct TransactionSearch {
|
||||
ton::BlockIdExt block_id;
|
||||
block::StdAddress addr;
|
||||
ton::LogicalTime lt;
|
||||
ton::Bits256 hash;
|
||||
};
|
||||
struct TransactionList {
|
||||
struct TransactionDescr {
|
||||
TransactionDescr(block::StdAddress addr, ton::LogicalTime lt, ton::Bits256 hash)
|
||||
: addr(addr), lt(lt), hash(hash) {
|
||||
}
|
||||
block::StdAddress addr;
|
||||
ton::LogicalTime lt;
|
||||
ton::Bits256 hash;
|
||||
};
|
||||
ton::BlockIdExt block_id;
|
||||
std::vector<TransactionDescr> vec;
|
||||
td::uint32 req_count_;
|
||||
};
|
||||
struct CodeBlock {
|
||||
std::string data;
|
||||
};
|
||||
struct Error {
|
||||
td::Status error;
|
||||
};
|
||||
template <class T>
|
||||
struct RawData {
|
||||
td::Ref<vm::Cell> root;
|
||||
T x;
|
||||
template <typename... Args>
|
||||
RawData(td::Ref<vm::Cell> root, Args &&... args) : root(std::move(root)), x(std::forward<Args>(args)...) {
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
HttpAnswer(std::string title, std::string prefix) : title_(title), prefix_(prefix) {
|
||||
buf_ = td::BufferSlice{1 << 28};
|
||||
sb_ = std::make_unique<td::StringBuilder>(buf_.as_slice());
|
||||
}
|
||||
|
||||
void set_title(std::string title) {
|
||||
title_ = title;
|
||||
}
|
||||
void set_block_id(ton::BlockIdExt block_id) {
|
||||
block_id_ = block_id;
|
||||
workchain_id_ = block_id_.id.workchain;
|
||||
}
|
||||
void set_account_id(block::StdAddress addr) {
|
||||
account_id_ = addr;
|
||||
}
|
||||
void set_workchain(ton::WorkchainId workchain_id) {
|
||||
workchain_id_ = workchain_id;
|
||||
}
|
||||
|
||||
std::string abort(td::Status error);
|
||||
std::string abort(std::string error);
|
||||
|
||||
std::string finish();
|
||||
std::string header();
|
||||
std::string footer();
|
||||
|
||||
template <typename T>
|
||||
HttpAnswer &operator<<(T x) {
|
||||
sb() << x;
|
||||
return *this;
|
||||
}
|
||||
td::StringBuilder &sb() {
|
||||
return *sb_;
|
||||
}
|
||||
HttpAnswer &operator<<(td::Bits256 x) {
|
||||
sb() << x.to_hex();
|
||||
return *this;
|
||||
}
|
||||
HttpAnswer &operator<<(td::BitString x) {
|
||||
sb() << x.to_hex();
|
||||
return *this;
|
||||
}
|
||||
HttpAnswer &operator<<(AddressCell addr);
|
||||
HttpAnswer &operator<<(MessageCell msg);
|
||||
HttpAnswer &operator<<(ton::BlockIdExt block_id);
|
||||
HttpAnswer &operator<<(ton::BlockId block_id);
|
||||
HttpAnswer &operator<<(TransactionCell trans);
|
||||
HttpAnswer &operator<<(AccountCell trans);
|
||||
HttpAnswer &operator<<(BlockHeaderCell head);
|
||||
HttpAnswer &operator<<(BlockShardsCell shards);
|
||||
HttpAnswer &operator<<(BlockSearch head);
|
||||
HttpAnswer &operator<<(AccountSearch head);
|
||||
HttpAnswer &operator<<(TransactionSearch head);
|
||||
|
||||
HttpAnswer &operator<<(AccountLink account);
|
||||
HttpAnswer &operator<<(MessageLink msg);
|
||||
HttpAnswer &operator<<(TransactionLink trans);
|
||||
HttpAnswer &operator<<(TransactionLinkShort trans);
|
||||
HttpAnswer &operator<<(BlockLink block);
|
||||
HttpAnswer &operator<<(BlockViewLink block);
|
||||
HttpAnswer &operator<<(BlockDownloadLink block);
|
||||
|
||||
HttpAnswer &operator<<(Error error);
|
||||
|
||||
HttpAnswer &operator<<(TransactionList trans);
|
||||
HttpAnswer &operator<<(CodeBlock block) {
|
||||
return *this << "<pre><code>" << block.data << "</code></pre>";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
HttpAnswer &operator<<(RawData<T> data) {
|
||||
std::ostringstream outp;
|
||||
data.x.print_ref(outp, data.root);
|
||||
vm::load_cell_slice(data.root).print_rec(outp);
|
||||
return *this << CodeBlock{outp.str()};
|
||||
}
|
||||
|
||||
private:
|
||||
void block_id_link(ton::BlockIdExt block_id);
|
||||
|
||||
std::string title_;
|
||||
ton::BlockIdExt block_id_;
|
||||
ton::WorkchainId workchain_id_ = ton::workchainInvalid;
|
||||
block::StdAddress account_id_;
|
||||
|
||||
std::string prefix_;
|
||||
td::Status error_;
|
||||
|
||||
std::unique_ptr<td::StringBuilder> sb_;
|
||||
td::BufferSlice buf_;
|
||||
};
|
1029
blockchain-explorer/blockchain-explorer-query.cpp
Normal file
1029
blockchain-explorer/blockchain-explorer-query.cpp
Normal file
File diff suppressed because it is too large
Load diff
274
blockchain-explorer/blockchain-explorer-query.hpp
Normal file
274
blockchain-explorer/blockchain-explorer-query.hpp
Normal file
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "block/block.h"
|
||||
#include "blockchain-explorer.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <microhttpd.h>
|
||||
|
||||
td::Result<ton::BlockIdExt> parse_block_id(std::map<std::string, std::string> &opts, bool allow_empty = false);
|
||||
td::Result<block::StdAddress> parse_account_addr(std::map<std::string, std::string> &opts);
|
||||
|
||||
class HttpAnswer;
|
||||
|
||||
class HttpQueryCommon : public td::actor::Actor {
|
||||
public:
|
||||
HttpQueryCommon(std::string prefix, td::Promise<MHD_Response *> promise)
|
||||
: prefix_(std::move(prefix)), promise_(std::move(promise)) {
|
||||
}
|
||||
void start_up() override {
|
||||
if (error_.is_error()) {
|
||||
abort_query(std::move(error_));
|
||||
return;
|
||||
}
|
||||
start_up_query();
|
||||
}
|
||||
virtual void start_up_query() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
virtual void abort_query(td::Status error);
|
||||
void create_header(HttpAnswer &ans) {
|
||||
}
|
||||
|
||||
protected:
|
||||
td::Status error_;
|
||||
|
||||
std::string prefix_;
|
||||
td::Promise<MHD_Response *> promise_;
|
||||
};
|
||||
|
||||
class HttpQueryBlockData : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryBlockData(ton::BlockIdExt block_id, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryBlockData(std::map<std::string, std::string> opts, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
|
||||
void abort_query(td::Status error) override;
|
||||
void finish_query();
|
||||
|
||||
void start_up() override;
|
||||
void got_block_data(td::BufferSlice result);
|
||||
|
||||
private:
|
||||
ton::BlockIdExt block_id_;
|
||||
|
||||
td::BufferSlice data_;
|
||||
};
|
||||
|
||||
class HttpQueryBlockView : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryBlockView(ton::BlockIdExt block_id, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryBlockView(std::map<std::string, std::string> opts, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up_query() override;
|
||||
void got_block_data(td::BufferSlice result);
|
||||
|
||||
private:
|
||||
ton::BlockIdExt block_id_;
|
||||
|
||||
td::BufferSlice data_;
|
||||
};
|
||||
|
||||
class HttpQueryBlockInfo : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryBlockInfo(ton::BlockIdExt block_id, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryBlockInfo(std::map<std::string, std::string> opts, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up_query() override;
|
||||
void got_block_header(td::BufferSlice result);
|
||||
void got_shard_info(td::BufferSlice result);
|
||||
void got_transactions(td::BufferSlice result);
|
||||
|
||||
void failed_to_get_shard_info(td::Status error);
|
||||
|
||||
private:
|
||||
ton::BlockIdExt block_id_;
|
||||
|
||||
td::int32 pending_queries_ = 0;
|
||||
|
||||
td::BufferSlice data_;
|
||||
td::BufferSlice shard_data_;
|
||||
td::Status shard_data_error_;
|
||||
|
||||
struct TransactionDescr {
|
||||
TransactionDescr(block::StdAddress addr, ton::LogicalTime lt, ton::Bits256 hash) : addr(addr), lt(lt), hash(hash) {
|
||||
}
|
||||
block::StdAddress addr;
|
||||
ton::LogicalTime lt;
|
||||
ton::Bits256 hash;
|
||||
};
|
||||
std::vector<TransactionDescr> transactions_;
|
||||
td::uint32 trans_req_count_;
|
||||
};
|
||||
|
||||
class HttpQueryBlockSearch : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryBlockSearch(ton::WorkchainId workchain, ton::AccountIdPrefix account, ton::BlockSeqno seqno,
|
||||
std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryBlockSearch(ton::WorkchainId workchain, ton::AccountIdPrefix account, ton::LogicalTime lt,
|
||||
std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryBlockSearch(ton::WorkchainId workchain, ton::AccountIdPrefix account, bool dummy, ton::UnixTime utime,
|
||||
std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryBlockSearch(std::map<std::string, std::string> opts, std::string prefix,
|
||||
td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up_query() override;
|
||||
void got_block_header(td::BufferSlice result);
|
||||
void got_shard_info(td::BufferSlice result);
|
||||
void got_transactions(td::BufferSlice result);
|
||||
|
||||
void failed_to_get_shard_info(td::Status error);
|
||||
|
||||
private:
|
||||
ton::AccountIdPrefixFull account_prefix_;
|
||||
td::uint32 mode_ = 0;
|
||||
ton::BlockSeqno seqno_ = 0;
|
||||
ton::LogicalTime lt_ = 0;
|
||||
ton::UnixTime utime_ = 0;
|
||||
|
||||
ton::BlockIdExt block_id_;
|
||||
|
||||
td::BufferSlice data_;
|
||||
td::BufferSlice shard_data_;
|
||||
td::Status shard_data_error_;
|
||||
|
||||
td::uint32 pending_queries_ = 0;
|
||||
|
||||
struct TransactionDescr {
|
||||
TransactionDescr(block::StdAddress addr, ton::LogicalTime lt, ton::Bits256 hash) : addr(addr), lt(lt), hash(hash) {
|
||||
}
|
||||
block::StdAddress addr;
|
||||
ton::LogicalTime lt;
|
||||
ton::Bits256 hash;
|
||||
};
|
||||
std::vector<TransactionDescr> transactions_;
|
||||
td::uint32 trans_req_count_;
|
||||
};
|
||||
|
||||
class HttpQueryViewAccount : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryViewAccount(ton::BlockIdExt block_id, block::StdAddress addr, std::string prefix,
|
||||
td::Promise<MHD_Response *> promise);
|
||||
HttpQueryViewAccount(std::map<std::string, std::string> opts, std::string prefix,
|
||||
td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up_query() override;
|
||||
void got_account(td::BufferSlice result);
|
||||
|
||||
private:
|
||||
ton::BlockIdExt block_id_;
|
||||
block::StdAddress addr_;
|
||||
|
||||
td::BufferSlice data_;
|
||||
td::BufferSlice proof_;
|
||||
ton::BlockIdExt res_block_id_;
|
||||
};
|
||||
|
||||
class HttpQueryViewTransaction : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryViewTransaction(block::StdAddress addr, ton::LogicalTime lt, ton::Bits256 hash, std::string prefix,
|
||||
td::Promise<MHD_Response *> promise);
|
||||
HttpQueryViewTransaction(std::map<std::string, std::string> opts, std::string prefix,
|
||||
td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up_query() override;
|
||||
void got_transaction(td::BufferSlice result);
|
||||
|
||||
private:
|
||||
block::StdAddress addr_;
|
||||
ton::LogicalTime lt_;
|
||||
ton::Bits256 hash_;
|
||||
|
||||
td::BufferSlice data_;
|
||||
ton::BlockIdExt res_block_id_;
|
||||
};
|
||||
|
||||
class HttpQueryViewTransaction2 : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryViewTransaction2(ton::BlockIdExt block_id, block::StdAddress addr, ton::LogicalTime lt, std::string prefix,
|
||||
td::Promise<MHD_Response *> promise);
|
||||
HttpQueryViewTransaction2(std::map<std::string, std::string> opts, std::string prefix,
|
||||
td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up_query() override;
|
||||
void got_transaction(td::BufferSlice result);
|
||||
|
||||
private:
|
||||
ton::BlockIdExt block_id_;
|
||||
block::StdAddress addr_;
|
||||
ton::LogicalTime lt_;
|
||||
ton::Bits256 hash_;
|
||||
|
||||
td::BufferSlice data_;
|
||||
};
|
||||
|
||||
class HttpQueryViewLastBlock : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryViewLastBlock(std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryViewLastBlock(std::map<std::string, std::string> opts, std::string prefix,
|
||||
td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up() override;
|
||||
void got_result(td::BufferSlice result);
|
||||
|
||||
private:
|
||||
ton::BlockIdExt res_block_id_;
|
||||
};
|
||||
|
||||
class HttpQueryStatus : public HttpQueryCommon {
|
||||
public:
|
||||
HttpQueryStatus(std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
HttpQueryStatus(std::map<std::string, std::string> opts, std::string prefix, td::Promise<MHD_Response *> promise);
|
||||
|
||||
void finish_query();
|
||||
|
||||
void start_up() override;
|
||||
void got_results(CoreActorInterface::RemoteNodeStatusList results);
|
||||
|
||||
private:
|
||||
CoreActorInterface::RemoteNodeStatusList results_;
|
||||
};
|
||||
|
582
blockchain-explorer/blockchain-explorer.cpp
Normal file
582
blockchain-explorer/blockchain-explorer.cpp
Normal file
|
@ -0,0 +1,582 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "adnl/adnl-ext-client.h"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "auto/tl/ton_api_json.h"
|
||||
#include "td/utils/OptionsParser.h"
|
||||
#include "td/utils/Time.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/port/signals.h"
|
||||
#include "td/utils/port/user.h"
|
||||
#include "td/utils/port/FileFd.h"
|
||||
#include "ton/ton-tl.hpp"
|
||||
#include "block/block-db.h"
|
||||
#include "block/block.h"
|
||||
#include "block/block-auto.h"
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cellops.h"
|
||||
#include "vm/cells/MerkleProof.h"
|
||||
#include "block/mc-config.h"
|
||||
#include "blockchain-explorer.hpp"
|
||||
#include "blockchain-explorer-http.hpp"
|
||||
#include "blockchain-explorer-query.hpp"
|
||||
|
||||
#include "auto/tl/lite_api.h"
|
||||
#include "ton/lite-tl.hpp"
|
||||
#include "tl-utils/lite-utils.hpp"
|
||||
|
||||
#include <microhttpd.h>
|
||||
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
int verbosity;
|
||||
|
||||
td::actor::Scheduler* scheduler_ptr;
|
||||
|
||||
static std::string urldecode(td::Slice from, bool decode_plus_sign_as_space) {
|
||||
size_t to_i = 0;
|
||||
|
||||
td::BufferSlice x{from.size()};
|
||||
auto to = x.as_slice();
|
||||
|
||||
for (size_t from_i = 0, n = from.size(); from_i < n; from_i++) {
|
||||
if (from[from_i] == '%' && from_i + 2 < n) {
|
||||
int high = td::hex_to_int(from[from_i + 1]);
|
||||
int low = td::hex_to_int(from[from_i + 2]);
|
||||
if (high < 16 && low < 16) {
|
||||
to[to_i++] = static_cast<char>(high * 16 + low);
|
||||
from_i += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
to[to_i++] = decode_plus_sign_as_space && from[from_i] == '+' ? ' ' : from[from_i];
|
||||
}
|
||||
|
||||
return to.truncate(to_i).str();
|
||||
}
|
||||
|
||||
class HttpQueryRunner {
|
||||
public:
|
||||
HttpQueryRunner(std::function<void(td::Promise<MHD_Response*>)> func) {
|
||||
auto P = td::PromiseCreator::lambda([Self = this](td::Result<MHD_Response*> R) {
|
||||
if (R.is_ok()) {
|
||||
Self->finish(R.move_as_ok());
|
||||
} else {
|
||||
Self->finish(nullptr);
|
||||
}
|
||||
});
|
||||
mutex_.lock();
|
||||
scheduler_ptr->run_in_context_external([&]() { func(std::move(P)); });
|
||||
}
|
||||
void finish(MHD_Response* response) {
|
||||
response_ = response;
|
||||
mutex_.unlock();
|
||||
}
|
||||
MHD_Response* wait() {
|
||||
mutex_.lock();
|
||||
mutex_.unlock();
|
||||
return response_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(td::Promise<MHD_Response*>)> func_;
|
||||
MHD_Response* response_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
class CoreActor : public CoreActorInterface {
|
||||
private:
|
||||
std::string global_config_ = "ton-global.config";
|
||||
|
||||
std::vector<td::actor::ActorOwn<ton::adnl::AdnlExtClient>> clients_;
|
||||
|
||||
td::uint32 http_port_ = 80;
|
||||
MHD_Daemon* daemon_ = nullptr;
|
||||
|
||||
td::IPAddress remote_addr_;
|
||||
ton::PublicKey remote_public_key_;
|
||||
|
||||
bool hide_ips_ = false;
|
||||
|
||||
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback(td::uint32 idx) {
|
||||
class Callback : public ton::adnl::AdnlExtClient::Callback {
|
||||
public:
|
||||
void on_ready() override {
|
||||
td::actor::send_closure(id_, &CoreActor::conn_ready, idx_);
|
||||
}
|
||||
void on_stop_ready() override {
|
||||
td::actor::send_closure(id_, &CoreActor::conn_closed, idx_);
|
||||
}
|
||||
Callback(td::actor::ActorId<CoreActor> id, td::uint32 idx) : id_(std::move(id)), idx_(idx) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<CoreActor> id_;
|
||||
td::uint32 idx_;
|
||||
};
|
||||
|
||||
return std::make_unique<Callback>(actor_id(this), idx);
|
||||
}
|
||||
|
||||
std::shared_ptr<RemoteNodeStatus> new_result_;
|
||||
td::int32 attempt_ = 0;
|
||||
td::int32 waiting_ = 0;
|
||||
|
||||
std::vector<bool> ready_;
|
||||
|
||||
void run_queries();
|
||||
void got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> data);
|
||||
void send_query(td::uint32 idx);
|
||||
|
||||
void add_result() {
|
||||
if (new_result_) {
|
||||
auto ts = static_cast<td::int32>(new_result_->ts_.at_unix());
|
||||
results_.emplace(ts, std::move(new_result_));
|
||||
}
|
||||
}
|
||||
|
||||
void alarm() override {
|
||||
auto t = static_cast<td::int32>(td::Clocks::system() / 60);
|
||||
if (t <= attempt_) {
|
||||
alarm_timestamp() = td::Timestamp::at_unix((attempt_ + 1) * 60);
|
||||
return;
|
||||
}
|
||||
if (waiting_ > 0 && new_result_) {
|
||||
add_result();
|
||||
}
|
||||
attempt_ = t;
|
||||
run_queries();
|
||||
alarm_timestamp() = td::Timestamp::at_unix((attempt_ + 1) * 60);
|
||||
}
|
||||
|
||||
public:
|
||||
std::mutex queue_mutex_;
|
||||
std::mutex res_mutex_;
|
||||
std::map<td::int32, std::shared_ptr<RemoteNodeStatus>> results_;
|
||||
std::vector<td::IPAddress> addrs_;
|
||||
static CoreActor* instance_;
|
||||
td::actor::ActorId<CoreActor> self_id_;
|
||||
|
||||
void conn_ready(td::uint32 idx) {
|
||||
ready_.at(idx) = true;
|
||||
}
|
||||
void conn_closed(td::uint32 idx) {
|
||||
ready_.at(idx) = false;
|
||||
}
|
||||
void set_global_config(std::string str) {
|
||||
global_config_ = str;
|
||||
}
|
||||
void set_http_port(td::uint32 port) {
|
||||
http_port_ = port;
|
||||
}
|
||||
void set_remote_addr(td::IPAddress addr) {
|
||||
remote_addr_ = addr;
|
||||
}
|
||||
void set_remote_public_key(td::BufferSlice file_name) {
|
||||
auto R = [&]() -> td::Result<ton::PublicKey> {
|
||||
TRY_RESULT_PREFIX(conf_data, td::read_file(file_name.as_slice().str()), "failed to read: ");
|
||||
return ton::PublicKey::import(conf_data.as_slice());
|
||||
}();
|
||||
|
||||
if (R.is_error()) {
|
||||
LOG(FATAL) << "bad server public key: " << R.move_as_error();
|
||||
}
|
||||
remote_public_key_ = R.move_as_ok();
|
||||
}
|
||||
void set_hide_ips(bool value) {
|
||||
hide_ips_ = value;
|
||||
}
|
||||
|
||||
void send_lite_query(td::uint32 idx, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||
void send_lite_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
|
||||
return send_lite_query(0, std::move(data), std::move(promise));
|
||||
}
|
||||
void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) override {
|
||||
}
|
||||
void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) override {
|
||||
RemoteNodeStatusList r;
|
||||
r.ips = hide_ips_ ? std::vector<td::IPAddress>{addrs_.size()} : addrs_;
|
||||
auto it = results_.rbegin();
|
||||
while (it != results_.rend() && r.results.size() < max) {
|
||||
r.results.push_back(it->second);
|
||||
it++;
|
||||
}
|
||||
promise.set_value(std::move(r));
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
instance_ = this;
|
||||
auto t = td::Clocks::system();
|
||||
attempt_ = static_cast<td::int32>(t / 60);
|
||||
auto next_t = (attempt_ + 1) * 60;
|
||||
alarm_timestamp() = td::Timestamp::at_unix(next_t);
|
||||
self_id_ = actor_id(this);
|
||||
}
|
||||
void tear_down() override {
|
||||
if (daemon_) {
|
||||
MHD_stop_daemon(daemon_);
|
||||
daemon_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CoreActor() {
|
||||
}
|
||||
|
||||
static int get_arg_iterate(void* cls, enum MHD_ValueKind kind, const char* key, const char* value) {
|
||||
auto X = static_cast<std::map<std::string, std::string>*>(cls);
|
||||
if (key && value && std::strlen(key) > 0 && std::strlen(value) > 0) {
|
||||
X->emplace(key, urldecode(td::Slice{value}, false));
|
||||
}
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
static int process_http_request(void* cls, struct MHD_Connection* connection, const char* url, const char* method,
|
||||
const char* version, const char* upload_data, size_t* upload_data_size, void** ptr) {
|
||||
static int dummy;
|
||||
struct MHD_Response* response = nullptr;
|
||||
int ret;
|
||||
|
||||
if (0 != std::strcmp(method, "GET"))
|
||||
return MHD_NO; /* unexpected method */
|
||||
if (&dummy != *ptr) {
|
||||
/* The first time only the headers are valid,
|
||||
do not respond in the first round... */
|
||||
*ptr = &dummy;
|
||||
return MHD_YES;
|
||||
}
|
||||
if (0 != *upload_data_size)
|
||||
return MHD_NO; /* upload data in a GET!? */
|
||||
|
||||
std::string url_s = url;
|
||||
|
||||
*ptr = nullptr; /* clear context pointer */
|
||||
|
||||
auto pos = url_s.rfind('/');
|
||||
std::string prefix;
|
||||
std::string command;
|
||||
if (pos == std::string::npos) {
|
||||
prefix = "";
|
||||
command = url_s;
|
||||
} else {
|
||||
prefix = url_s.substr(0, pos + 1);
|
||||
command = url_s.substr(pos + 1);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> opts;
|
||||
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, get_arg_iterate, static_cast<void*>(&opts));
|
||||
|
||||
if (command == "status") {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryStatus>("blockinfo", opts, prefix, std::move(promise)).release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else if (command == "block") {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryBlockInfo>("blockinfo", opts, prefix, std::move(promise)).release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else if (command == "search") {
|
||||
if (opts.count("roothash") + opts.count("filehash") > 0) {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryBlockInfo>("blockinfo", opts, prefix, std::move(promise)).release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryBlockSearch>("blocksearch", opts, prefix, std::move(promise)).release();
|
||||
}};
|
||||
response = g.wait();
|
||||
}
|
||||
} else if (command == "last") {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryViewLastBlock>("", opts, prefix, std::move(promise)).release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else if (command == "download") {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryBlockData>("downloadblock", opts, prefix, std::move(promise)).release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else if (command == "viewblock") {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryBlockView>("viewblock", opts, prefix, std::move(promise)).release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else if (command == "account") {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryViewAccount>("viewaccount", opts, prefix, std::move(promise)).release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else if (command == "transaction") {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryViewTransaction>("viewtransaction", opts, prefix, std::move(promise))
|
||||
.release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else if (command == "transaction2") {
|
||||
HttpQueryRunner g{[&](td::Promise<MHD_Response*> promise) {
|
||||
td::actor::create_actor<HttpQueryViewTransaction2>("viewtransaction2", opts, prefix, std::move(promise))
|
||||
.release();
|
||||
}};
|
||||
response = g.wait();
|
||||
} else {
|
||||
ret = MHD_NO;
|
||||
}
|
||||
if (response) {
|
||||
ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
|
||||
MHD_destroy_response(response);
|
||||
} else {
|
||||
ret = MHD_NO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void run() {
|
||||
if (remote_public_key_.empty()) {
|
||||
auto G = td::read_file(global_config_).move_as_ok();
|
||||
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
|
||||
ton::ton_api::liteclient_config_global gc;
|
||||
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
|
||||
|
||||
CHECK(gc.liteservers_.size() > 0);
|
||||
td::uint32 size = static_cast<td::uint32>(gc.liteservers_.size());
|
||||
ready_.resize(size, false);
|
||||
|
||||
for (td::uint32 i = 0; i < size; i++) {
|
||||
auto& cli = gc.liteservers_[i];
|
||||
td::IPAddress addr;
|
||||
addr.init_host_port(td::IPAddress::ipv4_to_str(cli->ip_), cli->port_).ensure();
|
||||
addrs_.push_back(addr);
|
||||
clients_.emplace_back(ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull::create(cli->id_).move_as_ok(),
|
||||
addr, make_callback(i)));
|
||||
}
|
||||
} else {
|
||||
if (!remote_addr_.is_valid()) {
|
||||
LOG(FATAL) << "remote addr not set";
|
||||
}
|
||||
ready_.resize(1, false);
|
||||
addrs_.push_back(remote_addr_);
|
||||
clients_.emplace_back(ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{remote_public_key_},
|
||||
remote_addr_, make_callback(0)));
|
||||
}
|
||||
daemon_ = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, static_cast<td::uint16>(http_port_), nullptr, nullptr,
|
||||
&process_http_request, nullptr, MHD_OPTION_END);
|
||||
CHECK(daemon_ != nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
void CoreActor::got_result(td::uint32 idx, td::int32 attempt, td::Result<td::BufferSlice> R) {
|
||||
if (attempt != attempt_) {
|
||||
return;
|
||||
}
|
||||
if (R.is_error()) {
|
||||
waiting_--;
|
||||
if (waiting_ == 0) {
|
||||
add_result();
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto data = R.move_as_ok();
|
||||
{
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
|
||||
if (F.is_ok()) {
|
||||
auto f = F.move_as_ok();
|
||||
auto err = td::Status::Error(f->code_, f->message_);
|
||||
waiting_--;
|
||||
if (waiting_ == 0) {
|
||||
add_result();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_masterchainInfo>(std::move(data), true);
|
||||
if (F.is_error()) {
|
||||
waiting_--;
|
||||
if (waiting_ == 0) {
|
||||
add_result();
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto f = F.move_as_ok();
|
||||
new_result_->values_[idx] = ton::create_block_id(f->last_);
|
||||
waiting_--;
|
||||
CHECK(waiting_ >= 0);
|
||||
if (waiting_ == 0) {
|
||||
add_result();
|
||||
}
|
||||
}
|
||||
|
||||
void CoreActor::send_query(td::uint32 idx) {
|
||||
if (!ready_[idx]) {
|
||||
return;
|
||||
}
|
||||
waiting_++;
|
||||
auto query = ton::create_tl_object<ton::lite_api::liteServer_getMasterchainInfo>();
|
||||
auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(serialize_tl_object(query, true));
|
||||
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), idx, attempt = attempt_](td::Result<td::BufferSlice> R) {
|
||||
td::actor::send_closure(SelfId, &CoreActor::got_result, idx, attempt, std::move(R));
|
||||
});
|
||||
td::actor::send_closure(clients_[idx], &ton::adnl::AdnlExtClient::send_query, "query", serialize_tl_object(q, true),
|
||||
td::Timestamp::in(10.0), std::move(P));
|
||||
}
|
||||
|
||||
void CoreActor::run_queries() {
|
||||
waiting_ = 0;
|
||||
new_result_ = std::make_shared<RemoteNodeStatus>(ready_.size(), td::Timestamp::at_unix(attempt_ * 60));
|
||||
for (td::uint32 i = 0; i < ready_.size(); i++) {
|
||||
send_query(i);
|
||||
}
|
||||
CHECK(waiting_ >= 0);
|
||||
if (waiting_ == 0) {
|
||||
add_result();
|
||||
}
|
||||
}
|
||||
|
||||
void CoreActor::send_lite_query(td::uint32 idx, td::BufferSlice query, td::Promise<td::BufferSlice> promise) {
|
||||
if (!ready_[idx]) {
|
||||
promise.set_error(td::Status::Error(ton::ErrorCode::notready, "ext conn not ready"));
|
||||
return;
|
||||
}
|
||||
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto B = R.move_as_ok();
|
||||
{
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_error>(B.clone(), true);
|
||||
if (F.is_ok()) {
|
||||
auto f = F.move_as_ok();
|
||||
promise.set_error(td::Status::Error(f->code_, f->message_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
promise.set_value(std::move(B));
|
||||
});
|
||||
auto q = ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(query));
|
||||
td::actor::send_closure(clients_[idx], &ton::adnl::AdnlExtClient::send_query, "query", serialize_tl_object(q, true),
|
||||
td::Timestamp::in(10.0), std::move(P));
|
||||
}
|
||||
|
||||
td::actor::ActorId<CoreActorInterface> CoreActorInterface::instance_actor_id() {
|
||||
auto instance = CoreActor::instance_;
|
||||
CHECK(instance);
|
||||
return instance->self_id_;
|
||||
}
|
||||
|
||||
CoreActor* CoreActor::instance_ = nullptr;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
SET_VERBOSITY_LEVEL(verbosity_INFO);
|
||||
td::set_default_failure_signal_handler().ensure();
|
||||
|
||||
td::actor::ActorOwn<CoreActor> x;
|
||||
|
||||
td::OptionsParser p;
|
||||
p.set_description("TON Blockchain explorer");
|
||||
p.add_option('h', "help", "prints_help", [&]() {
|
||||
char b[10240];
|
||||
td::StringBuilder sb(td::MutableSlice{b, 10000});
|
||||
sb << p;
|
||||
std::cout << sb.as_cslice().c_str();
|
||||
std::exit(2);
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('I', "hide-ips", "hides ips from status", [&]() {
|
||||
td::actor::send_closure(x, &CoreActor::set_hide_ips, true);
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('u', "user", "change user", [&](td::Slice user) { return td::change_user(user); });
|
||||
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
|
||||
td::actor::send_closure(x, &CoreActor::set_global_config, fname.str());
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('a', "addr", "connect to ip:port", [&](td::Slice arg) {
|
||||
td::IPAddress addr;
|
||||
TRY_STATUS(addr.init_host_port(arg.str()));
|
||||
td::actor::send_closure(x, &CoreActor::set_remote_addr, addr);
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('p', "pub", "remote public key", [&](td::Slice arg) {
|
||||
td::actor::send_closure(x, &CoreActor::set_remote_public_key, td::BufferSlice{arg});
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
|
||||
verbosity = td::to_integer<int>(arg);
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + verbosity);
|
||||
return (verbosity >= 0 && verbosity <= 9) ? td::Status::OK() : td::Status::Error("verbosity must be 0..9");
|
||||
});
|
||||
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
|
||||
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
close(0);
|
||||
setsid();
|
||||
#endif
|
||||
}).ensure();
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('H', "http-port", "listen on http port", [&](td::Slice arg) {
|
||||
td::actor::send_closure(x, &CoreActor::set_http_port, td::to_integer<td::uint32>(arg));
|
||||
return td::Status::OK();
|
||||
});
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
|
||||
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
|
||||
td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
|
||||
.move_as_ok();
|
||||
|
||||
dup2(FileLog.get_native_fd().fd(), 1);
|
||||
dup2(FileLog.get_native_fd().fd(), 2);
|
||||
return td::Status::OK();
|
||||
});
|
||||
#endif
|
||||
|
||||
td::actor::Scheduler scheduler({2});
|
||||
scheduler_ptr = &scheduler;
|
||||
scheduler.run_in_context([&] { x = td::actor::create_actor<CoreActor>("testnode"); });
|
||||
|
||||
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
|
||||
scheduler.run_in_context([&] {
|
||||
td::actor::send_closure(x, &CoreActor::run);
|
||||
x.release();
|
||||
});
|
||||
scheduler.run();
|
||||
|
||||
return 0;
|
||||
}
|
56
blockchain-explorer/blockchain-explorer.hpp
Normal file
56
blockchain-explorer/blockchain-explorer.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "ton/ton-types.h"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
|
||||
class CoreActorInterface : public td::actor::Actor {
|
||||
public:
|
||||
struct RemoteNodeStatus {
|
||||
std::vector<ton::BlockIdExt> values_;
|
||||
td::Timestamp ts_;
|
||||
RemoteNodeStatus(size_t size, td::Timestamp ts) : ts_(ts) {
|
||||
values_.resize(size);
|
||||
}
|
||||
};
|
||||
|
||||
struct RemoteNodeStatusList {
|
||||
std::vector<td::IPAddress> ips;
|
||||
std::vector<std::shared_ptr<RemoteNodeStatus>> results;
|
||||
};
|
||||
virtual ~CoreActorInterface() = default;
|
||||
|
||||
virtual void send_lite_query(td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void get_last_result(td::Promise<std::shared_ptr<RemoteNodeStatus>> promise) = 0;
|
||||
virtual void get_results(td::uint32 max, td::Promise<RemoteNodeStatusList> promise) = 0;
|
||||
|
||||
static td::actor::ActorId<CoreActorInterface> instance_actor_id();
|
||||
};
|
39
catchain/CMakeLists.txt
Normal file
39
catchain/CMakeLists.txt
Normal file
|
@ -0,0 +1,39 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
|
||||
set(CATCHAIN_SOURCE
|
||||
catchain-received-block.cpp
|
||||
#catchain-receiver-fork.cpp
|
||||
catchain-receiver-source.cpp
|
||||
catchain-receiver.cpp
|
||||
catchain-block.cpp
|
||||
catchain.cpp
|
||||
|
||||
catchain-block.hpp
|
||||
catchain-received-block.h
|
||||
catchain-received-block.hpp
|
||||
#catchain-receiver-fork.h
|
||||
#catchain-receiver-fork.hpp
|
||||
catchain-receiver-interface.h
|
||||
catchain-receiver-source.h
|
||||
catchain-receiver-source.hpp
|
||||
catchain-receiver.h
|
||||
catchain-receiver.hpp
|
||||
catchain-types.h
|
||||
catchain.h
|
||||
catchain.hpp
|
||||
)
|
||||
|
||||
add_library(catchain STATIC ${CATCHAIN_SOURCE})
|
||||
|
||||
target_include_directories(overlay PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
target_link_libraries(catchain PRIVATE tdutils tdactor adnl tl_api dht tdfec
|
||||
overlay)
|
||||
|
59
catchain/catchain-block.cpp
Normal file
59
catchain/catchain-block.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "catchain-block.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
std::unique_ptr<CatChainBlock> CatChainBlock::create(td::uint32 src, td::uint32 fork, PublicKeyHash src_hash,
|
||||
CatChainBlockHeight height, CatChainBlockHash hash,
|
||||
td::SharedSlice payload, CatChainBlock *prev,
|
||||
std::vector<CatChainBlock *> deps,
|
||||
std::vector<CatChainBlockHeight> vt) {
|
||||
return std::make_unique<CatChainBlockImpl>(src, fork, src_hash, height, hash, std::move(payload), prev,
|
||||
std::move(deps), std::move(vt));
|
||||
}
|
||||
|
||||
CatChainBlockImpl::CatChainBlockImpl(td::uint32 src, td::uint32 fork, PublicKeyHash src_hash,
|
||||
CatChainBlockHeight height, CatChainBlockHash hash, td::SharedSlice payload,
|
||||
CatChainBlock *prev, std::vector<CatChainBlock *> deps,
|
||||
std::vector<CatChainBlockHeight> vt)
|
||||
: src_(src)
|
||||
, fork_(fork)
|
||||
, src_hash_(src_hash)
|
||||
, height_(height)
|
||||
, hash_(hash)
|
||||
, payload_(std::move(payload))
|
||||
, prev_(prev)
|
||||
, deps_(std::move(deps))
|
||||
, vt_(std::move(vt)) {
|
||||
}
|
||||
|
||||
bool CatChainBlockImpl::is_descendant_of(CatChainBlock *block) {
|
||||
auto fork = block->fork();
|
||||
if (fork >= vt_.size()) {
|
||||
return false;
|
||||
}
|
||||
return block->height() <= vt_[fork];
|
||||
}
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
113
catchain/catchain-block.hpp
Normal file
113
catchain/catchain-block.hpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "catchain.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainBlockImpl : public CatChainBlock {
|
||||
private:
|
||||
std::unique_ptr<CatChainBlock::Extra> extra_;
|
||||
td::uint32 src_;
|
||||
td::uint32 fork_;
|
||||
PublicKeyHash src_hash_;
|
||||
CatChainBlockHeight height_;
|
||||
CatChainBlockHash hash_;
|
||||
td::SharedSlice payload_;
|
||||
CatChainBlock *prev_;
|
||||
std::vector<CatChainBlock *> deps_;
|
||||
std::vector<CatChainBlockHeight> vt_;
|
||||
bool preprocess_sent_ = false;
|
||||
bool is_processed_ = false;
|
||||
|
||||
public:
|
||||
td::SharedSlice &payload() override {
|
||||
return payload_;
|
||||
}
|
||||
const td::SharedSlice &payload() const override {
|
||||
return payload_;
|
||||
}
|
||||
|
||||
CatChainBlock::Extra *extra() const override {
|
||||
return extra_.get();
|
||||
}
|
||||
std::unique_ptr<Extra> move_extra() override {
|
||||
return std::move(extra_);
|
||||
}
|
||||
void set_extra(std::unique_ptr<Extra> extra) override {
|
||||
extra_ = std::move(extra);
|
||||
}
|
||||
|
||||
td::uint32 source() const override {
|
||||
return src_;
|
||||
}
|
||||
td::uint32 fork() const override {
|
||||
return fork_;
|
||||
}
|
||||
PublicKeyHash source_hash() const override {
|
||||
return src_hash_;
|
||||
}
|
||||
CatChainBlockHash hash() const override {
|
||||
return hash_;
|
||||
}
|
||||
CatChainBlockHeight height() const override {
|
||||
return height_;
|
||||
}
|
||||
|
||||
CatChainBlock *prev() override {
|
||||
return prev_;
|
||||
}
|
||||
const CatChainBlock *prev() const override {
|
||||
return prev_;
|
||||
}
|
||||
|
||||
const std::vector<CatChainBlock *> &deps() const override {
|
||||
return deps_;
|
||||
}
|
||||
const std::vector<CatChainBlockHeight> &vt() const override {
|
||||
return vt_;
|
||||
}
|
||||
|
||||
bool preprocess_is_sent() const override {
|
||||
return preprocess_sent_;
|
||||
}
|
||||
void preprocess_sent() override {
|
||||
preprocess_sent_ = true;
|
||||
}
|
||||
|
||||
bool is_processed() const override {
|
||||
return is_processed_;
|
||||
}
|
||||
void set_processed() override {
|
||||
is_processed_ = true;
|
||||
}
|
||||
|
||||
bool is_descendant_of(CatChainBlock *block) override;
|
||||
|
||||
CatChainBlockImpl(td::uint32 src, td::uint32 fork, PublicKeyHash src_hash, CatChainBlockHeight height,
|
||||
CatChainBlockHash hash, td::SharedSlice payload, CatChainBlock *prev,
|
||||
std::vector<CatChainBlock *> deps, std::vector<CatChainBlockHeight> vt);
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
523
catchain/catchain-received-block.cpp
Normal file
523
catchain/catchain-received-block.cpp
Normal file
|
@ -0,0 +1,523 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include <set>
|
||||
|
||||
#include "catchain-received-block.hpp"
|
||||
#include "catchain-receiver-source.h"
|
||||
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
void CatChainReceivedBlockImpl::initialize(tl_object_ptr<ton_api::catchain_block> block, td::SharedSlice payload) {
|
||||
if (state_ != bs_none) {
|
||||
return;
|
||||
}
|
||||
|
||||
payload_ = std::move(payload);
|
||||
CHECK(payload_.size() > 0);
|
||||
|
||||
prev_ = dynamic_cast<CatChainReceivedBlockImpl *>(chain_->create_block(std::move(block->data_->prev_)));
|
||||
CHECK(prev_ != nullptr);
|
||||
for (auto &X : block->data_->deps_) {
|
||||
auto B = dynamic_cast<CatChainReceivedBlockImpl *>(chain_->create_block(std::move(X)));
|
||||
CHECK(B != nullptr);
|
||||
block_deps_.push_back(B);
|
||||
}
|
||||
signature_ = td::SharedSlice{block->signature_.as_slice()};
|
||||
|
||||
state_ = bs_initialized;
|
||||
VLOG(CATCHAIN_DEBUG) << this << ": initialized payload_size=" << payload_.size();
|
||||
|
||||
if (prev_->is_ill()) {
|
||||
set_ill();
|
||||
return;
|
||||
}
|
||||
for (auto &X : block_deps_) {
|
||||
if (X->is_ill()) {
|
||||
set_ill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
td::uint32 pending_deps = 0;
|
||||
{
|
||||
if (!prev_->delivered()) {
|
||||
pending_deps++;
|
||||
} else {
|
||||
update_deps(prev_);
|
||||
}
|
||||
if (!prev_->delivered()) {
|
||||
prev_->add_rev_dep(this);
|
||||
}
|
||||
}
|
||||
for (auto &X : block_deps_) {
|
||||
if (!X->delivered()) {
|
||||
pending_deps++;
|
||||
} else {
|
||||
update_deps(X);
|
||||
}
|
||||
if (!X->delivered()) {
|
||||
X->add_rev_dep(this);
|
||||
}
|
||||
}
|
||||
pending_deps_ = pending_deps;
|
||||
if (pending_deps_ == 0 && in_db_) {
|
||||
schedule();
|
||||
}
|
||||
|
||||
chain_->get_source(source_id_)->block_received(height_);
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::run() {
|
||||
if (is_ill()) {
|
||||
return;
|
||||
}
|
||||
if (state_ == bs_none) {
|
||||
return;
|
||||
}
|
||||
if (state_ == bs_delivered) {
|
||||
return;
|
||||
}
|
||||
CHECK(state_ == bs_initialized);
|
||||
CHECK(!pending_deps_);
|
||||
CHECK(in_db_);
|
||||
|
||||
initialize_fork();
|
||||
pre_deliver();
|
||||
deliver();
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::initialize_fork() {
|
||||
CHECK(state_ == bs_initialized);
|
||||
CHECK(!fork_id_);
|
||||
CatChainReceiverSource *S = chain_->get_source(source_id_);
|
||||
if (height_ == 1) {
|
||||
fork_id_ = S->add_fork();
|
||||
} else {
|
||||
if (!prev_->next_) {
|
||||
prev_->next_ = this;
|
||||
fork_id_ = prev_->fork_id_;
|
||||
} else {
|
||||
fork_id_ = S->add_fork();
|
||||
}
|
||||
}
|
||||
|
||||
if (deps_.size() < fork_id_ + 1) {
|
||||
deps_.resize(fork_id_ + 1, 0);
|
||||
}
|
||||
CHECK(deps_[fork_id_] < height_);
|
||||
deps_[fork_id_] = height_;
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::pre_deliver(ton_api::catchain_block_data_fork &b) {
|
||||
{
|
||||
td::Status S;
|
||||
S = chain_->validate_block_sync(b.left_);
|
||||
if (S.is_error()) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": incorrect fork blame: left is invalid: " << S.move_as_error();
|
||||
set_ill();
|
||||
return;
|
||||
}
|
||||
S = chain_->validate_block_sync(b.right_);
|
||||
if (S.is_error()) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": incorrect fork blame: right is invalid: " << S.move_as_error();
|
||||
set_ill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// block is incorrect, since blocks are
|
||||
if (b.left_->height_ != b.right_->height_ || b.left_->src_ != b.right_->src_ ||
|
||||
b.left_->data_hash_ == b.right_->data_hash_) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": incorrect fork blame: not a fork";
|
||||
set_ill();
|
||||
return;
|
||||
}
|
||||
|
||||
auto S = chain_->get_source(b.left_->src_);
|
||||
S->on_found_fork_proof(
|
||||
create_serialize_tl_object<ton_api::catchain_block_data_fork>(std::move(b.left_), std::move(b.right_)));
|
||||
S->blame(fork_id_, height_);
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::pre_deliver(ton_api::catchain_block_data_badBlock &b) {
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::pre_deliver(ton_api::catchain_block_data_nop &b) {
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::pre_deliver() {
|
||||
if (is_ill()) {
|
||||
return;
|
||||
}
|
||||
CHECK(state_ == bs_initialized);
|
||||
CHECK(pending_deps_ == 0);
|
||||
CHECK(in_db_);
|
||||
|
||||
auto M = chain_->get_source(source_id_);
|
||||
|
||||
auto d = prev_ ? &prev_->deps_ : nullptr;
|
||||
|
||||
for (auto &X : block_deps_) {
|
||||
auto S = chain_->get_source(X->get_source_id());
|
||||
auto &f = S->get_forks();
|
||||
if (d) {
|
||||
auto &dd = *d;
|
||||
if (X->get_fork_id() < dd.size() && X->get_height() <= dd[X->get_fork_id()]) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": has direct dep from source " << X->get_source_id() << " and prev block "
|
||||
<< " has newer indirect dep";
|
||||
set_ill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (S->blamed() && d) {
|
||||
auto &dd = *d;
|
||||
for (auto x : f) {
|
||||
if (x != X->get_fork_id() && dd.size() > x && dd[x] > 0) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": has direct dep from source " << X->get_source_id() << " and prev block "
|
||||
<< " has indirect dep to another fork of this source " << x << " " << X->get_fork_id()
|
||||
<< " " << dd[x] << " " << f;
|
||||
M->blame(fork_id_, height_);
|
||||
set_ill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto v = S->get_blamed_heights();
|
||||
|
||||
for (size_t i = 0; i < v.size() && i < dd.size(); i++) {
|
||||
if (v[i] > 0 && dd[i] >= v[i]) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": has direct dep from source " << X->get_source_id() << " and prev block "
|
||||
<< " has indirect dep to block f" << i << "@" << v[i]
|
||||
<< " which is known to blame this source";
|
||||
M->blame(fork_id_, height_);
|
||||
set_ill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto X = fetch_tl_object<ton_api::catchain_block_inner_Data>(payload_.as_slice(), true);
|
||||
if (X.is_error()) {
|
||||
is_custom_ = true;
|
||||
} else {
|
||||
ton_api::downcast_call(*X.move_as_ok().get(), [Self = this](auto &obj) { Self->pre_deliver(obj); });
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::deliver() {
|
||||
if (is_ill()) {
|
||||
return;
|
||||
}
|
||||
CHECK(state_ == bs_initialized);
|
||||
CHECK(pending_deps_ == 0);
|
||||
CHECK(in_db_);
|
||||
|
||||
chain_->deliver_block(this);
|
||||
|
||||
state_ = bs_delivered;
|
||||
VLOG(CATCHAIN_DEBUG) << this << ": delivered";
|
||||
|
||||
for (auto &B : rev_deps_) {
|
||||
B->dep_delivered(this);
|
||||
}
|
||||
rev_deps_.clear();
|
||||
|
||||
chain_->get_source(source_id_)->block_delivered(height_);
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::set_ill() {
|
||||
if (state_ == bs_ill) {
|
||||
return;
|
||||
}
|
||||
VLOG(CATCHAIN_WARNING) << this << ": got ill";
|
||||
auto M = chain_->get_source(source_id_);
|
||||
M->blame();
|
||||
state_ = bs_ill;
|
||||
for (auto &B : rev_deps_) {
|
||||
B->dep_ill(this);
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::dep_ill(CatChainReceivedBlockImpl *block) {
|
||||
set_ill();
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::update_deps(CatChainReceivedBlockImpl *block) {
|
||||
auto &d = block->deps_;
|
||||
if (d.size() > deps_.size()) {
|
||||
deps_.resize(d.size(), 0);
|
||||
}
|
||||
for (size_t i = 0; i < d.size(); i++) {
|
||||
if (deps_[i] < d[i]) {
|
||||
deps_[i] = d[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::dep_delivered(CatChainReceivedBlockImpl *block) {
|
||||
if (is_ill()) {
|
||||
return;
|
||||
}
|
||||
CHECK(!block->is_ill());
|
||||
update_deps(block);
|
||||
pending_deps_--;
|
||||
if (pending_deps_ == 0 && in_db_) {
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::written() {
|
||||
if (!in_db_) {
|
||||
in_db_ = true;
|
||||
if (pending_deps_ == 0) {
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::add_rev_dep(CatChainReceivedBlockImpl *block) {
|
||||
rev_deps_.push_back(block);
|
||||
}
|
||||
|
||||
CatChainReceivedBlock *CatChainReceivedBlockImpl::get_prev() const {
|
||||
return prev_;
|
||||
}
|
||||
|
||||
CatChainBlockHash CatChainReceivedBlockImpl::get_prev_hash() const {
|
||||
CHECK(prev_);
|
||||
return prev_->get_hash();
|
||||
}
|
||||
|
||||
std::vector<CatChainBlockHash> CatChainReceivedBlockImpl::get_dep_hashes() const {
|
||||
std::vector<CatChainBlockHash> v;
|
||||
v.resize(block_deps_.size());
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = block_deps_[i]->get_hash();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::schedule() {
|
||||
chain_->run_block(this);
|
||||
}
|
||||
|
||||
void CatChainReceivedBlockImpl::find_pending_deps(std::vector<CatChainBlockHash> &vec, td::uint32 max_size) const {
|
||||
if (height_ == 0 || is_ill() || delivered() || vec.size() == max_size) {
|
||||
return;
|
||||
}
|
||||
if (!initialized()) {
|
||||
vec.push_back(get_hash());
|
||||
return;
|
||||
}
|
||||
if (prev_) {
|
||||
prev_->find_pending_deps(vec, max_size);
|
||||
}
|
||||
for (auto &X : block_deps_) {
|
||||
X->find_pending_deps(vec, max_size);
|
||||
}
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::catchain_block_id> CatChainReceivedBlock::block_id(CatChainReceiver *chain,
|
||||
tl_object_ptr<ton_api::catchain_block> &block,
|
||||
td::Slice payload) {
|
||||
return create_tl_object<ton_api::catchain_block_id>(block->incarnation_, chain->get_source_hash(block->src_).tl(),
|
||||
block->height_, sha256_bits256(payload));
|
||||
}
|
||||
tl_object_ptr<ton_api::catchain_block_id> CatChainReceivedBlock::block_id(
|
||||
CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block_dep> &block) {
|
||||
return create_tl_object<ton_api::catchain_block_id>(
|
||||
chain->get_incarnation(), chain->get_source_hash(block->src_).tl(), block->height_, block->data_hash_);
|
||||
}
|
||||
|
||||
CatChainBlockHash CatChainReceivedBlock::block_hash(CatChainReceiver *chain,
|
||||
tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) {
|
||||
return get_tl_object_sha_bits256(block_id(chain, block, payload));
|
||||
}
|
||||
|
||||
CatChainBlockHash CatChainReceivedBlock::block_hash(CatChainReceiver *chain,
|
||||
tl_object_ptr<ton_api::catchain_block_dep> &block) {
|
||||
return get_tl_object_sha_bits256(block_id(chain, block));
|
||||
}
|
||||
|
||||
td::Status CatChainReceivedBlock::pre_validate_block(CatChainReceiver *chain,
|
||||
tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) {
|
||||
CHECK(block->incarnation_ == chain->get_incarnation());
|
||||
if (block->height_ <= 0) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, std::string("bad height ") + std::to_string(block->height_));
|
||||
}
|
||||
if (block->src_ < 0 || static_cast<td::uint32>(block->src_) >= chain->get_sources_cnt()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, std::string("bad src ") + std::to_string(block->src_));
|
||||
}
|
||||
|
||||
if (block->data_->prev_->src_ < 0) {
|
||||
return td::Status::Error(ErrorCode::protoviolation,
|
||||
std::string("bad prev block src ") + std::to_string(block->data_->prev_->src_));
|
||||
}
|
||||
if (block->data_->deps_.size() > chain->opts().max_deps) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, std::string("too many deps"));
|
||||
}
|
||||
auto prev_src = static_cast<td::uint32>(block->data_->prev_->src_);
|
||||
|
||||
if (block->height_ > 1) {
|
||||
if (prev_src != static_cast<td::uint32>(block->src_)) {
|
||||
return td::Status::Error(ErrorCode::protoviolation,
|
||||
std::string("bad prev block src ") + std::to_string(block->data_->prev_->src_));
|
||||
}
|
||||
} else {
|
||||
if (prev_src != chain->get_sources_cnt()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation,
|
||||
std::string("bad prev(first) block src ") + std::to_string(block->data_->prev_->src_));
|
||||
}
|
||||
}
|
||||
if (block->data_->prev_->height_ + 1 != block->height_) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, std::string("bad prev block height ") +
|
||||
std::to_string(block->data_->prev_->height_) + " (our " +
|
||||
std::to_string(block->height_) + ")");
|
||||
}
|
||||
|
||||
std::set<td::uint32> used;
|
||||
used.insert(block->src_);
|
||||
for (auto &X : block->data_->deps_) {
|
||||
if (used.find(X->src_) != used.end()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "two deps from same source");
|
||||
}
|
||||
used.insert(X->src_);
|
||||
}
|
||||
|
||||
TRY_STATUS(chain->validate_block_sync(block->data_->prev_));
|
||||
for (auto &X : block->data_->deps_) {
|
||||
TRY_STATUS(chain->validate_block_sync(X));
|
||||
}
|
||||
|
||||
if (payload.size() == 0) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, "empty payload");
|
||||
}
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status CatChainReceivedBlock::pre_validate_block(CatChainReceiver *chain,
|
||||
tl_object_ptr<ton_api::catchain_block_dep> &block) {
|
||||
if (block->height_ < 0) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, std::string("bad height ") + std::to_string(block->height_));
|
||||
}
|
||||
if (block->height_ > 0) {
|
||||
if (block->src_ < 0 || static_cast<td::uint32>(block->src_) >= chain->get_sources_cnt()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, std::string("bad src ") + std::to_string(block->src_));
|
||||
}
|
||||
} else {
|
||||
if (block->src_ < 0 || static_cast<td::uint32>(block->src_) != chain->get_sources_cnt()) {
|
||||
return td::Status::Error(ErrorCode::protoviolation,
|
||||
std::string("bad src (first block) ") + std::to_string(block->src_));
|
||||
}
|
||||
if (block->data_hash_ != chain->get_incarnation() || block->signature_.size() != 0) {
|
||||
return td::Status::Error(ErrorCode::protoviolation, std::string("bad first block"));
|
||||
}
|
||||
}
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::catchain_block> CatChainReceivedBlockImpl::export_tl() const {
|
||||
CHECK(initialized());
|
||||
CHECK(height_ > 0);
|
||||
std::vector<tl_object_ptr<ton_api::catchain_block_dep>> deps;
|
||||
|
||||
for (auto &B : block_deps_) {
|
||||
deps.push_back(B->export_tl_dep());
|
||||
}
|
||||
|
||||
return create_tl_object<ton_api::catchain_block>(
|
||||
chain_->get_incarnation(), source_id_, height_,
|
||||
create_tl_object<ton_api::catchain_block_data>(prev_->export_tl_dep(), std::move(deps)),
|
||||
signature_.clone_as_buffer_slice());
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::catchain_block_dep> CatChainReceivedBlockImpl::export_tl_dep() const {
|
||||
return create_tl_object<ton_api::catchain_block_dep>(source_id_, height_, data_hash_,
|
||||
signature_.clone_as_buffer_slice());
|
||||
}
|
||||
|
||||
CatChainReceivedBlockImpl::CatChainReceivedBlockImpl(td::uint32 source_id, CatChainSessionId hash,
|
||||
CatChainReceiver *chain) {
|
||||
chain_ = chain;
|
||||
state_ = bs_delivered;
|
||||
fork_id_ = 0;
|
||||
source_id_ = source_id;
|
||||
data_ = nullptr;
|
||||
prev_ = nullptr;
|
||||
height_ = 0;
|
||||
|
||||
data_hash_ = hash;
|
||||
hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
|
||||
chain->get_incarnation(), chain->get_incarnation(), height_, data_hash_));
|
||||
}
|
||||
|
||||
CatChainReceivedBlockImpl::CatChainReceivedBlockImpl(tl_object_ptr<ton_api::catchain_block> block,
|
||||
td::SharedSlice payload, CatChainReceiver *chain) {
|
||||
chain_ = chain;
|
||||
data_hash_ = sha256_bits256(payload.as_slice());
|
||||
hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
|
||||
block->incarnation_, chain->get_source_hash(block->src_).tl(), block->height_, data_hash_));
|
||||
height_ = block->height_;
|
||||
source_id_ = block->src_;
|
||||
|
||||
auto S = chain_->get_source(source_id_);
|
||||
S->on_new_block(this);
|
||||
|
||||
initialize(std::move(block), std::move(payload));
|
||||
}
|
||||
|
||||
CatChainReceivedBlockImpl::CatChainReceivedBlockImpl(tl_object_ptr<ton_api::catchain_block_dep> block,
|
||||
CatChainReceiver *chain) {
|
||||
chain_ = chain;
|
||||
data_hash_ = block->data_hash_;
|
||||
source_id_ = block->src_;
|
||||
signature_ = td::SharedSlice{block->signature_.as_slice()};
|
||||
hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
|
||||
chain_->get_incarnation(), chain_->get_source_hash(source_id_).tl(), block->height_, data_hash_));
|
||||
height_ = block->height_;
|
||||
|
||||
auto S = chain_->get_source(source_id_);
|
||||
S->on_new_block(this);
|
||||
}
|
||||
|
||||
std::unique_ptr<CatChainReceivedBlock> CatChainReceivedBlock::create(tl_object_ptr<ton_api::catchain_block> block,
|
||||
td::SharedSlice payload, CatChainReceiver *chain) {
|
||||
return std::make_unique<CatChainReceivedBlockImpl>(std::move(block), std::move(payload), chain);
|
||||
}
|
||||
|
||||
std::unique_ptr<CatChainReceivedBlock> CatChainReceivedBlock::create(tl_object_ptr<ton_api::catchain_block_dep> block,
|
||||
CatChainReceiver *chain) {
|
||||
return std::make_unique<CatChainReceivedBlockImpl>(std::move(block), chain);
|
||||
}
|
||||
|
||||
std::unique_ptr<CatChainReceivedBlock> CatChainReceivedBlock::create_root(td::uint32 source_id,
|
||||
CatChainSessionId data_hash,
|
||||
CatChainReceiver *chain) {
|
||||
return std::make_unique<CatChainReceivedBlockImpl>(source_id, data_hash, chain);
|
||||
}
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
114
catchain/catchain-received-block.h
Normal file
114
catchain/catchain-received-block.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
#include "catchain/catchain-receiver.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainReceiver;
|
||||
class CatChainReceiverSource;
|
||||
class CatChainReceiverFork;
|
||||
|
||||
class CatChainReceivedBlock {
|
||||
public:
|
||||
// getters
|
||||
virtual const td::SharedSlice &get_payload() const = 0;
|
||||
virtual CatChainBlockHash get_hash() const = 0;
|
||||
virtual const td::SharedSlice &get_signature() const = 0;
|
||||
|
||||
virtual CatChainBlockHeight get_height() const = 0;
|
||||
virtual CatChainReceivedBlock *get_prev() const = 0;
|
||||
virtual CatChainBlockHash get_prev_hash() const = 0;
|
||||
|
||||
virtual const std::vector<CatChainBlockHeight> &get_deps() const = 0;
|
||||
virtual std::vector<CatChainBlockHash> get_dep_hashes() const = 0;
|
||||
|
||||
virtual CatChainReceiver *get_chain() const = 0;
|
||||
|
||||
virtual td::uint32 get_fork_id() const = 0;
|
||||
virtual td::uint32 get_source_id() const = 0;
|
||||
|
||||
virtual tl_object_ptr<ton_api::catchain_block> export_tl() const = 0;
|
||||
virtual tl_object_ptr<ton_api::catchain_block_dep> export_tl_dep() const = 0;
|
||||
|
||||
virtual void find_pending_deps(std::vector<CatChainBlockHash> &vec, td::uint32 max_size) const = 0;
|
||||
|
||||
public:
|
||||
// state
|
||||
virtual bool initialized() const = 0;
|
||||
virtual bool delivered() const = 0;
|
||||
virtual bool is_ill() const = 0;
|
||||
virtual bool is_custom() const = 0;
|
||||
virtual bool in_db() const = 0;
|
||||
|
||||
public:
|
||||
//change state
|
||||
virtual void initialize(tl_object_ptr<ton_api::catchain_block> block, td::SharedSlice payload) = 0;
|
||||
virtual void set_ill() = 0;
|
||||
virtual void written() = 0;
|
||||
virtual void run() = 0;
|
||||
|
||||
public:
|
||||
static std::unique_ptr<CatChainReceivedBlock> create(tl_object_ptr<ton_api::catchain_block> block,
|
||||
td::SharedSlice payload, CatChainReceiver *chain);
|
||||
static std::unique_ptr<CatChainReceivedBlock> create(tl_object_ptr<ton_api::catchain_block_dep> block,
|
||||
CatChainReceiver *chain);
|
||||
static std::unique_ptr<CatChainReceivedBlock> create_root(td::uint32 source_id, CatChainBlockPayloadHash data_hash,
|
||||
CatChainReceiver *chain);
|
||||
|
||||
static tl_object_ptr<ton_api::catchain_block_id> block_id(CatChainReceiver *chain,
|
||||
tl_object_ptr<ton_api::catchain_block> &block,
|
||||
td::Slice payload);
|
||||
static tl_object_ptr<ton_api::catchain_block_id> block_id(CatChainReceiver *chain,
|
||||
tl_object_ptr<ton_api::catchain_block_dep> &block);
|
||||
static CatChainBlockHash block_hash(CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block> &block,
|
||||
td::Slice payload);
|
||||
static CatChainBlockHash block_hash(CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block_dep> &block);
|
||||
static td::Status pre_validate_block(CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block> &block,
|
||||
td::Slice payload);
|
||||
static td::Status pre_validate_block(CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block_dep> &block);
|
||||
|
||||
virtual ~CatChainReceivedBlock() = default;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceivedBlock &block) {
|
||||
sb << "[block " << block.get_chain()->get_incarnation() << " " << block.get_source_id() << " " << block.get_fork_id()
|
||||
<< " " << block.get_hash() << "]";
|
||||
return sb;
|
||||
}
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceivedBlock *block) {
|
||||
sb << *block;
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
179
catchain/catchain-received-block.hpp
Normal file
179
catchain/catchain-received-block.hpp
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "catchain/catchain-received-block.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainReceiver;
|
||||
class CatChainReceiverSource;
|
||||
class CatChainReceiverFork;
|
||||
|
||||
class CatChainReceivedBlockImpl : public CatChainReceivedBlock {
|
||||
public:
|
||||
const td::SharedSlice &get_payload() const override {
|
||||
return payload_;
|
||||
}
|
||||
CatChainBlockHash get_hash() const override {
|
||||
return hash_;
|
||||
}
|
||||
const td::SharedSlice &get_signature() const override {
|
||||
return signature_;
|
||||
}
|
||||
|
||||
CatChainBlockHeight get_height() const override {
|
||||
return height_;
|
||||
}
|
||||
CatChainReceivedBlock *get_prev() const override;
|
||||
CatChainBlockHash get_prev_hash() const override;
|
||||
|
||||
const std::vector<CatChainBlockHeight> &get_deps() const override {
|
||||
return deps_;
|
||||
}
|
||||
|
||||
std::vector<CatChainBlockHash> get_dep_hashes() const override;
|
||||
|
||||
CatChainReceiver *get_chain() const override {
|
||||
return chain_;
|
||||
}
|
||||
|
||||
td::uint32 get_fork_id() const override {
|
||||
return fork_id_;
|
||||
}
|
||||
|
||||
td::uint32 get_source_id() const override {
|
||||
return source_id_;
|
||||
}
|
||||
|
||||
tl_object_ptr<ton_api::catchain_block> export_tl() const override;
|
||||
tl_object_ptr<ton_api::catchain_block_dep> export_tl_dep() const override;
|
||||
|
||||
void find_pending_deps(std::vector<CatChainBlockHash> &vec, td::uint32 max_size) const override;
|
||||
|
||||
public:
|
||||
bool initialized() const override {
|
||||
return state_ >= bs_initialized;
|
||||
}
|
||||
bool delivered() const override {
|
||||
return state_ >= bs_delivered;
|
||||
}
|
||||
bool is_ill() const override {
|
||||
return state_ == bs_ill;
|
||||
}
|
||||
bool is_custom() const override {
|
||||
return is_custom_;
|
||||
}
|
||||
bool in_db() const override {
|
||||
return in_db_;
|
||||
}
|
||||
|
||||
public:
|
||||
void initialize(tl_object_ptr<ton_api::catchain_block> block, td::SharedSlice payload) override;
|
||||
|
||||
void run() override;
|
||||
void pre_deliver(ton_api::catchain_block_data_fork &b);
|
||||
void pre_deliver(ton_api::catchain_block_data_badBlock &b);
|
||||
void pre_deliver(ton_api::catchain_block_data_nop &b);
|
||||
template <class T>
|
||||
void pre_deliver(T &b) {
|
||||
// do nothing, it is custom block
|
||||
is_custom_ = true;
|
||||
}
|
||||
void pre_deliver();
|
||||
void deliver();
|
||||
|
||||
void dep_delivered(CatChainReceivedBlockImpl *block);
|
||||
void dep_ill(CatChainReceivedBlockImpl *block);
|
||||
|
||||
void set_ill() override;
|
||||
void schedule();
|
||||
|
||||
void written() override;
|
||||
|
||||
public:
|
||||
CatChainReceivedBlockImpl(tl_object_ptr<ton_api::catchain_block> block, td::SharedSlice payload,
|
||||
CatChainReceiver *chain);
|
||||
CatChainReceivedBlockImpl(tl_object_ptr<ton_api::catchain_block_dep> block, CatChainReceiver *chain);
|
||||
|
||||
CatChainReceivedBlockImpl(td::uint32 source_id, CatChainSessionId hash, CatChainReceiver *chain);
|
||||
|
||||
private:
|
||||
enum State {
|
||||
bs_none,
|
||||
bs_ill,
|
||||
bs_initialized,
|
||||
bs_delivered,
|
||||
} state_ = bs_none;
|
||||
|
||||
void update_deps(CatChainReceivedBlockImpl *block);
|
||||
|
||||
void add_rev_dep(CatChainReceivedBlockImpl *block);
|
||||
void add_child_dep(CatChainReceivedBlockImpl *block);
|
||||
|
||||
void initialize_fork();
|
||||
void on_ready_to_deliver();
|
||||
|
||||
td::uint32 fork_id_{0};
|
||||
td::uint32 source_id_;
|
||||
CatChainReceiver *chain_;
|
||||
|
||||
tl_object_ptr<ton_api::catchain_block_inner_Data> data_;
|
||||
td::SharedSlice payload_;
|
||||
|
||||
CatChainBlockHash hash_;
|
||||
CatChainBlockPayloadHash data_hash_;
|
||||
|
||||
CatChainReceivedBlockImpl *prev_;
|
||||
CatChainBlockHeight height_;
|
||||
|
||||
CatChainReceivedBlockImpl *next_ = nullptr;
|
||||
|
||||
std::vector<CatChainReceivedBlockImpl *> block_deps_;
|
||||
std::vector<CatChainBlockHeight> deps_;
|
||||
|
||||
td::SharedSlice signature_;
|
||||
|
||||
std::vector<CatChainReceivedBlockImpl *> rev_deps_;
|
||||
|
||||
td::uint32 pending_deps_ = 0;
|
||||
|
||||
bool is_custom_ = false;
|
||||
bool in_db_ = false;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceivedBlockImpl &block) {
|
||||
sb << "[block " << block.get_chain()->get_incarnation() << " " << block.get_source_id() << " " << block.get_fork_id()
|
||||
<< " " << block.get_hash() << "]";
|
||||
return sb;
|
||||
}
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceivedBlockImpl *block) {
|
||||
sb << *block;
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
70
catchain/catchain-receiver-interface.h
Normal file
70
catchain/catchain-receiver-interface.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "adnl/adnl.h"
|
||||
#include "overlay/overlays.h"
|
||||
#include "catchain-types.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainReceiverInterface : public td::actor::Actor {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
virtual void new_block(td::uint32 src_id, td::uint32 fork_id, CatChainBlockHash hash, CatChainBlockHeight height,
|
||||
CatChainBlockHash prev, std::vector<CatChainBlockHash> deps,
|
||||
std::vector<CatChainBlockHeight> vt, td::SharedSlice data) = 0;
|
||||
virtual void blame(td::uint32 src_id) = 0;
|
||||
virtual void on_custom_message(PublicKeyHash src, td::BufferSlice data) = 0;
|
||||
virtual void on_custom_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void on_broadcast(PublicKeyHash src, td::BufferSlice data) = 0;
|
||||
virtual void start() = 0;
|
||||
virtual ~Callback() = default;
|
||||
};
|
||||
virtual void add_block(td::BufferSlice payload, std::vector<CatChainBlockHash> deps) = 0;
|
||||
virtual void debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height,
|
||||
std::vector<CatChainBlockHash> deps) = 0;
|
||||
virtual void blame_node(td::uint32 idx) = 0;
|
||||
virtual void send_fec_broadcast(td::BufferSlice data) = 0;
|
||||
virtual void send_custom_query_data(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
|
||||
td::Timestamp timeout, td::BufferSlice query) = 0;
|
||||
virtual void send_custom_query_data_via(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
|
||||
td::Timestamp timeout, td::BufferSlice query, td::uint64 max_answer_size,
|
||||
td::actor::ActorId<adnl::AdnlSenderInterface> via) = 0;
|
||||
virtual void send_custom_message_data(PublicKeyHash dst, td::BufferSlice query) = 0;
|
||||
|
||||
virtual void destroy() = 0;
|
||||
|
||||
static td::actor::ActorOwn<CatChainReceiverInterface> create(std::unique_ptr<Callback> callback, CatChainOptions opts,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<overlay::Overlays> overlay_manager,
|
||||
std::vector<CatChainNode> ids, PublicKeyHash local_id,
|
||||
CatChainSessionId unique_hash, std::string db_root);
|
||||
|
||||
virtual ~CatChainReceiverInterface() = default;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
179
catchain/catchain-receiver-source.cpp
Normal file
179
catchain/catchain-receiver-source.cpp
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "catchain-receiver-source.hpp"
|
||||
#include "common/errorlog.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
td::uint32 CatChainReceiverSourceImpl::add_fork() {
|
||||
if (fork_ids_.size() > 0) {
|
||||
blame();
|
||||
}
|
||||
auto F = chain_->add_fork();
|
||||
CHECK(F > 0);
|
||||
|
||||
fork_ids_.push_back(F);
|
||||
|
||||
VLOG(CATCHAIN_INFO) << this << ": adding new fork " << F << " of source " << id_;
|
||||
|
||||
if (fork_ids_.size() > 1) {
|
||||
CHECK(blamed());
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
CatChainReceiverSourceImpl::CatChainReceiverSourceImpl(CatChainReceiver *chain, PublicKey source,
|
||||
adnl::AdnlNodeIdShort adnl_id, td::uint32 id)
|
||||
: chain_(chain), id_(id), adnl_id_(adnl_id) {
|
||||
src_ = source.compute_short_id();
|
||||
|
||||
encryptor_ = source.create_encryptor_async().move_as_ok();
|
||||
encryptor_sync_ = source.create_encryptor().move_as_ok();
|
||||
full_id_ = std::move(source);
|
||||
}
|
||||
|
||||
td::Result<std::unique_ptr<CatChainReceiverSource>> CatChainReceiverSource::create(CatChainReceiver *chain,
|
||||
PublicKey source,
|
||||
adnl::AdnlNodeIdShort adnl_id,
|
||||
td::uint32 id) {
|
||||
return std::make_unique<CatChainReceiverSourceImpl>(chain, std::move(source), adnl_id, id);
|
||||
}
|
||||
|
||||
void CatChainReceiverSourceImpl::blame(td::uint32 fork, CatChainBlockHeight height) {
|
||||
blame();
|
||||
if (blamed_heights_.size() > 0) {
|
||||
if (blamed_heights_.size() <= fork) {
|
||||
blamed_heights_.resize(fork + 1, 0);
|
||||
}
|
||||
if (blamed_heights_[fork] == 0 || blamed_heights_[fork] > height) {
|
||||
VLOG(CATCHAIN_INFO) << this << ": blamed at " << fork << " " << height;
|
||||
blamed_heights_[fork] = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverSourceImpl::blame() {
|
||||
if (!blamed_) {
|
||||
LOG(ERROR) << this << ": CATCHAIN: blaming source " << id_;
|
||||
blocks_.clear();
|
||||
chain_->on_blame(id_);
|
||||
}
|
||||
blamed_ = true;
|
||||
}
|
||||
|
||||
CatChainReceivedBlock *CatChainReceiverSourceImpl::get_block(CatChainBlockHeight height) const {
|
||||
auto it = blocks_.find(height);
|
||||
if (it != blocks_.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverSourceImpl::block_received(CatChainBlockHeight height) {
|
||||
if (blamed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (received_height_ + 1 == height) {
|
||||
received_height_ = height;
|
||||
}
|
||||
while (true) {
|
||||
auto it = blocks_.find(received_height_ + 1);
|
||||
if (it == blocks_.end()) {
|
||||
return;
|
||||
}
|
||||
if (!it->second->initialized()) {
|
||||
return;
|
||||
}
|
||||
received_height_++;
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverSourceImpl::block_delivered(CatChainBlockHeight height) {
|
||||
if (blamed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (delivered_height_ + 1 == height) {
|
||||
delivered_height_ = height;
|
||||
}
|
||||
while (true) {
|
||||
auto it = blocks_.find(delivered_height_ + 1);
|
||||
if (it == blocks_.end()) {
|
||||
return;
|
||||
}
|
||||
if (!it->second->delivered()) {
|
||||
return;
|
||||
}
|
||||
delivered_height_++;
|
||||
}
|
||||
}
|
||||
|
||||
td::Status CatChainReceiverSourceImpl::validate_dep_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) {
|
||||
auto S = std::move(dep->signature_);
|
||||
auto str = serialize_tl_object(dep, true);
|
||||
dep->signature_ = std::move(S);
|
||||
|
||||
auto R = encryptor_sync_->check_signature(str.as_slice(), dep->signature_.as_slice());
|
||||
if (R.is_error()) {
|
||||
return R.move_as_error();
|
||||
}
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void CatChainReceiverSourceImpl::on_new_block(CatChainReceivedBlock *block) {
|
||||
if (fork_is_found()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(block->get_source_id() == id_);
|
||||
auto it = blocks_.find(block->get_height());
|
||||
if (it != blocks_.end()) {
|
||||
CHECK(block->get_hash() != it->second->get_hash());
|
||||
VLOG(CATCHAIN_WARNING) << this << ": found fork on height " << block->get_height();
|
||||
if (!fork_is_found()) {
|
||||
on_found_fork_proof(create_serialize_tl_object<ton_api::catchain_block_data_fork>(block->export_tl_dep(),
|
||||
it->second->export_tl_dep())
|
||||
.as_slice());
|
||||
chain_->add_prepared_event(fork_proof());
|
||||
}
|
||||
blame();
|
||||
return;
|
||||
}
|
||||
blocks_[block->get_height()] = block;
|
||||
}
|
||||
|
||||
void CatChainReceiverSourceImpl::on_found_fork_proof(td::Slice proof) {
|
||||
if (!fork_is_found()) {
|
||||
fetch_tl_object<ton_api::catchain_block_data_fork>(proof, true).ensure();
|
||||
fork_proof_ = td::SharedSlice{proof};
|
||||
errorlog::ErrorLog::log(PSTRING() << "catchain " << chain_->get_incarnation() << " source " << id_
|
||||
<< " found fork. hash=" << sha256_bits256(fork_proof_.as_slice()).to_hex());
|
||||
errorlog::ErrorLog::log_file(fork_proof_.clone_as_buffer_slice());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
85
catchain/catchain-receiver-source.h
Normal file
85
catchain/catchain-receiver-source.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "catchain-receiver.h"
|
||||
|
||||
#include "keys/encryptor.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainReceiver;
|
||||
class CatChainReceivedBlock;
|
||||
|
||||
class CatChainReceiverSource {
|
||||
public:
|
||||
virtual td::uint32 get_id() const = 0;
|
||||
virtual PublicKeyHash get_hash() const = 0;
|
||||
virtual PublicKey get_full_id() const = 0;
|
||||
virtual adnl::AdnlNodeIdShort get_adnl_id() const = 0;
|
||||
|
||||
virtual td::uint32 add_fork() = 0;
|
||||
|
||||
virtual bool blamed() const = 0;
|
||||
virtual void blame(td::uint32 fork, CatChainBlockHeight height) = 0;
|
||||
virtual void blame() = 0;
|
||||
|
||||
virtual const std::vector<td::uint32> &get_forks() const = 0;
|
||||
virtual const std::vector<CatChainBlockHeight> &get_blamed_heights() const = 0;
|
||||
virtual Encryptor *get_encryptor_sync() const = 0;
|
||||
virtual td::uint32 get_forks_cnt() const = 0;
|
||||
|
||||
virtual CatChainBlockHeight delivered_height() const = 0;
|
||||
virtual CatChainBlockHeight received_height() const = 0;
|
||||
virtual CatChainReceivedBlock *get_block(CatChainBlockHeight height) const = 0;
|
||||
virtual void block_received(CatChainBlockHeight height) = 0;
|
||||
virtual void block_delivered(CatChainBlockHeight height) = 0;
|
||||
|
||||
virtual td::Status validate_dep_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) = 0;
|
||||
virtual void on_new_block(CatChainReceivedBlock *block) = 0;
|
||||
virtual void on_found_fork_proof(td::Slice fork) = 0;
|
||||
virtual td::BufferSlice fork_proof() const = 0;
|
||||
virtual bool fork_is_found() const = 0;
|
||||
|
||||
static td::Result<std::unique_ptr<CatChainReceiverSource>> create(CatChainReceiver *chain, PublicKey pub_key,
|
||||
adnl::AdnlNodeIdShort adnl_id, td::uint32 id);
|
||||
|
||||
virtual CatChainReceiver *get_chain() const = 0;
|
||||
|
||||
virtual ~CatChainReceiverSource() = default;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceiverSource &source) {
|
||||
sb << "[source " << source.get_chain()->get_incarnation() << " " << source.get_id() << "]";
|
||||
return sb;
|
||||
}
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceiverSource *source) {
|
||||
sb << *source;
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
137
catchain/catchain-receiver-source.hpp
Normal file
137
catchain/catchain-receiver-source.hpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "catchain-receiver-source.h"
|
||||
#include "catchain-receiver.h"
|
||||
#include "catchain-received-block.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainReceiverSourceImpl : public CatChainReceiverSource {
|
||||
public:
|
||||
td::uint32 get_id() const override {
|
||||
return id_;
|
||||
}
|
||||
PublicKeyHash get_hash() const override {
|
||||
return src_;
|
||||
}
|
||||
PublicKey get_full_id() const override {
|
||||
return full_id_;
|
||||
}
|
||||
adnl::AdnlNodeIdShort get_adnl_id() const override {
|
||||
return adnl_id_;
|
||||
}
|
||||
|
||||
td::uint32 add_fork() override;
|
||||
|
||||
bool blamed() const override {
|
||||
return blamed_;
|
||||
}
|
||||
void blame(td::uint32 fork, CatChainBlockHeight height) override;
|
||||
void blame() override;
|
||||
void block_received(CatChainBlockHeight height) override;
|
||||
void block_delivered(CatChainBlockHeight height) override;
|
||||
|
||||
const std::vector<td::uint32> &get_forks() const override {
|
||||
return fork_ids_;
|
||||
}
|
||||
|
||||
const std::vector<CatChainBlockHeight> &get_blamed_heights() const override {
|
||||
return blamed_heights_;
|
||||
}
|
||||
|
||||
td::actor::ActorId<EncryptorAsync> get_encryptor() const {
|
||||
return encryptor_.get();
|
||||
}
|
||||
Encryptor *get_encryptor_sync() const override {
|
||||
return encryptor_sync_.get();
|
||||
}
|
||||
|
||||
td::uint32 get_forks_cnt() const override {
|
||||
return static_cast<td::uint32>(fork_ids_.size());
|
||||
}
|
||||
|
||||
CatChainBlockHeight delivered_height() const override {
|
||||
return delivered_height_;
|
||||
}
|
||||
CatChainBlockHeight received_height() const override {
|
||||
return received_height_;
|
||||
}
|
||||
CatChainReceivedBlock *get_block(CatChainBlockHeight height) const override;
|
||||
|
||||
td::Status validate_dep_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) override;
|
||||
void on_new_block(CatChainReceivedBlock *block) override;
|
||||
void on_found_fork_proof(td::Slice proof) override;
|
||||
bool fork_is_found() const override {
|
||||
return !fork_proof_.empty();
|
||||
}
|
||||
td::BufferSlice fork_proof() const override {
|
||||
if (!fork_proof_.empty()) {
|
||||
return fork_proof_.clone_as_buffer_slice();
|
||||
} else {
|
||||
return td::BufferSlice();
|
||||
}
|
||||
}
|
||||
|
||||
CatChainReceiver *get_chain() const override {
|
||||
return chain_;
|
||||
}
|
||||
|
||||
CatChainReceiverSourceImpl(CatChainReceiver *chain, PublicKey source, adnl::AdnlNodeIdShort adnl_id, td::uint32 id);
|
||||
|
||||
private:
|
||||
CatChainReceiver *chain_;
|
||||
td::uint32 id_;
|
||||
PublicKeyHash src_;
|
||||
bool blamed_ = false;
|
||||
PublicKey full_id_;
|
||||
adnl::AdnlNodeIdShort adnl_id_;
|
||||
|
||||
std::vector<td::uint32> fork_ids_;
|
||||
td::actor::ActorOwn<EncryptorAsync> encryptor_;
|
||||
std::unique_ptr<Encryptor> encryptor_sync_;
|
||||
std::vector<CatChainBlockHeight> blamed_heights_;
|
||||
std::map<CatChainBlockHeight, CatChainReceivedBlock *> blocks_;
|
||||
td::SharedSlice fork_proof_;
|
||||
|
||||
CatChainBlockHeight delivered_height_ = 0;
|
||||
CatChainBlockHeight received_height_ = 0;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceiverSourceImpl &source) {
|
||||
sb << "[source " << source.get_chain()->get_incarnation() << " " << source.get_id() << "]";
|
||||
return sb;
|
||||
}
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceiverSourceImpl *source) {
|
||||
sb << *source;
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
988
catchain/catchain-receiver.cpp
Normal file
988
catchain/catchain-receiver.cpp
Normal file
|
@ -0,0 +1,988 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include <set>
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/db/RocksDb.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "common/delay.h"
|
||||
|
||||
#include "catchain-receiver.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
PublicKeyHash CatChainReceiverImpl::get_source_hash(td::uint32 source_id) const {
|
||||
CHECK(source_id < sources_.size());
|
||||
return sources_[source_id]->get_hash();
|
||||
}
|
||||
|
||||
td::uint32 CatChainReceiverImpl::add_fork() {
|
||||
return ++total_forks_;
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::deliver_block(CatChainReceivedBlock *block) {
|
||||
VLOG(CATCHAIN_INFO) << this << ": delivering block " << block->get_hash() << " src=" << block->get_source_id()
|
||||
<< " fork=" << block->get_fork_id() << " height=" << block->get_height()
|
||||
<< " custom=" << block->is_custom();
|
||||
callback_->new_block(block->get_source_id(), block->get_fork_id(), block->get_hash(), block->get_height(),
|
||||
block->get_height() == 1 ? CatChainBlockHash::zero() : block->get_prev_hash(),
|
||||
block->get_dep_hashes(), block->get_deps(),
|
||||
block->is_custom() ? block->get_payload().clone() : td::SharedSlice());
|
||||
|
||||
std::vector<adnl::AdnlNodeIdShort> v;
|
||||
|
||||
for (auto it : neighbours_) {
|
||||
auto S = get_source(it);
|
||||
v.push_back(S->get_adnl_id());
|
||||
}
|
||||
|
||||
auto update = create_tl_object<ton_api::catchain_blockUpdate>(block->export_tl());
|
||||
auto D = serialize_tl_object(update, true, block->get_payload().as_slice());
|
||||
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_multiple_messages, std::move(v),
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(D));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::receive_block(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::catchain_block> block,
|
||||
td::BufferSlice payload) {
|
||||
auto id = CatChainReceivedBlock::block_hash(this, block, payload);
|
||||
auto B = get_block(id);
|
||||
if (B && B->initialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (block->incarnation_ != incarnation_) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": dropping broken block from " << src << ": bad incarnation "
|
||||
<< block->incarnation_;
|
||||
return;
|
||||
}
|
||||
|
||||
auto S = validate_block_sync(block, payload.as_slice());
|
||||
|
||||
if (S.is_error()) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": received broken block from " << src << ": " << S.move_as_error();
|
||||
return;
|
||||
}
|
||||
|
||||
auto raw_data = serialize_tl_object(block, true, payload.as_slice());
|
||||
create_block(std::move(block), td::SharedSlice{payload.as_slice()});
|
||||
|
||||
if (!opts_.debug_disable_db) {
|
||||
db_.set(
|
||||
id, std::move(raw_data), [](td::Unit) {}, 1.0);
|
||||
}
|
||||
block_written_to_db(id);
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::receive_block_answer(adnl::AdnlNodeIdShort src, td::BufferSlice data) {
|
||||
auto F = fetch_tl_prefix<ton_api::catchain_BlockResult>(data, true);
|
||||
if (F.is_error()) {
|
||||
VLOG(CATCHAIN_INFO) << this << ": received bad block result: " << F.move_as_error();
|
||||
return;
|
||||
}
|
||||
auto f = F.move_as_ok();
|
||||
ton_api::downcast_call(
|
||||
*f.get(),
|
||||
td::overloaded(
|
||||
[&](ton_api::catchain_blockNotFound &r) { VLOG(CATCHAIN_INFO) << this << ": catchain block not found"; },
|
||||
[&](ton_api::catchain_blockResult &r) { receive_block(src, std::move(r.block_), std::move(data)); }));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::receive_message_from_overlay(adnl::AdnlNodeIdShort src, td::BufferSlice data) {
|
||||
if (!read_db_) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*auto S = get_source_by_hash(src);
|
||||
CHECK(S != nullptr);
|
||||
|
||||
if (S->blamed()) {
|
||||
VLOG(CATCHAIN_INFO) << this << ": dropping block update from blamed source " << src;
|
||||
return;
|
||||
}*/
|
||||
auto R = fetch_tl_prefix<ton_api::catchain_blockUpdate>(data, true);
|
||||
if (R.is_error()) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": dropping broken block from " << src << ": " << R.move_as_error();
|
||||
return;
|
||||
}
|
||||
|
||||
auto U = R.move_as_ok();
|
||||
receive_block(src, std::move(U->block_), std::move(data));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::receive_broadcast_from_overlay(PublicKeyHash src, td::BufferSlice data) {
|
||||
if (!read_db_) {
|
||||
return;
|
||||
}
|
||||
callback_->on_broadcast(src, std::move(data));
|
||||
}
|
||||
|
||||
/*void CatChainReceiverImpl::send_block(PublicKeyHash src, tl_object_ptr<ton_api::catchain_block> block,
|
||||
td::BufferSlice payload) {
|
||||
CHECK(read_db_);
|
||||
CHECK(src == local_id_);
|
||||
|
||||
validate_block_sync(block, payload.as_slice()).ensure();
|
||||
auto B = create_block(std::move(block), td::SharedSlice{payload.as_slice()});
|
||||
CHECK(B != nullptr);
|
||||
|
||||
run_scheduler();
|
||||
CHECK(B->delivered());
|
||||
}*/
|
||||
|
||||
CatChainReceivedBlock *CatChainReceiverImpl::create_block(tl_object_ptr<ton_api::catchain_block> block,
|
||||
td::SharedSlice payload) {
|
||||
if (block->height_ == 0) {
|
||||
return root_block_;
|
||||
}
|
||||
auto hash = CatChainReceivedBlock::block_hash(this, block, payload.as_slice());
|
||||
|
||||
auto it = blocks_.find(hash);
|
||||
if (it != blocks_.end()) {
|
||||
if (!it->second->initialized()) {
|
||||
it->second->initialize(std::move(block), std::move(payload));
|
||||
}
|
||||
return it->second.get();
|
||||
} else {
|
||||
blocks_.emplace(hash, CatChainReceivedBlock::create(std::move(block), std::move(payload), this));
|
||||
it = blocks_.find(hash);
|
||||
return it->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
CatChainReceivedBlock *CatChainReceiverImpl::create_block(tl_object_ptr<ton_api::catchain_block_dep> block) {
|
||||
if (block->height_ == 0) {
|
||||
return root_block_;
|
||||
}
|
||||
auto hash = CatChainReceivedBlock::block_hash(this, block);
|
||||
auto it = blocks_.find(hash);
|
||||
if (it != blocks_.end()) {
|
||||
return it->second.get();
|
||||
} else {
|
||||
blocks_.emplace(hash, CatChainReceivedBlock::create(std::move(block), this));
|
||||
it = blocks_.find(hash);
|
||||
return it->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
td::Status CatChainReceiverImpl::validate_block_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) {
|
||||
TRY_STATUS_PREFIX(CatChainReceivedBlock::pre_validate_block(this, dep), "failed to validate block: ");
|
||||
|
||||
if (dep->height_ > 0) {
|
||||
auto id = CatChainReceivedBlock::block_id(this, dep);
|
||||
auto B = serialize_tl_object(id, true);
|
||||
auto block = get_block(get_tl_object_sha_bits256(id));
|
||||
if (block) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
auto S = get_source_by_hash(PublicKeyHash{id->src_});
|
||||
CHECK(S != nullptr);
|
||||
auto E = S->get_encryptor_sync();
|
||||
CHECK(E != nullptr);
|
||||
return E->check_signature(B.as_slice(), dep->signature_.as_slice());
|
||||
} else {
|
||||
return td::Status::OK();
|
||||
}
|
||||
}
|
||||
|
||||
td::Status CatChainReceiverImpl::validate_block_sync(tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) {
|
||||
//LOG(INFO) << ton_api::to_string(block);
|
||||
TRY_STATUS_PREFIX(CatChainReceivedBlock::pre_validate_block(this, block, payload), "failed to validate block: ");
|
||||
|
||||
if (block->height_ > 0) {
|
||||
auto id = CatChainReceivedBlock::block_id(this, block, payload);
|
||||
auto B = serialize_tl_object(id, true);
|
||||
|
||||
auto S = get_source_by_hash(PublicKeyHash{id->src_});
|
||||
CHECK(S != nullptr);
|
||||
auto E = S->get_encryptor_sync();
|
||||
CHECK(E != nullptr);
|
||||
return E->check_signature(B.as_slice(), block->signature_.as_slice());
|
||||
} else {
|
||||
return td::Status::OK();
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::run_scheduler() {
|
||||
while (!to_run_.empty()) {
|
||||
auto B = to_run_.front();
|
||||
to_run_.pop_front();
|
||||
|
||||
B->run();
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::run_block(CatChainReceivedBlock *block) {
|
||||
to_run_.push_back(block);
|
||||
}
|
||||
|
||||
CatChainReceivedBlock *CatChainReceiverImpl::get_block(CatChainBlockHash hash) const {
|
||||
auto it = blocks_.find(hash);
|
||||
if (it == blocks_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return it->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::add_block_cont_3(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload) {
|
||||
last_sent_block_ = create_block(std::move(block), td::SharedSlice{payload.as_slice()});
|
||||
last_sent_block_->written();
|
||||
|
||||
run_scheduler();
|
||||
if (!intentional_fork_) {
|
||||
CHECK(last_sent_block_->delivered());
|
||||
}
|
||||
|
||||
active_send_ = false;
|
||||
if (pending_blocks_.size() > 0) {
|
||||
auto B = std::move(pending_blocks_.front());
|
||||
pending_blocks_.pop_front();
|
||||
add_block(std::move(B->payload_), std::move(B->deps_));
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::add_block_cont_2(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload) {
|
||||
if (opts_.debug_disable_db) {
|
||||
add_block_cont_3(std::move(block), std::move(payload));
|
||||
return;
|
||||
}
|
||||
|
||||
auto id = CatChainReceivedBlock::block_hash(this, block, payload);
|
||||
|
||||
td::BufferSlice raw_data{32};
|
||||
raw_data.as_slice().copy_from(as_slice(id));
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), block = std::move(block),
|
||||
payload = std::move(payload)](td::Result<td::Unit> R) mutable {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::add_block_cont_3, std::move(block), std::move(payload));
|
||||
});
|
||||
|
||||
db_.set(CatChainBlockHash::zero(), std::move(raw_data), std::move(P), 0);
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::add_block_cont(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload) {
|
||||
validate_block_sync(block, payload.as_slice()).ensure();
|
||||
if (opts_.debug_disable_db) {
|
||||
add_block_cont_2(std::move(block), std::move(payload));
|
||||
return;
|
||||
}
|
||||
auto id = CatChainReceivedBlock::block_hash(this, block, payload.as_slice());
|
||||
|
||||
auto raw_data = serialize_tl_object(block, true, payload.as_slice());
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), block = std::move(block),
|
||||
payload = std::move(payload)](td::Result<td::Unit> R) mutable {
|
||||
R.ensure();
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::add_block_cont_2, std::move(block), std::move(payload));
|
||||
});
|
||||
|
||||
db_.set(id, std::move(raw_data), std::move(P), 0);
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::add_block(td::BufferSlice payload, std::vector<CatChainBlockHash> deps) {
|
||||
if (active_send_) {
|
||||
auto B = std::make_unique<PendingBlock>(std::move(payload), std::move(deps));
|
||||
pending_blocks_.push_back(std::move(B));
|
||||
return;
|
||||
}
|
||||
active_send_ = true;
|
||||
|
||||
auto S = get_source_by_hash(local_id_);
|
||||
CHECK(S != nullptr);
|
||||
CHECK(S->get_id() == local_idx_);
|
||||
if (!intentional_fork_) {
|
||||
CHECK(!S->blamed());
|
||||
}
|
||||
|
||||
auto prev = last_sent_block_->export_tl_dep();
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::catchain_block_dep>> deps_arr;
|
||||
deps_arr.resize(deps.size());
|
||||
for (size_t i = 0; i < deps.size(); i++) {
|
||||
auto B = get_block(deps[i]);
|
||||
LOG_CHECK(B != nullptr) << this << ": cannot find block with hash " << deps[i];
|
||||
if (!intentional_fork_) {
|
||||
CHECK(B->get_source_id() != local_idx_);
|
||||
}
|
||||
deps_arr[i] = B->export_tl_dep();
|
||||
}
|
||||
|
||||
auto height = prev->height_ + 1;
|
||||
auto block_data = create_tl_object<ton_api::catchain_block_data>(std::move(prev), std::move(deps_arr));
|
||||
auto block = create_tl_object<ton_api::catchain_block>(incarnation_, local_idx_, height, std::move(block_data),
|
||||
td::BufferSlice());
|
||||
|
||||
auto id = CatChainReceivedBlock::block_id(this, block, payload);
|
||||
auto id_s = serialize_tl_object(id, true);
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), print_id = print_id(), block = std::move(block),
|
||||
payload = std::move(payload)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
LOG(FATAL) << print_id << ": failed to sign: " << R.move_as_error();
|
||||
return;
|
||||
}
|
||||
block->signature_ = R.move_as_ok();
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::add_block_cont, std::move(block), std::move(payload));
|
||||
});
|
||||
|
||||
td::actor::send_closure_later(keyring_, &keyring::Keyring::sign_message, local_id_, std::move(id_s), std::move(P));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::debug_add_fork_cont(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload) {
|
||||
validate_block_sync(block, payload.as_slice()).ensure();
|
||||
auto B = create_block(std::move(block), td::SharedSlice{payload.as_slice()});
|
||||
B->written();
|
||||
|
||||
run_scheduler();
|
||||
CHECK(B->delivered());
|
||||
|
||||
active_send_ = false;
|
||||
if (pending_blocks_.size() > 0) {
|
||||
auto B = std::move(pending_blocks_.front());
|
||||
pending_blocks_.pop_front();
|
||||
add_block(std::move(B->payload_), std::move(B->deps_));
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height,
|
||||
std::vector<CatChainBlockHash> deps) {
|
||||
intentional_fork_ = true;
|
||||
auto S = get_source_by_hash(local_id_);
|
||||
CHECK(S != nullptr);
|
||||
CHECK(S->get_id() == local_idx_);
|
||||
|
||||
if (height > S->received_height() + 1) {
|
||||
height = S->received_height() + 1;
|
||||
}
|
||||
|
||||
CHECK(height > 0);
|
||||
CatChainReceivedBlock *prev;
|
||||
if (height == 1) {
|
||||
prev = root_block_;
|
||||
} else {
|
||||
prev = sources_[local_idx_]->get_block(height - 1);
|
||||
CHECK(prev);
|
||||
}
|
||||
|
||||
std::vector<tl_object_ptr<ton_api::catchain_block_dep>> deps_arr;
|
||||
deps_arr.resize(deps.size());
|
||||
for (size_t i = 0; i < deps.size(); i++) {
|
||||
auto B = get_block(deps[i]);
|
||||
LOG_CHECK(B != nullptr) << this << ": cannot find block with hash " << deps[i];
|
||||
CHECK(B->get_source_id() != local_idx_);
|
||||
deps_arr[i] = B->export_tl_dep();
|
||||
}
|
||||
|
||||
auto block_data = create_tl_object<ton_api::catchain_block_data>(prev->export_tl_dep(), std::move(deps_arr));
|
||||
auto block = create_tl_object<ton_api::catchain_block>(incarnation_, local_idx_, height, std::move(block_data),
|
||||
td::BufferSlice());
|
||||
|
||||
auto id = CatChainReceivedBlock::block_id(this, block, payload);
|
||||
auto id_s = serialize_tl_object(id, true);
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), print_id = print_id(), block = std::move(block),
|
||||
payload = std::move(payload)](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
LOG(FATAL) << print_id << ": failed to sign: " << R.move_as_error();
|
||||
return;
|
||||
}
|
||||
block->signature_ = R.move_as_ok();
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::debug_add_fork_cont, std::move(block), std::move(payload));
|
||||
});
|
||||
|
||||
td::actor::send_closure_later(keyring_, &keyring::Keyring::sign_message, local_id_, std::move(id_s), std::move(P));
|
||||
}
|
||||
|
||||
CatChainReceiverImpl::CatChainReceiverImpl(std::unique_ptr<Callback> callback, CatChainOptions opts,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<overlay::Overlays> overlay_manager,
|
||||
std::vector<CatChainNode> ids, PublicKeyHash local_id,
|
||||
CatChainSessionId unique_hash, std::string db_root)
|
||||
: callback_(std::move(callback))
|
||||
, opts_(std::move(opts))
|
||||
, keyring_(keyring)
|
||||
, adnl_(adnl)
|
||||
, overlay_manager_(overlay_manager)
|
||||
, local_id_(local_id)
|
||||
, db_root_(db_root) {
|
||||
std::vector<td::Bits256> short_ids;
|
||||
local_idx_ = static_cast<td::uint32>(ids.size());
|
||||
for (auto &id : ids) {
|
||||
td::uint32 seq = static_cast<td::uint32>(sources_.size());
|
||||
auto R = CatChainReceiverSource::create(this, id.pub_key, id.adnl_id, seq);
|
||||
auto S = R.move_as_ok();
|
||||
auto h = id.pub_key.compute_short_id();
|
||||
short_ids.push_back(h.bits256_value());
|
||||
sources_hashes_[h] = seq;
|
||||
sources_adnl_addrs_[id.adnl_id] = seq;
|
||||
sources_.push_back(std::move(S));
|
||||
|
||||
if (h == local_id_) {
|
||||
CHECK(local_idx_ == static_cast<td::uint32>(ids.size()));
|
||||
local_idx_ = seq;
|
||||
}
|
||||
}
|
||||
CHECK(local_idx_ != static_cast<td::uint32>(ids.size()));
|
||||
|
||||
//std::sort(short_ids.begin(), short_ids.end());
|
||||
auto F = create_tl_object<ton_api::catchain_firstblock>(unique_hash, std::move(short_ids));
|
||||
|
||||
overlay_full_id_ = overlay::OverlayIdFull{serialize_tl_object(F, true)};
|
||||
overlay_id_ = overlay_full_id_.compute_short_id();
|
||||
incarnation_ = overlay_id_.bits256_value();
|
||||
|
||||
auto R = CatChainReceivedBlock::create_root(get_sources_cnt(), incarnation_, this);
|
||||
root_block_ = R.get();
|
||||
blocks_[root_block_->get_hash()] = std::move(R);
|
||||
last_sent_block_ = root_block_;
|
||||
|
||||
choose_neighbours();
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::start_up() {
|
||||
std::vector<adnl::AdnlNodeIdShort> ids;
|
||||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
ids.push_back(get_source(i)->get_adnl_id());
|
||||
}
|
||||
std::map<PublicKeyHash, td::uint32> root_keys;
|
||||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
root_keys.emplace(get_source(i)->get_hash(), 16 << 20);
|
||||
}
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::create_private_overlay,
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_full_id_.clone(), std::move(ids),
|
||||
make_callback(), overlay::OverlayPrivacyRules{0, std::move(root_keys)});
|
||||
|
||||
CHECK(root_block_);
|
||||
|
||||
if (!opts_.debug_disable_db) {
|
||||
std::shared_ptr<td::KeyValue> kv = std::make_shared<td::RocksDb>(
|
||||
td::RocksDb::open(db_root_ + "/catchainreceiver-" + td::base64url_encode(as_slice(incarnation_))).move_as_ok());
|
||||
db_ = DbType{std::move(kv)};
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<DbType::GetResult> R) {
|
||||
R.ensure();
|
||||
auto g = R.move_as_ok();
|
||||
if (g.status == td::KeyValue::GetStatus::NotFound) {
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::read_db);
|
||||
} else {
|
||||
auto B = std::move(g.value);
|
||||
CHECK(B.size() == 32);
|
||||
CatChainBlockHash x;
|
||||
as_slice(x).copy_from(B.as_slice());
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::read_db_from, x);
|
||||
}
|
||||
});
|
||||
|
||||
db_.get(CatChainBlockHash::zero(), std::move(P));
|
||||
} else {
|
||||
read_db();
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::tear_down() {
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::delete_overlay, get_source(local_idx_)->get_adnl_id(),
|
||||
overlay_id_);
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::read_db_from(CatChainBlockHash id) {
|
||||
pending_in_db_ = 1;
|
||||
db_root_block_ = id;
|
||||
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id](td::Result<DbType::GetResult> R) {
|
||||
R.ensure();
|
||||
auto g = R.move_as_ok();
|
||||
CHECK(g.status == td::KeyValue::GetStatus::Ok);
|
||||
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::read_block_from_db, id, std::move(g.value));
|
||||
});
|
||||
|
||||
db_.get(id, std::move(P));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::read_block_from_db(CatChainBlockHash id, td::BufferSlice data) {
|
||||
pending_in_db_--;
|
||||
|
||||
auto F = fetch_tl_prefix<ton_api::catchain_block>(data, true);
|
||||
F.ensure();
|
||||
|
||||
auto block = F.move_as_ok();
|
||||
auto payload = std::move(data);
|
||||
|
||||
auto block_id = CatChainReceivedBlock::block_hash(this, block, payload);
|
||||
CHECK(block_id == id);
|
||||
|
||||
auto B = get_block(id);
|
||||
if (B && B->initialized()) {
|
||||
CHECK(B->in_db());
|
||||
if (!pending_in_db_) {
|
||||
read_db();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto source = get_source(block->src_);
|
||||
CHECK(source != nullptr);
|
||||
|
||||
CHECK(block->incarnation_ == incarnation_);
|
||||
|
||||
validate_block_sync(block, payload).ensure();
|
||||
|
||||
B = create_block(std::move(block), td::SharedSlice{payload.as_slice()});
|
||||
B->written();
|
||||
CHECK(B);
|
||||
|
||||
auto deps = B->get_dep_hashes();
|
||||
deps.push_back(B->get_prev_hash());
|
||||
for (auto &dep : deps) {
|
||||
auto dep_block = get_block(dep);
|
||||
if (!dep_block || !dep_block->initialized()) {
|
||||
pending_in_db_++;
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), dep](td::Result<DbType::GetResult> R) {
|
||||
R.ensure();
|
||||
auto g = R.move_as_ok();
|
||||
CHECK(g.status == td::KeyValue::GetStatus::Ok);
|
||||
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::read_block_from_db, dep, std::move(g.value));
|
||||
});
|
||||
|
||||
db_.get(dep, std::move(P));
|
||||
}
|
||||
}
|
||||
|
||||
if (!pending_in_db_) {
|
||||
read_db();
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::read_db() {
|
||||
if (!db_root_block_.is_zero()) {
|
||||
run_scheduler();
|
||||
last_sent_block_ = get_block(db_root_block_);
|
||||
CHECK(last_sent_block_);
|
||||
CHECK(last_sent_block_->delivered());
|
||||
}
|
||||
|
||||
read_db_ = true;
|
||||
|
||||
next_rotate_ = td::Timestamp::in(60 + td::Random::fast(0, 60));
|
||||
next_sync_ = td::Timestamp::in(0.01 * td::Random::fast(0, 60));
|
||||
alarm_timestamp().relax(next_rotate_);
|
||||
alarm_timestamp().relax(next_sync_);
|
||||
|
||||
callback_->start();
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<CatChainReceiverInterface> CatChainReceiverInterface::create(
|
||||
std::unique_ptr<Callback> callback, CatChainOptions opts, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<overlay::Overlays> overlay_manager,
|
||||
std::vector<CatChainNode> ids, PublicKeyHash local_id, CatChainSessionId unique_hash, std::string db_root) {
|
||||
auto A = td::actor::create_actor<CatChainReceiverImpl>("catchainreceiver", std::move(callback), std::move(opts),
|
||||
keyring, adnl, overlay_manager, std::move(ids), local_id,
|
||||
unique_hash, db_root);
|
||||
return std::move(A);
|
||||
}
|
||||
|
||||
CatChainReceiverSource *CatChainReceiverImpl::get_source_by_hash(PublicKeyHash source_hash) const {
|
||||
auto it = sources_hashes_.find(source_hash);
|
||||
if (it == sources_hashes_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return get_source(it->second);
|
||||
}
|
||||
|
||||
CatChainReceiverSource *CatChainReceiverImpl::get_source_by_adnl_id(adnl::AdnlNodeIdShort source_hash) const {
|
||||
auto it = sources_adnl_addrs_.find(source_hash);
|
||||
if (it == sources_adnl_addrs_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return get_source(it->second);
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::receive_query_from_overlay(adnl::AdnlNodeIdShort src, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (!read_db_) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::notready, "db not read"));
|
||||
return;
|
||||
}
|
||||
td::PerfWarningTimer t{"catchain query process", 0.001};
|
||||
auto F = fetch_tl_object<ton_api::Function>(data.clone(), true);
|
||||
if (F.is_error()) {
|
||||
callback_->on_custom_query(get_source_by_adnl_id(src)->get_hash(), std::move(data), std::move(promise));
|
||||
//LOG(WARNING) << this << ": unknown query from " << src;
|
||||
return;
|
||||
}
|
||||
auto f = F.move_as_ok();
|
||||
ton_api::downcast_call(*f.get(), [&](auto &obj) { this->process_query(src, obj, std::move(promise)); });
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlock &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto it = blocks_.find(query.block_);
|
||||
if (it == blocks_.end() || it->second->get_height() == 0 || !it->second->initialized()) {
|
||||
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_blockNotFound>(), true));
|
||||
} else {
|
||||
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_blockResult>(it->second->export_tl()),
|
||||
true, it->second->get_payload().as_slice()));
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlocks &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
if (query.blocks_.size() > 100) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "too many blocks"));
|
||||
return;
|
||||
}
|
||||
td::int32 cnt = 0;
|
||||
for (auto &b : query.blocks_) {
|
||||
auto it = blocks_.find(b);
|
||||
if (it != blocks_.end() && it->second->get_height() > 0) {
|
||||
auto block = create_tl_object<ton_api::catchain_blockUpdate>(it->second->export_tl());
|
||||
CHECK(it->second->get_payload().size() > 0);
|
||||
auto B = serialize_tl_object(block, true, it->second->get_payload().clone());
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_message, src,
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(B));
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_sent>(cnt), true));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlockHistory &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto h = query.height_;
|
||||
if (h <= 0) {
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "not-positive height"));
|
||||
return;
|
||||
}
|
||||
if (h > 100) {
|
||||
h = 100;
|
||||
}
|
||||
std::set<CatChainBlockHash> s{query.stop_if_.begin(), query.stop_if_.end()};
|
||||
|
||||
auto B = get_block(query.block_);
|
||||
if (B == nullptr) {
|
||||
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_sent>(0), true));
|
||||
return;
|
||||
}
|
||||
if (static_cast<CatChainBlockHeight>(h) > B->get_height()) {
|
||||
h = B->get_height();
|
||||
}
|
||||
td::uint32 cnt = 0;
|
||||
while (h-- > 0) {
|
||||
if (s.find(B->get_hash()) != s.end()) {
|
||||
break;
|
||||
}
|
||||
auto block = create_tl_object<ton_api::catchain_blockUpdate>(B->export_tl());
|
||||
CHECK(B->get_payload().size() > 0);
|
||||
auto BB = serialize_tl_object(block, true, B->get_payload().as_slice());
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_message, src,
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(BB));
|
||||
B = B->get_prev();
|
||||
cnt++;
|
||||
}
|
||||
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_sent>(cnt), true));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getDifference &query,
|
||||
td::Promise<td::BufferSlice> promise) {
|
||||
auto &vt = query.rt_;
|
||||
if (vt.size() != get_sources_cnt()) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": incorrect query from " << src;
|
||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "bad vt size"));
|
||||
return;
|
||||
}
|
||||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
if (vt[i] >= 0) {
|
||||
auto S = get_source(i);
|
||||
if (S->fork_is_found()) {
|
||||
auto obj = fetch_tl_object<ton_api::catchain_block_data_fork>(S->fork_proof(), true);
|
||||
obj.ensure();
|
||||
auto f = obj.move_as_ok();
|
||||
promise.set_value(
|
||||
create_serialize_tl_object<ton_api::catchain_differenceFork>(std::move(f->left_), std::move(f->right_)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<td::int32> my_vt(get_sources_cnt());
|
||||
td::uint64 total = 0;
|
||||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
if (vt[i] >= 0) {
|
||||
auto x = static_cast<CatChainBlockHeight>(vt[i]);
|
||||
auto S = get_source(i);
|
||||
if (S->delivered_height() > x) {
|
||||
total += S->delivered_height() - x;
|
||||
}
|
||||
my_vt[i] = S->delivered_height();
|
||||
} else {
|
||||
my_vt[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
const td::uint32 max_send = 100;
|
||||
|
||||
td::int32 l = 0;
|
||||
td::int32 r = max_send + 1;
|
||||
while (r - l > 1) {
|
||||
td::int32 x = (r + l) / 2;
|
||||
td::uint64 sum = 0;
|
||||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
if (vt[i] >= 0 && my_vt[i] > vt[i]) {
|
||||
sum += (my_vt[i] - vt[i] > x) ? x : (my_vt[i] - vt[i]);
|
||||
}
|
||||
}
|
||||
if (sum > max_send) {
|
||||
r = x;
|
||||
} else {
|
||||
l = x;
|
||||
}
|
||||
}
|
||||
CHECK(r > 0);
|
||||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
if (vt[i] >= 0 && my_vt[i] > vt[i]) {
|
||||
auto S = get_source(i);
|
||||
auto t = (my_vt[i] - vt[i] > r) ? r : (my_vt[i] - vt[i]);
|
||||
CHECK(t > 0);
|
||||
while (t-- > 0) {
|
||||
auto M = S->get_block(++vt[i]);
|
||||
CHECK(M != nullptr);
|
||||
auto block = create_tl_object<ton_api::catchain_blockUpdate>(M->export_tl());
|
||||
CHECK(M->get_payload().size() > 0);
|
||||
auto BB = serialize_tl_object(block, true, M->get_payload().as_slice());
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_message, src,
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(BB));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_difference>(std::move(vt)), true));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::got_fork_proof(td::BufferSlice data) {
|
||||
auto F = fetch_tl_object<ton_api::catchain_differenceFork>(std::move(data), true);
|
||||
if (F.is_error()) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": received bad fork proof: " << F.move_as_error();
|
||||
return;
|
||||
}
|
||||
auto f = F.move_as_ok();
|
||||
{
|
||||
td::Status S;
|
||||
S = validate_block_sync(f->left_);
|
||||
if (S.is_error()) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": incorrect fork blame: left is invalid: " << S.move_as_error();
|
||||
return;
|
||||
}
|
||||
S = validate_block_sync(f->right_);
|
||||
if (S.is_error()) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": incorrect fork blame: right is invalid: " << S.move_as_error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// block is incorrect, since blocks are
|
||||
if (f->left_->height_ != f->right_->height_ || f->left_->src_ != f->right_->src_ ||
|
||||
f->left_->data_hash_ == f->right_->data_hash_) {
|
||||
VLOG(CATCHAIN_WARNING) << this << ": incorrect fork blame: not a fork";
|
||||
return;
|
||||
}
|
||||
|
||||
auto S = get_source(f->left_->src_);
|
||||
S->on_found_fork_proof(
|
||||
create_serialize_tl_object<ton_api::catchain_block_data_fork>(std::move(f->left_), std::move(f->right_)));
|
||||
S->blame();
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::synchronize_with(CatChainReceiverSource *S) {
|
||||
CHECK(!S->blamed());
|
||||
std::vector<td::int32> rt(get_sources_cnt());
|
||||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
auto SS = get_source(i);
|
||||
if (SS->blamed()) {
|
||||
rt[i] = -1;
|
||||
} else {
|
||||
rt[i] = S->delivered_height();
|
||||
}
|
||||
}
|
||||
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), src = S->get_hash(), print_id = print_id()](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(CATCHAIN_INFO) << print_id << ": timedout syncronize query to " << src;
|
||||
return;
|
||||
}
|
||||
auto data = R.move_as_ok();
|
||||
auto X = fetch_tl_object<ton_api::catchain_Difference>(data.clone(), true);
|
||||
if (X.is_error()) {
|
||||
VLOG(CATCHAIN_WARNING) << print_id << ": received incorrect answer to syncronize query from " << src << ": "
|
||||
<< X.move_as_error();
|
||||
return;
|
||||
}
|
||||
auto A = X.move_as_ok();
|
||||
|
||||
if (A->get_id() == ton_api::catchain_differenceFork::ID) {
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::got_fork_proof, std::move(data));
|
||||
}
|
||||
// use answer ?
|
||||
return;
|
||||
});
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_query, S->get_adnl_id(),
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, "sync", std::move(P),
|
||||
td::Timestamp::in(5.0),
|
||||
serialize_tl_object(create_tl_object<ton_api::catchain_getDifference>(std::move(rt)), true));
|
||||
|
||||
if (S->delivered_height() < S->received_height()) {
|
||||
auto B = S->get_block(S->delivered_height() + 1);
|
||||
CHECK(B->initialized());
|
||||
|
||||
std::vector<CatChainBlockHash> vec;
|
||||
B->find_pending_deps(vec, 16);
|
||||
|
||||
for (auto &hash : vec) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[SelfId = actor_id(this), print_id = print_id(), src = S->get_adnl_id()](td::Result<td::BufferSlice> R) {
|
||||
if (R.is_error()) {
|
||||
VLOG(CATCHAIN_INFO) << print_id << ": timedout syncronize query to " << src;
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &CatChainReceiverImpl::receive_block_answer, src, R.move_as_ok());
|
||||
}
|
||||
});
|
||||
auto query = serialize_tl_object(create_tl_object<ton_api::catchain_getBlock>(hash), true);
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_query, S->get_adnl_id(),
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, "sync blocks", std::move(P),
|
||||
td::Timestamp::in(2.0), std::move(query));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::choose_neighbours() {
|
||||
std::vector<td::uint32> n;
|
||||
n.resize(get_max_neighbours());
|
||||
|
||||
td::uint32 size = 0;
|
||||
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
|
||||
if (i == local_idx_) {
|
||||
continue;
|
||||
}
|
||||
auto S = get_source(i);
|
||||
if (!S->blamed()) {
|
||||
size++;
|
||||
if (size <= n.size()) {
|
||||
n[size - 1] = i;
|
||||
} else {
|
||||
td::uint32 id = td::Random::fast(0, size - 1);
|
||||
if (id < n.size()) {
|
||||
n[id] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (size < n.size()) {
|
||||
n.resize(size);
|
||||
}
|
||||
neighbours_ = std::move(n);
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::alarm() {
|
||||
alarm_timestamp() = td::Timestamp::never();
|
||||
if (next_sync_ && next_sync_.is_in_past()) {
|
||||
next_sync_ = td::Timestamp::in(td::Random::fast(2.0, 3.0));
|
||||
for (auto i = 0; i < 3; i++) {
|
||||
auto S = get_source(td::Random::fast(0, get_sources_cnt() - 1));
|
||||
CHECK(S != nullptr);
|
||||
if (!S->blamed()) {
|
||||
synchronize_with(S);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (next_rotate_ && next_rotate_.is_in_past()) {
|
||||
next_rotate_ = td::Timestamp::in(td::Random::fast(60.0, 120.0));
|
||||
choose_neighbours();
|
||||
}
|
||||
alarm_timestamp().relax(next_rotate_);
|
||||
alarm_timestamp().relax(next_sync_);
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::send_fec_broadcast(td::BufferSlice data) {
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_broadcast_fec_ex,
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, local_id_, 0, std::move(data));
|
||||
}
|
||||
void CatChainReceiverImpl::send_custom_query_data(PublicKeyHash dst, std::string name,
|
||||
td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
|
||||
td::BufferSlice query) {
|
||||
auto S = get_source_by_hash(dst);
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_query, S->get_adnl_id(),
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(name), std::move(promise),
|
||||
timeout, std::move(query));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::send_custom_query_data_via(PublicKeyHash dst, std::string name,
|
||||
td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
|
||||
td::BufferSlice query, td::uint64 max_answer_size,
|
||||
td::actor::ActorId<adnl::AdnlSenderInterface> via) {
|
||||
auto S = get_source_by_hash(dst);
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_query_via, S->get_adnl_id(),
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(name), std::move(promise),
|
||||
timeout, std::move(query), max_answer_size, via);
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::send_custom_message_data(PublicKeyHash dst, td::BufferSlice data) {
|
||||
auto S = get_source_by_hash(dst);
|
||||
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_message, S->get_adnl_id(),
|
||||
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(data));
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::block_written_to_db(CatChainBlockHash hash) {
|
||||
auto block = get_block(hash);
|
||||
CHECK(block);
|
||||
|
||||
block->written();
|
||||
run_scheduler();
|
||||
}
|
||||
|
||||
static void destroy_db(std::string name, td::uint32 attempt) {
|
||||
auto S = td::RocksDb::destroy(name);
|
||||
if (S.is_ok()) {
|
||||
return;
|
||||
}
|
||||
if (S.is_error() && attempt >= 10) {
|
||||
LOG(ERROR) << "failed to destroy catchain " << name << ": " << S;
|
||||
} else {
|
||||
LOG(DEBUG) << "failed to destroy catchain " << name << ": " << S;
|
||||
delay_action([name, attempt]() { destroy_db(name, attempt); }, td::Timestamp::in(1.0));
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainReceiverImpl::destroy() {
|
||||
auto name = db_root_ + "/catchainreceiver-" + td::base64url_encode(as_slice(incarnation_));
|
||||
delay_action([name]() { destroy_db(name, 0); }, td::Timestamp::in(1.0));
|
||||
stop();
|
||||
}
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
89
catchain/catchain-receiver.h
Normal file
89
catchain/catchain-receiver.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl/adnl.h"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "auto/tl/ton_api.h"
|
||||
|
||||
#include "catchain-types.h"
|
||||
#include "catchain-receiver-interface.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
constexpr int VERBOSITY_NAME(CATCHAIN_WARNING) = verbosity_WARNING;
|
||||
constexpr int VERBOSITY_NAME(CATCHAIN_NOTICE) = verbosity_DEBUG;
|
||||
constexpr int VERBOSITY_NAME(CATCHAIN_INFO) = verbosity_DEBUG;
|
||||
constexpr int VERBOSITY_NAME(CATCHAIN_DEBUG) = verbosity_DEBUG;
|
||||
constexpr int VERBOSITY_NAME(CATCHAIN_EXTRA_DEBUG) = verbosity_DEBUG + 1;
|
||||
|
||||
class CatChainReceivedBlock;
|
||||
class CatChainReceiverSource;
|
||||
|
||||
class CatChainReceiver : public CatChainReceiverInterface {
|
||||
public:
|
||||
struct PrintId {
|
||||
CatChainSessionId instance_;
|
||||
PublicKeyHash local_id_;
|
||||
};
|
||||
td::uint32 get_max_neighbours() const {
|
||||
return 5;
|
||||
}
|
||||
virtual PrintId print_id() const = 0;
|
||||
virtual CatChainReceivedBlock *create_block(tl_object_ptr<ton_api::catchain_block> block,
|
||||
td::SharedSlice payload) = 0;
|
||||
virtual CatChainReceivedBlock *create_block(tl_object_ptr<ton_api::catchain_block_dep> block) = 0;
|
||||
virtual CatChainReceiverSource *get_source(td::uint32 source_id) const = 0;
|
||||
virtual PublicKeyHash get_source_hash(td::uint32 source_id) const = 0;
|
||||
virtual td::uint32 get_forks_cnt() const = 0;
|
||||
virtual td::uint32 get_sources_cnt() const = 0;
|
||||
virtual CatChainSessionId get_incarnation() const = 0;
|
||||
virtual void run_block(CatChainReceivedBlock *block) = 0;
|
||||
virtual void deliver_block(CatChainReceivedBlock *block) = 0;
|
||||
virtual td::uint32 add_fork() = 0;
|
||||
virtual void add_prepared_event(td::BufferSlice data) = 0;
|
||||
virtual void on_blame(td::uint32 source_id) = 0;
|
||||
|
||||
virtual const CatChainOptions &opts() const = 0;
|
||||
|
||||
virtual td::Status validate_block_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) = 0;
|
||||
virtual td::Status validate_block_sync(tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) = 0;
|
||||
|
||||
virtual ~CatChainReceiver() = default;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceiver::PrintId &print_id) {
|
||||
sb << "[catchainreceiver " << print_id.instance_ << "@" << print_id.local_id_ << "]";
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceiver *catchain) {
|
||||
sb << catchain->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
240
catchain/catchain-receiver.hpp
Normal file
240
catchain/catchain-receiver.hpp
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
#include "catchain-types.h"
|
||||
#include "catchain-receiver.h"
|
||||
#include "catchain-receiver-source.h"
|
||||
#include "catchain-received-block.h"
|
||||
|
||||
#include "td/db/KeyValueAsync.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainReceiverImpl : public CatChainReceiver {
|
||||
public:
|
||||
PrintId print_id() const override {
|
||||
return PrintId{incarnation_, local_id_};
|
||||
}
|
||||
|
||||
void add_prepared_event(td::BufferSlice data) override {
|
||||
add_block(std::move(data), std::vector<CatChainBlockHash>());
|
||||
}
|
||||
CatChainSessionId get_incarnation() const override {
|
||||
return incarnation_;
|
||||
}
|
||||
void run_block(CatChainReceivedBlock *block) override;
|
||||
|
||||
td::uint32 get_forks_cnt() const override {
|
||||
return total_forks_;
|
||||
}
|
||||
td::uint32 get_sources_cnt() const override {
|
||||
return static_cast<td::uint32>(sources_.size());
|
||||
}
|
||||
|
||||
CatChainReceiverSource *get_source(td::uint32 source_id) const override {
|
||||
if (source_id >= get_sources_cnt()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sources_[source_id].get();
|
||||
}
|
||||
PublicKeyHash get_source_hash(td::uint32 source_id) const override;
|
||||
CatChainReceiverSource *get_source_by_hash(PublicKeyHash source_hash) const;
|
||||
CatChainReceiverSource *get_source_by_adnl_id(adnl::AdnlNodeIdShort source_hash) const;
|
||||
|
||||
td::uint32 add_fork() override;
|
||||
|
||||
void deliver_block(CatChainReceivedBlock *block) override;
|
||||
|
||||
void receive_message_from_overlay(adnl::AdnlNodeIdShort src, td::BufferSlice data);
|
||||
void receive_query_from_overlay(adnl::AdnlNodeIdShort src, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlock &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlocks &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlockHistory &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getDifference &query,
|
||||
td::Promise<td::BufferSlice> promise);
|
||||
template <class T>
|
||||
void process_query(adnl::AdnlNodeIdShort src, T &query, td::Promise<td::BufferSlice> promise) {
|
||||
//LOG(WARNING) << this << ": unknown query from " << src;
|
||||
callback_->on_custom_query(get_source_by_adnl_id(src)->get_hash(), serialize_tl_object(&query, true),
|
||||
std::move(promise));
|
||||
}
|
||||
void receive_broadcast_from_overlay(PublicKeyHash src, td::BufferSlice data);
|
||||
|
||||
void receive_block(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
|
||||
void receive_block_answer(adnl::AdnlNodeIdShort src, td::BufferSlice);
|
||||
//void send_block(PublicKeyHash src, tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
|
||||
|
||||
CatChainReceivedBlock *create_block(tl_object_ptr<ton_api::catchain_block> block, td::SharedSlice payload) override;
|
||||
CatChainReceivedBlock *create_block(tl_object_ptr<ton_api::catchain_block_dep> block) override;
|
||||
|
||||
td::Status validate_block_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) override;
|
||||
td::Status validate_block_sync(tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) override;
|
||||
|
||||
void send_fec_broadcast(td::BufferSlice data) override;
|
||||
void send_custom_query_data(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
|
||||
td::Timestamp timeout, td::BufferSlice query) override;
|
||||
void send_custom_query_data_via(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
|
||||
td::Timestamp timeout, td::BufferSlice query, td::uint64 max_answer_size,
|
||||
td::actor::ActorId<adnl::AdnlSenderInterface> via) override;
|
||||
void send_custom_message_data(PublicKeyHash dst, td::BufferSlice query) override;
|
||||
|
||||
void run_scheduler();
|
||||
void add_block(td::BufferSlice data, std::vector<CatChainBlockHash> deps) override;
|
||||
void add_block_cont(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
|
||||
void add_block_cont_2(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
|
||||
void add_block_cont_3(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
|
||||
void debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height,
|
||||
std::vector<CatChainBlockHash> deps) override;
|
||||
void debug_add_fork_cont(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
|
||||
void on_blame(td::uint32 src) override {
|
||||
callback_->blame(src);
|
||||
}
|
||||
void blame_node(td::uint32 idx) override {
|
||||
}
|
||||
const CatChainOptions &opts() const override {
|
||||
return opts_;
|
||||
}
|
||||
|
||||
void got_fork_proof(td::BufferSlice data);
|
||||
void synchronize_with(CatChainReceiverSource *source);
|
||||
void alarm() override;
|
||||
void start_up() override;
|
||||
void tear_down() override;
|
||||
void read_db();
|
||||
void read_db_from(CatChainBlockHash id);
|
||||
void read_block_from_db(CatChainBlockHash id, td::BufferSlice data);
|
||||
|
||||
void block_written_to_db(CatChainBlockHash hash);
|
||||
|
||||
void destroy() override;
|
||||
|
||||
CatChainReceivedBlock *get_block(CatChainBlockHash hash) const;
|
||||
|
||||
CatChainReceiverImpl(std::unique_ptr<Callback> callback, CatChainOptions opts,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<overlay::Overlays>, std::vector<CatChainNode> ids, PublicKeyHash local_id,
|
||||
CatChainBlockHash unique_hash, std::string db_root);
|
||||
|
||||
private:
|
||||
std::unique_ptr<overlay::Overlays::Callback> make_callback() {
|
||||
class Callback : public overlay::Overlays::Callback {
|
||||
public:
|
||||
void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id,
|
||||
td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &CatChainReceiverImpl::receive_message_from_overlay, src, std::move(data));
|
||||
}
|
||||
void receive_query(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
|
||||
td::Promise<td::BufferSlice> promise) override {
|
||||
td::actor::send_closure(id_, &CatChainReceiverImpl::receive_query_from_overlay, src, std::move(data),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void receive_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &CatChainReceiverImpl::receive_broadcast_from_overlay, src, std::move(data));
|
||||
}
|
||||
Callback(td::actor::ActorId<CatChainReceiverImpl> id) : id_(std::move(id)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<CatChainReceiverImpl> id_;
|
||||
};
|
||||
|
||||
return std::make_unique<Callback>(actor_id(this));
|
||||
}
|
||||
|
||||
struct PendingBlock {
|
||||
td::BufferSlice payload_;
|
||||
std::vector<CatChainBlockHash> deps_;
|
||||
|
||||
PendingBlock(td::BufferSlice &&payload, std::vector<CatChainBlockHash> &&deps)
|
||||
: payload_(std::move(payload)), deps_(std::move(deps)) {
|
||||
}
|
||||
};
|
||||
|
||||
std::list<std::unique_ptr<PendingBlock>> pending_blocks_;
|
||||
bool active_send_ = false;
|
||||
bool read_db_ = false;
|
||||
td::uint32 pending_in_db_ = 0;
|
||||
CatChainBlockHash db_root_block_ = CatChainBlockHash::zero();
|
||||
|
||||
void choose_neighbours();
|
||||
|
||||
std::vector<std::unique_ptr<CatChainReceiverSource>> sources_;
|
||||
std::map<PublicKeyHash, td::uint32> sources_hashes_;
|
||||
std::map<adnl::AdnlNodeIdShort, td::uint32> sources_adnl_addrs_;
|
||||
td::uint32 total_forks_ = 0;
|
||||
std::map<CatChainBlockHash, std::unique_ptr<CatChainReceivedBlock>> blocks_;
|
||||
CatChainReceivedBlock *root_block_;
|
||||
CatChainReceivedBlock *last_sent_block_;
|
||||
|
||||
CatChainSessionId incarnation_;
|
||||
|
||||
std::unique_ptr<Callback> callback_;
|
||||
CatChainOptions opts_;
|
||||
|
||||
std::vector<td::uint32> neighbours_;
|
||||
|
||||
//std::queue<tl_object_ptr<ton_api::catchain_block_inner_Data>> events_;
|
||||
//std::queue<td::BufferSlice> raw_events_;
|
||||
|
||||
td::actor::ActorId<keyring::Keyring> keyring_;
|
||||
td::actor::ActorId<adnl::Adnl> adnl_;
|
||||
td::actor::ActorId<overlay::Overlays> overlay_manager_;
|
||||
overlay::OverlayIdShort overlay_id_;
|
||||
overlay::OverlayIdFull overlay_full_id_;
|
||||
PublicKeyHash local_id_;
|
||||
td::uint32 local_idx_;
|
||||
|
||||
td::Timestamp next_sync_;
|
||||
td::Timestamp next_rotate_;
|
||||
|
||||
std::string db_root_;
|
||||
|
||||
using DbType = td::KeyValueAsync<CatChainBlockHash, td::BufferSlice>;
|
||||
DbType db_;
|
||||
|
||||
bool intentional_fork_ = false;
|
||||
|
||||
std::list<CatChainReceivedBlock *> to_run_;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceiverImpl *catchain) {
|
||||
sb << catchain->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
47
catchain/catchain-types.h
Normal file
47
catchain/catchain-types.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/int_types.h"
|
||||
#include "adnl/adnl-node-id.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
using CatChainBlockHash = td::Bits256;
|
||||
using CatChainBlockPayloadHash = td::Bits256;
|
||||
using CatChainBlockHeight = td::uint32;
|
||||
using CatChainSessionId = td::Bits256;
|
||||
|
||||
struct CatChainNode {
|
||||
adnl::AdnlNodeIdShort adnl_id;
|
||||
PublicKey pub_key;
|
||||
};
|
||||
|
||||
struct CatChainOptions {
|
||||
td::Clocks::Duration idle_timeout = 16.0;
|
||||
td::uint32 max_deps = 4;
|
||||
|
||||
bool debug_disable_db = false;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
317
catchain/catchain.cpp
Normal file
317
catchain/catchain.cpp
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "catchain-types.h"
|
||||
#include "catchain.hpp"
|
||||
#include "catchain-receiver.h"
|
||||
|
||||
#include "adnl/utils.hpp"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
void CatChainImpl::send_process() {
|
||||
CHECK(receiver_started_);
|
||||
|
||||
std::vector<CatChainBlock *> v;
|
||||
std::vector<CatChainBlockHash> w;
|
||||
while (top_blocks_.size() > 0 && v.size() < opts_.max_deps) {
|
||||
auto B = *top_blocks_.get_random();
|
||||
CHECK(B != nullptr);
|
||||
top_blocks_.remove(B->hash());
|
||||
if (B->source() == sources_.size() || !blamed_sources_[B->source()]) {
|
||||
w.push_back(B->hash());
|
||||
v.push_back(B);
|
||||
set_processed(B);
|
||||
}
|
||||
}
|
||||
|
||||
process_deps_ = std::move(w);
|
||||
VLOG(CATCHAIN_INFO) << this << ": creating block. deps=" << process_deps_;
|
||||
callback_->process_blocks(std::move(v));
|
||||
VLOG(CATCHAIN_INFO) << this << ": sent creating block";
|
||||
}
|
||||
|
||||
void CatChainImpl::send_preprocess(CatChainBlock *block) {
|
||||
if (block->preprocess_is_sent()) {
|
||||
return;
|
||||
}
|
||||
auto prev = block->prev();
|
||||
if (prev) {
|
||||
send_preprocess(prev);
|
||||
}
|
||||
|
||||
auto deps = block->deps();
|
||||
for (auto X : deps) {
|
||||
send_preprocess(X);
|
||||
}
|
||||
|
||||
block->preprocess_sent();
|
||||
VLOG(CATCHAIN_INFO) << this << ": preprocessing block " << block->hash() << " src=" << block->source();
|
||||
callback_->preprocess_block(block);
|
||||
VLOG(CATCHAIN_INFO) << this << ": sent preprocessing block " << block->hash() << " src=" << block->source();
|
||||
}
|
||||
|
||||
void CatChainImpl::set_processed(CatChainBlock *block) {
|
||||
if (block->is_processed()) {
|
||||
return;
|
||||
}
|
||||
auto prev = block->prev();
|
||||
if (prev) {
|
||||
set_processed(prev);
|
||||
}
|
||||
|
||||
auto deps = block->deps();
|
||||
for (auto X : deps) {
|
||||
set_processed(X);
|
||||
}
|
||||
|
||||
block->set_processed();
|
||||
}
|
||||
|
||||
void CatChainImpl::processed_block(td::BufferSlice payload) {
|
||||
CHECK(receiver_started_);
|
||||
VLOG(CATCHAIN_INFO) << this << ": created block. deps=" << process_deps_ << " payload_size=" << payload.size();
|
||||
td::actor::send_closure(receiver_, &CatChainReceiverInterface::add_block, std::move(payload),
|
||||
std::move(process_deps_));
|
||||
CHECK(active_process_);
|
||||
if (top_blocks_.size() > 0 || force_process_) {
|
||||
force_process_ = false;
|
||||
send_process();
|
||||
} else {
|
||||
active_process_ = false;
|
||||
VLOG(CATCHAIN_INFO) << this << ": finished processing";
|
||||
callback_->finished_processing();
|
||||
VLOG(CATCHAIN_INFO) << this << ": sent finished processing";
|
||||
alarm_timestamp() = td::Timestamp::in(opts_.idle_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainImpl::need_new_block(td::Timestamp t) {
|
||||
if (!receiver_started_) {
|
||||
return;
|
||||
}
|
||||
if (!force_process_) {
|
||||
VLOG(CATCHAIN_INFO) << this << ": forcing creation of new block";
|
||||
}
|
||||
force_process_ = true;
|
||||
if (!active_process_) {
|
||||
alarm_timestamp().relax(t);
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainImpl::on_new_block(td::uint32 src_id, td::uint32 fork, CatChainBlockHash hash, CatChainBlockHeight height,
|
||||
CatChainBlockHash prev, std::vector<CatChainBlockHash> deps,
|
||||
std::vector<CatChainBlockHeight> vt, td::SharedSlice data) {
|
||||
VLOG(CATCHAIN_DEBUG) << this << ": new block " << hash;
|
||||
if (top_blocks_.size() == 0 && !active_process_ && receiver_started_) {
|
||||
alarm_timestamp().relax(td::Timestamp::in(opts_.idle_timeout));
|
||||
}
|
||||
|
||||
CatChainBlock *p = nullptr;
|
||||
if (!prev.is_zero()) {
|
||||
p = get_block(prev);
|
||||
CHECK(p != nullptr);
|
||||
if (top_blocks_.exists(prev)) {
|
||||
top_blocks_.remove(prev);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CatChainBlock *> v;
|
||||
v.resize(deps.size());
|
||||
for (size_t i = 0; i < deps.size(); i++) {
|
||||
if (!blamed_sources_[src_id] && top_blocks_.exists(deps[i])) {
|
||||
top_blocks_.remove(deps[i]);
|
||||
}
|
||||
v[i] = get_block(deps[i]);
|
||||
CHECK(v[i] != nullptr);
|
||||
}
|
||||
|
||||
CHECK(src_id < sources_.size());
|
||||
auto src_hash = sources_[src_id];
|
||||
blocks_[hash] =
|
||||
CatChainBlock::create(src_id, fork, src_hash, height, hash, std::move(data), p, std::move(v), std::move(vt));
|
||||
|
||||
auto B = get_block(hash);
|
||||
CHECK(B != nullptr);
|
||||
|
||||
if (!blamed_sources_[src_id]) {
|
||||
send_preprocess(B);
|
||||
top_source_blocks_[src_id] = B;
|
||||
|
||||
if (src_id != local_idx_) {
|
||||
top_blocks_.insert(B->hash(), B);
|
||||
}
|
||||
|
||||
if (top_blocks_.size() == 0 && !active_process_ && receiver_started_) {
|
||||
alarm_timestamp().relax(td::Timestamp::in(opts_.idle_timeout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainImpl::on_blame(td::uint32 src_id) {
|
||||
if (blamed_sources_[src_id]) {
|
||||
return;
|
||||
}
|
||||
blamed_sources_[src_id] = true;
|
||||
top_source_blocks_[src_id] = nullptr;
|
||||
|
||||
// recompute top blocks
|
||||
top_blocks_.reset();
|
||||
auto size = static_cast<td::uint32>(sources_.size());
|
||||
for (td::uint32 i = 0; i < size; i++) {
|
||||
if (!blamed_sources_[i] && top_source_blocks_[i] && i != local_idx_) {
|
||||
auto B = top_source_blocks_[i];
|
||||
bool f = true;
|
||||
if (B->is_processed()) {
|
||||
continue;
|
||||
}
|
||||
for (td::uint32 j = 0; j < size; j++) {
|
||||
if (i != j && !blamed_sources_[j] && top_source_blocks_[j]) {
|
||||
if (top_source_blocks_[j]->is_descendant_of(B)) {
|
||||
f = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f) {
|
||||
top_blocks_.insert(B->hash(), B);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainImpl::on_custom_message(PublicKeyHash src, td::BufferSlice data) {
|
||||
callback_->process_message(src, std::move(data));
|
||||
}
|
||||
|
||||
void CatChainImpl::on_custom_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
|
||||
callback_->process_query(src, std::move(data), std::move(promise));
|
||||
}
|
||||
|
||||
void CatChainImpl::on_broadcast(PublicKeyHash src, td::BufferSlice data) {
|
||||
VLOG(CATCHAIN_INFO) << this << ": processing broadcast";
|
||||
callback_->process_broadcast(src, std::move(data));
|
||||
VLOG(CATCHAIN_INFO) << this << ": sent processing broadcast";
|
||||
}
|
||||
|
||||
void CatChainImpl::on_receiver_started() {
|
||||
receiver_started_ = true;
|
||||
callback_->started();
|
||||
CHECK(!active_process_);
|
||||
active_process_ = true;
|
||||
send_process();
|
||||
}
|
||||
|
||||
CatChainImpl::CatChainImpl(std::unique_ptr<Callback> callback, CatChainOptions opts,
|
||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<overlay::Overlays> overlay_manager, std::vector<CatChainNode> ids,
|
||||
PublicKeyHash local_id, CatChainSessionId unique_hash, std::string db_root)
|
||||
: opts_(std::move(opts)), db_root_(db_root) {
|
||||
callback_ = std::move(callback);
|
||||
sources_.resize(ids.size());
|
||||
unique_hash_ = unique_hash;
|
||||
for (size_t i = 0; i < ids.size(); i++) {
|
||||
sources_[i] = ids[i].pub_key.compute_short_id();
|
||||
if (sources_[i] == local_id) {
|
||||
local_idx_ = static_cast<td::uint32>(i);
|
||||
}
|
||||
}
|
||||
blamed_sources_.resize(ids.size(), false);
|
||||
top_source_blocks_.resize(ids.size(), nullptr);
|
||||
|
||||
args_ = std::make_unique<Args>(keyring, adnl, overlay_manager, std::move(ids), local_id, unique_hash);
|
||||
}
|
||||
|
||||
void CatChainImpl::alarm() {
|
||||
alarm_timestamp() = td::Timestamp::never();
|
||||
if (!active_process_) {
|
||||
active_process_ = true;
|
||||
send_process();
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainImpl::start_up() {
|
||||
class ChainCb : public CatChainReceiverInterface::Callback {
|
||||
public:
|
||||
void new_block(td::uint32 src_id, td::uint32 fork_id, CatChainBlockHash hash, CatChainBlockHeight height,
|
||||
CatChainBlockHash prev, std::vector<CatChainBlockHash> deps, std::vector<CatChainBlockHeight> vt,
|
||||
td::SharedSlice data) override {
|
||||
td::actor::send_closure(id_, &CatChainImpl::on_new_block, src_id, fork_id, hash, height, prev, std::move(deps),
|
||||
std::move(vt), std::move(data));
|
||||
}
|
||||
void blame(td::uint32 src_id) override {
|
||||
td::actor::send_closure(id_, &CatChainImpl::on_blame, src_id);
|
||||
}
|
||||
void on_custom_message(PublicKeyHash src, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &CatChainImpl::on_custom_message, src, std::move(data));
|
||||
}
|
||||
void on_custom_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
|
||||
td::actor::send_closure(id_, &CatChainImpl::on_custom_query, src, std::move(data), std::move(promise));
|
||||
}
|
||||
void on_broadcast(PublicKeyHash src, td::BufferSlice data) override {
|
||||
td::actor::send_closure(id_, &CatChainImpl::on_broadcast, src, std::move(data));
|
||||
}
|
||||
void start() override {
|
||||
td::actor::send_closure(id_, &CatChainImpl::on_receiver_started);
|
||||
}
|
||||
ChainCb(td::actor::ActorId<CatChainImpl> id) : id_(id) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorId<CatChainImpl> id_;
|
||||
};
|
||||
|
||||
auto cb = std::make_unique<ChainCb>(actor_id(this));
|
||||
|
||||
receiver_ =
|
||||
CatChainReceiverInterface::create(std::move(cb), opts_, args_->keyring, args_->adnl, args_->overlay_manager,
|
||||
std::move(args_->ids), args_->local_id, args_->unique_hash, db_root_);
|
||||
args_ = nullptr;
|
||||
//alarm_timestamp() = td::Timestamp::in(opts_.idle_timeout);
|
||||
}
|
||||
|
||||
td::actor::ActorOwn<CatChain> CatChain::create(std::unique_ptr<Callback> callback, CatChainOptions opts,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<overlay::Overlays> overlay_manager,
|
||||
std::vector<CatChainNode> ids, PublicKeyHash local_id,
|
||||
CatChainSessionId unique_hash, std::string db_root) {
|
||||
return td::actor::create_actor<CatChainImpl>("catchain", std::move(callback), std::move(opts), keyring, adnl,
|
||||
overlay_manager, std::move(ids), local_id, unique_hash, db_root);
|
||||
}
|
||||
|
||||
CatChainBlock *CatChainImpl::get_block(CatChainBlockHash hash) const {
|
||||
auto it = blocks_.find(hash);
|
||||
if (it == blocks_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return it->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
void CatChainImpl::destroy() {
|
||||
td::actor::send_closure(receiver_, &CatChainReceiverInterface::destroy);
|
||||
receiver_.release();
|
||||
stop();
|
||||
}
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
125
catchain/catchain.h
Normal file
125
catchain/catchain.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "adnl/adnl.h"
|
||||
#include "adnl/utils.hpp"
|
||||
#include "overlay/overlays.h"
|
||||
#include "catchain-types.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainBlock {
|
||||
public:
|
||||
class Extra {
|
||||
public:
|
||||
virtual ~Extra() = default;
|
||||
};
|
||||
virtual td::SharedSlice &payload() = 0;
|
||||
virtual const td::SharedSlice &payload() const = 0;
|
||||
virtual Extra *extra() const = 0;
|
||||
virtual std::unique_ptr<Extra> move_extra() = 0;
|
||||
virtual void set_extra(std::unique_ptr<Extra> extra) = 0;
|
||||
|
||||
virtual td::uint32 source() const = 0;
|
||||
virtual td::uint32 fork() const = 0;
|
||||
virtual PublicKeyHash source_hash() const = 0;
|
||||
virtual CatChainBlockHash hash() const = 0;
|
||||
virtual CatChainBlockHeight height() const = 0;
|
||||
|
||||
virtual CatChainBlock *prev() = 0;
|
||||
virtual const CatChainBlock *prev() const = 0;
|
||||
virtual const std::vector<CatChainBlock *> &deps() const = 0;
|
||||
virtual const std::vector<CatChainBlockHeight> &vt() const = 0;
|
||||
|
||||
virtual bool preprocess_is_sent() const = 0;
|
||||
virtual void preprocess_sent() = 0;
|
||||
|
||||
virtual bool is_processed() const = 0;
|
||||
virtual void set_processed() = 0;
|
||||
|
||||
virtual bool is_descendant_of(CatChainBlock *block) = 0;
|
||||
|
||||
static std::unique_ptr<CatChainBlock> create(td::uint32 src, td::uint32 fork_id, PublicKeyHash src_hash,
|
||||
CatChainBlockHeight height, CatChainBlockHash hash,
|
||||
td::SharedSlice payload, CatChainBlock *prev,
|
||||
std::vector<CatChainBlock *> deps, std::vector<CatChainBlockHeight> vt);
|
||||
|
||||
virtual ~CatChainBlock() = default;
|
||||
};
|
||||
|
||||
class CatChain : public td::actor::Actor {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
virtual void process_blocks(std::vector<CatChainBlock *> blocks) = 0;
|
||||
virtual void finished_processing() = 0;
|
||||
virtual void preprocess_block(CatChainBlock *block) = 0;
|
||||
virtual void process_broadcast(PublicKeyHash src, td::BufferSlice data) = 0;
|
||||
virtual void process_message(PublicKeyHash src, td::BufferSlice data) = 0;
|
||||
virtual void process_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
|
||||
virtual void started() = 0;
|
||||
virtual ~Callback() = default;
|
||||
};
|
||||
struct PrintId {
|
||||
CatChainSessionId instance_;
|
||||
PublicKeyHash local_id_;
|
||||
};
|
||||
virtual PrintId print_id() const = 0;
|
||||
virtual void processed_block(td::BufferSlice payload) = 0;
|
||||
virtual void need_new_block(td::Timestamp t) = 0;
|
||||
virtual void debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height) = 0;
|
||||
|
||||
virtual void send_broadcast(td::BufferSlice data) = 0;
|
||||
virtual void send_message(PublicKeyHash dst, td::BufferSlice data) = 0;
|
||||
virtual void send_query(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
|
||||
td::Timestamp timeout, td::BufferSlice query) = 0;
|
||||
virtual void send_query_via(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
|
||||
td::Timestamp timeout, td::BufferSlice query, td::uint64 max_answer_size,
|
||||
td::actor::ActorId<adnl::AdnlSenderInterface> via) = 0;
|
||||
virtual void destroy() = 0;
|
||||
|
||||
static td::actor::ActorOwn<CatChain> create(std::unique_ptr<Callback> callback, CatChainOptions opts,
|
||||
td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<overlay::Overlays> overlay_manager,
|
||||
std::vector<CatChainNode> ids, PublicKeyHash local_id,
|
||||
CatChainSessionId unique_hash, std::string db_root);
|
||||
virtual ~CatChain() = default;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChain::PrintId &print_id) {
|
||||
sb << "[catchain " << print_id.instance_ << "@" << print_id.local_id_ << "]";
|
||||
return sb;
|
||||
}
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChain *catchain) {
|
||||
sb << catchain->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
138
catchain/catchain.hpp
Normal file
138
catchain/catchain.hpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "catchain.h"
|
||||
#include "catchain-types.h"
|
||||
#include "catchain-receiver-interface.h"
|
||||
#include "td/utils/DecTree.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace catchain {
|
||||
|
||||
class CatChainImpl : public CatChain {
|
||||
private:
|
||||
std::unique_ptr<CatChain::Callback> callback_;
|
||||
CatChainOptions opts_;
|
||||
td::DecTree<CatChainBlockHash, CatChainBlock *> top_blocks_;
|
||||
std::map<CatChainBlockHash, std::unique_ptr<CatChainBlock>> blocks_;
|
||||
std::vector<CatChainBlock *> top_source_blocks_;
|
||||
|
||||
std::vector<PublicKeyHash> sources_;
|
||||
std::vector<bool> blamed_sources_;
|
||||
|
||||
std::vector<CatChainBlockHash> process_deps_;
|
||||
|
||||
CatChainSessionId unique_hash_;
|
||||
td::uint32 local_idx_;
|
||||
bool active_process_ = false;
|
||||
bool force_process_ = false;
|
||||
td::actor::ActorOwn<CatChainReceiverInterface> receiver_;
|
||||
|
||||
bool receiver_started_ = false;
|
||||
|
||||
std::string db_root_;
|
||||
|
||||
void send_process();
|
||||
void send_preprocess(CatChainBlock *block);
|
||||
void set_processed(CatChainBlock *block);
|
||||
|
||||
struct Args {
|
||||
td::actor::ActorId<keyring::Keyring> keyring;
|
||||
td::actor::ActorId<adnl::Adnl> adnl;
|
||||
td::actor::ActorId<overlay::Overlays> overlay_manager;
|
||||
std::vector<CatChainNode> ids;
|
||||
PublicKeyHash local_id;
|
||||
CatChainSessionId unique_hash;
|
||||
|
||||
Args(td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||
td::actor::ActorId<overlay::Overlays> overlay_manager, std::vector<CatChainNode> ids, PublicKeyHash local_id,
|
||||
CatChainSessionId unique_hash)
|
||||
: keyring(keyring)
|
||||
, adnl(adnl)
|
||||
, overlay_manager(overlay_manager)
|
||||
, ids(std::move(ids))
|
||||
, local_id(local_id)
|
||||
, unique_hash(unique_hash) {
|
||||
}
|
||||
};
|
||||
std::unique_ptr<Args> args_;
|
||||
|
||||
public:
|
||||
PrintId print_id() const override {
|
||||
return PrintId{unique_hash_, sources_[local_idx_]};
|
||||
}
|
||||
CatChainBlock *get_block(CatChainBlockHash hash) const;
|
||||
void on_new_block(td::uint32 src_id, td::uint32 fork, CatChainBlockHash hash, CatChainBlockHeight height,
|
||||
CatChainBlockHash prev, std::vector<CatChainBlockHash> deps, std::vector<CatChainBlockHeight> vt,
|
||||
td::SharedSlice data);
|
||||
void on_blame(td::uint32 src_id);
|
||||
void on_custom_message(PublicKeyHash src, td::BufferSlice data);
|
||||
void on_custom_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
|
||||
void on_broadcast(PublicKeyHash src, td::BufferSlice data);
|
||||
void on_receiver_started();
|
||||
void processed_block(td::BufferSlice payload) override;
|
||||
void need_new_block(td::Timestamp t) override;
|
||||
void debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height) override {
|
||||
td::actor::send_closure(receiver_, &CatChainReceiverInterface::debug_add_fork, std::move(payload), height,
|
||||
std::vector<CatChainBlockHash>{});
|
||||
}
|
||||
|
||||
void send_broadcast(td::BufferSlice data) override {
|
||||
td::actor::send_closure(receiver_, &CatChainReceiverInterface::send_fec_broadcast, std::move(data));
|
||||
}
|
||||
void send_message(PublicKeyHash dst, td::BufferSlice data) override {
|
||||
td::actor::send_closure(receiver_, &CatChainReceiverInterface::send_custom_message_data, dst, std::move(data));
|
||||
}
|
||||
void send_query(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
|
||||
td::BufferSlice query) override {
|
||||
td::actor::send_closure(receiver_, &CatChainReceiverInterface::send_custom_query_data, dst, name,
|
||||
std::move(promise), timeout, std::move(query));
|
||||
}
|
||||
void send_query_via(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
|
||||
td::BufferSlice query, td::uint64 max_answer_size,
|
||||
td::actor::ActorId<adnl::AdnlSenderInterface> via) override {
|
||||
td::actor::send_closure(receiver_, &CatChainReceiverInterface::send_custom_query_data_via, dst, name,
|
||||
std::move(promise), timeout, std::move(query), max_answer_size, via);
|
||||
}
|
||||
void destroy() override;
|
||||
CatChainImpl(std::unique_ptr<Callback> callback, CatChainOptions opts, td::actor::ActorId<keyring::Keyring> keyring,
|
||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<overlay::Overlays> overlay_manager,
|
||||
std::vector<CatChainNode> ids, PublicKeyHash local_id, CatChainSessionId unique_hash,
|
||||
std::string db_root);
|
||||
|
||||
void alarm() override;
|
||||
void start_up() override;
|
||||
};
|
||||
|
||||
} // namespace catchain
|
||||
|
||||
} // namespace ton
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainImpl *catchain) {
|
||||
sb << catchain->print_id();
|
||||
return sb;
|
||||
}
|
||||
|
||||
} // namespace td
|
21
common/CMakeLists.txt
Normal file
21
common/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
set(COMMON_SOURCE
|
||||
checksum.h
|
||||
errorcode.h
|
||||
status.h
|
||||
io.hpp
|
||||
|
||||
errorlog.h
|
||||
errorlog.cpp
|
||||
)
|
||||
|
||||
|
||||
add_library(common STATIC ${COMMON_SOURCE})
|
||||
|
||||
target_include_directories(common PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
target_link_libraries(common PRIVATE tdutils ton_crypto )
|
33
common/checksum.h
Normal file
33
common/checksum.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/int_types.h"
|
||||
#include "crypto/common/bitstring.h"
|
||||
#include "td/utils/crypto.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
inline Bits256 sha256_bits256(Slice data) {
|
||||
Bits256 id;
|
||||
sha256(data, id.as_slice());
|
||||
return id;
|
||||
}
|
||||
|
||||
} // namespace td
|
52
common/delay.h
Normal file
52
common/delay.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
template <typename T>
|
||||
class DelayedAction : public td::actor::Actor {
|
||||
public:
|
||||
DelayedAction(T promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
void set_timer(td::Timestamp t) {
|
||||
alarm_timestamp() = t;
|
||||
}
|
||||
void alarm() override {
|
||||
promise_();
|
||||
stop();
|
||||
}
|
||||
|
||||
static void create(T promise, td::Timestamp t) {
|
||||
auto A = td::actor::create_actor<DelayedAction>("delayed", std::move(promise));
|
||||
td::actor::send_closure(A, &DelayedAction::set_timer, t);
|
||||
A.release();
|
||||
}
|
||||
|
||||
private:
|
||||
T promise_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void delay_action(T promise, td::Timestamp timeout) {
|
||||
DelayedAction<T>::create(std::move(promise), timeout);
|
||||
}
|
||||
} // namespace ton
|
25
common/errorcode.h
Normal file
25
common/errorcode.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace ton {
|
||||
|
||||
enum ErrorCode : int { failure = 601, error = 602, warning = 603, protoviolation = 621, notready = 651, timeout = 652 };
|
||||
|
||||
}
|
74
common/errorlog.cpp
Normal file
74
common/errorlog.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "errorlog.h"
|
||||
#include "checksum.h"
|
||||
|
||||
#include "td/utils/port/FileFd.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/Time.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace errorlog {
|
||||
|
||||
td::FileFd fd;
|
||||
std::mutex init_mutex_;
|
||||
std::string files_path_;
|
||||
|
||||
void ErrorLog::create(std::string db_root) {
|
||||
init_mutex_.lock();
|
||||
if (!fd.empty()) {
|
||||
init_mutex_.unlock();
|
||||
return;
|
||||
}
|
||||
auto path = db_root + "/error";
|
||||
td::mkdir(path).ensure();
|
||||
files_path_ = path + "/files";
|
||||
td::mkdir(files_path_).ensure();
|
||||
auto R = td::FileFd::open(path + "/log.txt",
|
||||
td::FileFd::Flags::Write | td::FileFd::Flags::Append | td::FileFd::Flags::Create);
|
||||
R.ensure();
|
||||
fd = R.move_as_ok();
|
||||
init_mutex_.unlock();
|
||||
}
|
||||
|
||||
void ErrorLog::log(std::string error) {
|
||||
error = PSTRING() << "[" << td::Clocks::system() << "] " << error << "\n";
|
||||
CHECK(!fd.empty());
|
||||
auto s = td::Slice{error};
|
||||
while (s.size() > 0) {
|
||||
auto R = fd.write(s);
|
||||
R.ensure();
|
||||
s.remove_prefix(R.move_as_ok());
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorLog::log_file(td::BufferSlice data) {
|
||||
auto filename = sha256_bits256(data.as_slice());
|
||||
auto path = files_path_ + "/" + filename.to_hex();
|
||||
|
||||
td::write_file(path, data.as_slice()).ensure();
|
||||
}
|
||||
|
||||
} // namespace errorlog
|
||||
|
||||
} // namespace ton
|
37
common/errorlog.h
Normal file
37
common/errorlog.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "td/utils/buffer.h"
|
||||
|
||||
namespace ton {
|
||||
|
||||
namespace errorlog {
|
||||
|
||||
class ErrorLog {
|
||||
public:
|
||||
static void create(std::string db_root);
|
||||
static void log(std::string error);
|
||||
static void log_file(td::BufferSlice data);
|
||||
};
|
||||
|
||||
} // namespace errorlog
|
||||
|
||||
} // namespace ton
|
45
common/io.hpp
Normal file
45
common/io.hpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/base64.h"
|
||||
#include "tl-utils/tl-utils.hpp"
|
||||
|
||||
#include "common/errorcode.h"
|
||||
#include "common/status.h"
|
||||
#include "keys/keys.hpp"
|
||||
|
||||
#include "crypto/common/bitstring.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
template <unsigned size>
|
||||
StringBuilder &operator<<(StringBuilder &stream, const td::BitArray<size> &x) {
|
||||
return stream << td::base64_encode(as_slice(x));
|
||||
}
|
||||
|
||||
inline StringBuilder &operator<<(StringBuilder &stream, const ton::PublicKeyHash &value) {
|
||||
return stream << value.bits256_value();
|
||||
}
|
||||
|
||||
} // namespace td
|
33
common/status.h
Normal file
33
common/status.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
inline td::Status status_prefix(td::Status &&status, std::string prefix) {
|
||||
if (status.is_ok()) {
|
||||
return std::move(status);
|
||||
} else {
|
||||
return td::Status::Error(status.code(), prefix + status.message().str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
333
crypto/CMakeLists.txt
Normal file
333
crypto/CMakeLists.txt
Normal file
|
@ -0,0 +1,333 @@
|
|||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
endif()
|
||||
|
||||
set(TON_CRYPTO_SOURCE
|
||||
Ed25519.cpp
|
||||
common/bigint.cpp
|
||||
common/refcnt.cpp
|
||||
common/refint.cpp
|
||||
common/bitstring.cpp
|
||||
common/util.cpp
|
||||
ellcurve/Ed25519.cpp
|
||||
ellcurve/Fp25519.cpp
|
||||
ellcurve/Montgomery.cpp
|
||||
ellcurve/TwEdwards.cpp
|
||||
openssl/bignum.cpp
|
||||
openssl/residue.cpp
|
||||
openssl/rand.cpp
|
||||
vm/stack.cpp
|
||||
vm/atom.cpp
|
||||
vm/continuation.cpp
|
||||
vm/dict.cpp
|
||||
vm/dispatch.cpp
|
||||
vm/opctable.cpp
|
||||
vm/cp0.cpp
|
||||
vm/stackops.cpp
|
||||
vm/tupleops.cpp
|
||||
vm/arithops.cpp
|
||||
vm/cellops.cpp
|
||||
vm/contops.cpp
|
||||
vm/dictops.cpp
|
||||
vm/debugops.cpp
|
||||
vm/tonops.cpp
|
||||
vm/boc.cpp
|
||||
tl/tlblib.cpp
|
||||
|
||||
Ed25519.h
|
||||
common/AtomicRef.h
|
||||
common/bigint.hpp
|
||||
common/bitstring.h
|
||||
common/refcnt.hpp
|
||||
common/refint.h
|
||||
common/util.h
|
||||
|
||||
ellcurve/Ed25519.h
|
||||
ellcurve/Fp25519.h
|
||||
ellcurve/Montgomery.h
|
||||
ellcurve/TwEdwards.h
|
||||
|
||||
openssl/bignum.h
|
||||
openssl/digest.h
|
||||
openssl/rand.hpp
|
||||
openssl/residue.h
|
||||
|
||||
tl/tlbc-aux.h
|
||||
tl/tlbc-data.h
|
||||
tl/tlblib.hpp
|
||||
|
||||
vm/arithops.h
|
||||
vm/atom.h
|
||||
vm/boc.h
|
||||
vm/box.hpp
|
||||
vm/cellops.h
|
||||
vm/continuation.h
|
||||
vm/contops.h
|
||||
vm/cp0.h
|
||||
vm/debugops.h
|
||||
vm/dict.h
|
||||
vm/dictops.h
|
||||
vm/excno.hpp
|
||||
vm/fmt.hpp
|
||||
vm/log.h
|
||||
vm/opctable.h
|
||||
vm/stack.hpp
|
||||
vm/stackops.h
|
||||
vm/tupleops.h
|
||||
vm/tonops.h
|
||||
vm/vmstate.h
|
||||
|
||||
vm/cells.h
|
||||
vm/cellslice.h
|
||||
|
||||
vm/cells/Cell.cpp
|
||||
vm/cells/CellBuilder.cpp
|
||||
vm/cells/CellHash.cpp
|
||||
vm/cells/CellSlice.cpp
|
||||
vm/cells/CellTraits.cpp
|
||||
vm/cells/CellUsageTree.cpp
|
||||
vm/cells/DataCell.cpp
|
||||
vm/cells/LevelMask.cpp
|
||||
vm/cells/MerkleProof.cpp
|
||||
vm/cells/MerkleUpdate.cpp
|
||||
|
||||
vm/cells/Cell.h
|
||||
vm/cells/CellBuilder.h
|
||||
vm/cells/CellHash.h
|
||||
vm/cells/CellSlice.h
|
||||
vm/cells/CellTraits.h
|
||||
vm/cells/CellUsageTree.h
|
||||
vm/cells/CellWithStorage.h
|
||||
vm/cells/DataCell.h
|
||||
vm/cells/ExtCell.h
|
||||
vm/cells/LevelMask.h
|
||||
vm/cells/MerkleProof.h
|
||||
vm/cells/MerkleUpdate.h
|
||||
vm/cells/PrunnedCell.h
|
||||
vm/cells/UsageCell.h
|
||||
vm/cells/VirtualCell.h
|
||||
vm/cells/VirtualizationParameters.h
|
||||
|
||||
vm/db/StaticBagOfCellsDb.h
|
||||
vm/db/StaticBagOfCellsDb.cpp
|
||||
|
||||
vm/db/BlobView.h
|
||||
vm/db/BlobView.cpp
|
||||
)
|
||||
|
||||
set(TON_DB_SOURCE
|
||||
vm/db/DynamicBagOfCellsDb.cpp
|
||||
vm/db/CellStorage.cpp
|
||||
vm/db/TonDb.cpp
|
||||
|
||||
vm/db/DynamicBagOfCellsDb.h
|
||||
vm/db/CellHashTable.h
|
||||
vm/db/CellStorage.h
|
||||
vm/db/TonDb.h
|
||||
)
|
||||
|
||||
set(FIFT_SOURCE
|
||||
fift/Dictionary.cpp
|
||||
fift/Fift.cpp
|
||||
fift/IntCtx.cpp
|
||||
fift/SourceLookup.cpp
|
||||
fift/utils.cpp
|
||||
fift/words.cpp
|
||||
|
||||
fift/Dictionary.h
|
||||
fift/Fift.h
|
||||
fift/IntCtx.h
|
||||
fift/SourceLookup.h
|
||||
fift/utils.h
|
||||
fift/words.h
|
||||
)
|
||||
|
||||
set(PARSER_SOURCE
|
||||
parser/srcread.cpp
|
||||
parser/lexer.cpp
|
||||
parser/symtable.cpp
|
||||
|
||||
parser/srcread.h
|
||||
parser/lexer.h
|
||||
parser/symtable.h
|
||||
)
|
||||
|
||||
set(FUNC_LIB_SOURCE
|
||||
func/keywords.cpp
|
||||
func/unify-types.cpp
|
||||
func/parse-func.cpp
|
||||
func/abscode.cpp
|
||||
func/gen-abscode.cpp
|
||||
func/analyzer.cpp
|
||||
func/asmops.cpp
|
||||
func/builtins.cpp
|
||||
func/stack-transform.cpp
|
||||
func/optimize.cpp
|
||||
func/codegen.cpp
|
||||
)
|
||||
|
||||
set(TLB_BLOCK_AUTO
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/block/block-auto.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/block/block-auto.h
|
||||
)
|
||||
|
||||
set(BLOCK_SOURCE
|
||||
block/Binlog.h
|
||||
block/Binlog.cpp
|
||||
block/block.cpp
|
||||
block/block-db.cpp
|
||||
block/block-parse.cpp
|
||||
block/check-proof.cpp
|
||||
block/mc-config.cpp
|
||||
block/output-queue-merger.cpp
|
||||
block/transaction.cpp
|
||||
${TLB_BLOCK_AUTO}
|
||||
|
||||
block/block-binlog.h
|
||||
block/block-db-impl.h
|
||||
block/block-db.h
|
||||
block/block.h
|
||||
block/block-parse.h
|
||||
block/check-proof.h
|
||||
block/output-queue-merger.h
|
||||
block/transaction.h
|
||||
)
|
||||
|
||||
set(ED25519_TEST_SOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/Ed25519.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TONDB_TEST_SOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test-db.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(CELLS_TEST_SOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test-cells.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TONVM_TEST_SOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/vm.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(FIFT_TEST_SOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/fift.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
add_library(ton_crypto STATIC ${TON_CRYPTO_SOURCE})
|
||||
target_include_directories(ton_crypto PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(ton_crypto PUBLIC ${OPENSSL_CRYPTO_LIBRARY} tdutils)
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(ton_crypto PUBLIC dl z)
|
||||
endif()
|
||||
target_include_directories(ton_crypto SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
add_library(ton_db STATIC ${TON_DB_SOURCE})
|
||||
target_include_directories(ton_db PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(ton_db PUBLIC tdutils tddb ton_crypto)
|
||||
|
||||
add_executable(test-ed25519-crypto test/test-ed25519-crypto.cpp)
|
||||
target_include_directories(test-ed25519-crypto PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
target_link_libraries(test-ed25519-crypto PUBLIC ton_crypto)
|
||||
|
||||
add_library(fift-lib ${FIFT_SOURCE})
|
||||
target_include_directories(fift-lib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
target_link_libraries(fift-lib PUBLIC ton_crypto ton_db tdutils ton_block)
|
||||
set_target_properties(fift-lib PROPERTIES OUTPUT_NAME fift)
|
||||
|
||||
add_executable(fift fift/fift-main.cpp)
|
||||
target_link_libraries(fift PUBLIC fift-lib)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(fift wingetopt)
|
||||
endif()
|
||||
|
||||
add_library(src_parser ${PARSER_SOURCE})
|
||||
target_include_directories(src_parser PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
target_link_libraries(src_parser PUBLIC ton_crypto)
|
||||
|
||||
add_executable(func func/func.cpp ${FUNC_LIB_SOURCE})
|
||||
target_include_directories(func PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
target_link_libraries(func PUBLIC ton_crypto src_parser)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(func wingetopt)
|
||||
endif()
|
||||
|
||||
add_executable(tlbc tl/tlbc.cpp)
|
||||
target_include_directories(tlbc PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
target_link_libraries(tlbc PUBLIC ton_crypto src_parser)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(tlbc wingetopt)
|
||||
endif()
|
||||
|
||||
add_library(ton_block ${BLOCK_SOURCE})
|
||||
target_include_directories(ton_block PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/block> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(ton_block PUBLIC ton_crypto tdutils tdactor tl_api)
|
||||
|
||||
set(TURN_OFF_LSAN cd .)
|
||||
if (TON_USE_ASAN AND NOT WIN32)
|
||||
set(TURN_OFF_LSAN export LSAN_OPTIONS=detect_leaks=0)
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
set(GENERATE_TLB_CMD tlbc)
|
||||
add_custom_command(
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/block
|
||||
COMMAND ${TURN_OFF_LSAN}
|
||||
COMMAND ${GENERATE_TLB_CMD} -o block-auto -n block::gen -z block.tlb
|
||||
COMMENT "Generate block tlb source files"
|
||||
OUTPUT ${TLB_BLOCK_AUTO}
|
||||
DEPENDS tlbc block/block.tlb
|
||||
)
|
||||
add_custom_target(tlb_generate_block DEPENDS ${TLB_BLOCK_AUTO})
|
||||
add_dependencies(ton_block tlb_generate_block)
|
||||
|
||||
add_custom_target(gen_fif ALL)
|
||||
function(GenFif)
|
||||
set(options )
|
||||
set(oneValueArgs DEST)
|
||||
set(multiValueArgs SOURCE)
|
||||
set(FUNC_LIB_SOURCE smartcont/stdlib.fc)
|
||||
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
string(REGEX REPLACE "[^a-zA-Z_]" "_" ID ${ARG_DEST})
|
||||
add_custom_command(
|
||||
COMMENT "Generate ${ARG_DEST}"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMAND func -PS -o ${ARG_DEST} ${FUNC_LIB_SOURCE} ${ARG_SOURCE}
|
||||
MAIN_DEPENDENCY ${ARG_SOURCE}
|
||||
DEPENDS func ${FUNC_LIB_SOURCE}
|
||||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_DEST}
|
||||
)
|
||||
add_custom_target(gen_fif_${ID} DEPENDS ${ARG_DEST})
|
||||
add_dependencies(gen_fif gen_fif_${ID})
|
||||
endfunction()
|
||||
|
||||
GenFif(DEST smartcont/config-code.fif SOURCE smartcont/config-code.fc)
|
||||
GenFif(DEST smartcont/wallet-code.fif SOURCE smartcont/wallet-code.fc)
|
||||
GenFif(DEST smartcont/simple-wallet-code.fif SOURCE smartcont/simple-wallet-code.fc)
|
||||
GenFif(DEST smartcont/elector-code.fif SOURCE smartcont/elector-code.fc)
|
||||
endif()
|
||||
|
||||
add_executable(create-state block/create-state.cpp)
|
||||
target_include_directories(create-state PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(create-state PUBLIC ton_crypto fift-lib ton_block)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(create-state wingetopt)
|
||||
endif()
|
||||
|
||||
add_executable(test-block block/test-block.cpp)
|
||||
target_include_directories(test-block PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(test-block PUBLIC ton_crypto fift-lib ton_block)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(test-block wingetopt)
|
||||
endif()
|
394
crypto/Ed25519.cpp
Normal file
394
crypto/Ed25519.cpp
Normal file
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#include "crypto/Ed25519.h"
|
||||
|
||||
#if TD_HAVE_OPENSSL
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000L && OPENSSL_VERSION_NUMBER != 0x20000000L
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/BigNum.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#else
|
||||
|
||||
#include "crypto/ellcurve/Ed25519.h"
|
||||
|
||||
#endif
|
||||
|
||||
namespace td {
|
||||
|
||||
Ed25519::PublicKey::PublicKey(SecureString octet_string) : octet_string_(std::move(octet_string)) {
|
||||
}
|
||||
|
||||
SecureString Ed25519::PublicKey::as_octet_string() const {
|
||||
return octet_string_.copy();
|
||||
}
|
||||
|
||||
Ed25519::PrivateKey::PrivateKey(SecureString octet_string) : octet_string_(std::move(octet_string)) {
|
||||
}
|
||||
|
||||
SecureString Ed25519::PrivateKey::as_octet_string() const {
|
||||
return octet_string_.copy();
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000L && OPENSSL_VERSION_NUMBER != 0x20000000L
|
||||
|
||||
namespace detail {
|
||||
|
||||
static Result<SecureString> X25519_key_from_PKEY(EVP_PKEY *pkey, bool is_private) {
|
||||
auto func = is_private ? &EVP_PKEY_get_raw_private_key : &EVP_PKEY_get_raw_public_key;
|
||||
size_t len = 0;
|
||||
if (func(pkey, nullptr, &len) == 0) {
|
||||
return Status::Error("Failed to get raw key length");
|
||||
}
|
||||
CHECK(len == 32);
|
||||
|
||||
SecureString result(len);
|
||||
if (func(pkey, result.as_mutable_slice().ubegin(), &len) == 0) {
|
||||
return Status::Error("Failed to get raw key");
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
static EVP_PKEY *X25519_key_to_PKEY(Slice key, bool is_private) {
|
||||
auto func = is_private ? &EVP_PKEY_new_raw_private_key : &EVP_PKEY_new_raw_public_key;
|
||||
return func(EVP_PKEY_ED25519, nullptr, key.ubegin(), key.size());
|
||||
}
|
||||
|
||||
static Result<SecureString> X25519_pem_from_PKEY(EVP_PKEY *pkey, bool is_private, Slice password) {
|
||||
BIO *mem_bio = BIO_new(BIO_s_mem());
|
||||
SCOPE_EXIT {
|
||||
BIO_vfree(mem_bio);
|
||||
};
|
||||
if (is_private) {
|
||||
PEM_write_bio_PrivateKey(mem_bio, pkey, EVP_aes_256_cbc(), const_cast<unsigned char *>(password.ubegin()),
|
||||
narrow_cast<int>(password.size()), nullptr, nullptr);
|
||||
} else {
|
||||
PEM_write_bio_PUBKEY(mem_bio, pkey);
|
||||
}
|
||||
char *data_ptr = nullptr;
|
||||
auto data_size = BIO_get_mem_data(mem_bio, &data_ptr);
|
||||
return std::string(data_ptr, data_size);
|
||||
}
|
||||
|
||||
static int password_cb(char *buf, int size, int rwflag, void *u) {
|
||||
auto &password = *reinterpret_cast<Slice *>(u);
|
||||
auto password_size = narrow_cast<int>(password.size());
|
||||
if (size < password_size) {
|
||||
return -1;
|
||||
}
|
||||
if (rwflag == 0) {
|
||||
MutableSlice(buf, size).copy_from(password);
|
||||
}
|
||||
return password_size;
|
||||
}
|
||||
|
||||
static EVP_PKEY *X25519_pem_to_PKEY(Slice pem, Slice password) {
|
||||
BIO *mem_bio = BIO_new_mem_buf(pem.ubegin(), narrow_cast<int>(pem.size()));
|
||||
SCOPE_EXIT {
|
||||
BIO_vfree(mem_bio);
|
||||
};
|
||||
|
||||
return PEM_read_bio_PrivateKey(mem_bio, nullptr, password_cb, &password);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
Result<Ed25519::PrivateKey> Ed25519::generate_private_key() {
|
||||
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(NID_ED25519, nullptr);
|
||||
if (pctx == nullptr) {
|
||||
return Status::Error("Can't create EVP_PKEY_CTX");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
};
|
||||
|
||||
if (EVP_PKEY_keygen_init(pctx) <= 0) {
|
||||
return Status::Error("Can't init keygen");
|
||||
}
|
||||
|
||||
EVP_PKEY *pkey = nullptr;
|
||||
if (EVP_PKEY_keygen(pctx, &pkey) <= 0) {
|
||||
return Status::Error("Can't generate random private key");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_free(pkey);
|
||||
};
|
||||
|
||||
TRY_RESULT(private_key, detail::X25519_key_from_PKEY(pkey, true));
|
||||
return std::move(private_key);
|
||||
}
|
||||
|
||||
Result<Ed25519::PublicKey> Ed25519::PrivateKey::get_public_key() const {
|
||||
auto pkey = detail::X25519_key_to_PKEY(octet_string_, true);
|
||||
if (pkey == nullptr) {
|
||||
return Status::Error("Can't import private key");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_free(pkey);
|
||||
};
|
||||
|
||||
TRY_RESULT(key, detail::X25519_key_from_PKEY(pkey, false));
|
||||
return Ed25519::PublicKey(std::move(key));
|
||||
}
|
||||
|
||||
Result<SecureString> Ed25519::PrivateKey::as_pem(Slice password) const {
|
||||
auto pkey = detail::X25519_key_to_PKEY(octet_string_, true);
|
||||
if (pkey == nullptr) {
|
||||
return Status::Error("Can't import private key");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_free(pkey);
|
||||
};
|
||||
|
||||
return detail::X25519_pem_from_PKEY(pkey, true, password);
|
||||
}
|
||||
|
||||
Result<Ed25519::PrivateKey> Ed25519::PrivateKey::from_pem(Slice pem, Slice password) {
|
||||
auto pkey = detail::X25519_pem_to_PKEY(pem, password);
|
||||
if (pkey == nullptr) {
|
||||
return Status::Error("Can't import private key from pem");
|
||||
}
|
||||
TRY_RESULT(key, detail::X25519_key_from_PKEY(pkey, true));
|
||||
return Ed25519::PrivateKey(std::move(key));
|
||||
}
|
||||
|
||||
Result<SecureString> Ed25519::PrivateKey::sign(Slice data) const {
|
||||
auto pkey = detail::X25519_key_to_PKEY(octet_string_, true);
|
||||
if (pkey == nullptr) {
|
||||
return Status::Error("Can't import private key");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_free(pkey);
|
||||
};
|
||||
|
||||
EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
|
||||
if (md_ctx == nullptr) {
|
||||
return Status::Error("Can't create EVP_MD_CTX");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_MD_CTX_free(md_ctx);
|
||||
};
|
||||
|
||||
if (EVP_DigestSignInit(md_ctx, nullptr, nullptr, nullptr, pkey) <= 0) {
|
||||
return Status::Error("Can't init DigestSign");
|
||||
}
|
||||
|
||||
SecureString res(64, '\0');
|
||||
size_t len = 64;
|
||||
if (EVP_DigestSign(md_ctx, res.as_mutable_slice().ubegin(), &len, data.ubegin(), data.size()) <= 0) {
|
||||
return Status::Error("Can't sign data");
|
||||
}
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
Status Ed25519::PublicKey::verify_signature(Slice data, Slice signature) const {
|
||||
auto pkey = detail::X25519_key_to_PKEY(octet_string_, false);
|
||||
if (pkey == nullptr) {
|
||||
return Status::Error("Can't import public key");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_free(pkey);
|
||||
};
|
||||
|
||||
EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
|
||||
if (md_ctx == nullptr) {
|
||||
return Status::Error("Can't create EVP_MD_CTX");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_MD_CTX_free(md_ctx);
|
||||
};
|
||||
|
||||
if (EVP_DigestVerifyInit(md_ctx, nullptr, nullptr, nullptr, pkey) <= 0) {
|
||||
return Status::Error("Can't init DigestVerify");
|
||||
}
|
||||
|
||||
if (EVP_DigestVerify(md_ctx, signature.ubegin(), signature.size(), data.ubegin(), data.size())) {
|
||||
return Status::OK();
|
||||
}
|
||||
return Status::Error("Wrong signature");
|
||||
}
|
||||
|
||||
Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key) {
|
||||
BigNum p = BigNum::from_hex("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed").move_as_ok();
|
||||
auto public_y = public_key.as_octet_string();
|
||||
public_y.as_mutable_slice()[31] = static_cast<char>(public_y[31] & 127);
|
||||
BigNum y = BigNum::from_le_binary(public_y);
|
||||
BigNum y2 = y.clone();
|
||||
y += 1;
|
||||
y2 -= 1;
|
||||
|
||||
BigNumContext context;
|
||||
|
||||
BigNum::mod_sub(y2, p, y2, p, context);
|
||||
|
||||
BigNum inverse_y_plus_1;
|
||||
BigNum::mod_inverse(inverse_y_plus_1, y2, p, context);
|
||||
|
||||
BigNum u;
|
||||
BigNum::mod_mul(u, y, inverse_y_plus_1, p, context);
|
||||
|
||||
auto pr_key = private_key.as_octet_string();
|
||||
unsigned char buf[64];
|
||||
SHA512(Slice(pr_key).ubegin(), 32, buf);
|
||||
buf[0] &= 248;
|
||||
buf[31] &= 127;
|
||||
buf[31] |= 64;
|
||||
|
||||
auto pkey_private = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, nullptr, buf, 32);
|
||||
if (pkey_private == nullptr) {
|
||||
return Status::Error("Can't import private key");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_free(pkey_private);
|
||||
};
|
||||
// LOG(ERROR) << buffer_to_hex(Slice(buf, 32));
|
||||
|
||||
auto pub_key = u.to_le_binary(32);
|
||||
auto pkey_public = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, nullptr, Slice(pub_key).ubegin(), pub_key.size());
|
||||
if (pkey_public == nullptr) {
|
||||
return Status::Error("Can't import public key");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_free(pkey_public);
|
||||
};
|
||||
// LOG(ERROR) << buffer_to_hex(pub_key);
|
||||
|
||||
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey_private, nullptr);
|
||||
if (ctx == nullptr) {
|
||||
return Status::Error("Can't create EVP_PKEY_CTX");
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
};
|
||||
|
||||
if (EVP_PKEY_derive_init(ctx) <= 0) {
|
||||
return Status::Error("Can't init derive");
|
||||
}
|
||||
if (EVP_PKEY_derive_set_peer(ctx, pkey_public) <= 0) {
|
||||
return Status::Error("Can't init derive");
|
||||
}
|
||||
|
||||
size_t result_len = 0;
|
||||
if (EVP_PKEY_derive(ctx, nullptr, &result_len) <= 0) {
|
||||
return Status::Error("Can't get result length");
|
||||
}
|
||||
if (result_len != 32) {
|
||||
return Status::Error("Unexpected result length");
|
||||
}
|
||||
|
||||
SecureString result(result_len, '\0');
|
||||
if (EVP_PKEY_derive(ctx, result.as_mutable_slice().ubegin(), &result_len) <= 0) {
|
||||
return Status::Error("Failed to compute shared secret");
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Result<Ed25519::PrivateKey> Ed25519::generate_private_key() {
|
||||
crypto::Ed25519::PrivateKey private_key;
|
||||
if (!private_key.random_private_key(true)) {
|
||||
return Status::Error("Can't generate random private key");
|
||||
}
|
||||
SecureString private_key_buf(32);
|
||||
if (!private_key.export_private_key(private_key_buf.as_mutable_slice())) {
|
||||
return Status::Error("Failed to export private key");
|
||||
}
|
||||
return PrivateKey(std::move(private_key_buf));
|
||||
}
|
||||
|
||||
Result<Ed25519::PublicKey> Ed25519::PrivateKey::get_public_key() const {
|
||||
crypto::Ed25519::PrivateKey private_key;
|
||||
if (!private_key.import_private_key(Slice(octet_string_).ubegin())) {
|
||||
return Status::Error("Bad private key");
|
||||
}
|
||||
SecureString public_key(32);
|
||||
if (!private_key.get_public_key().export_public_key(public_key.as_mutable_slice())) {
|
||||
return Status::Error("Failed to export public key");
|
||||
}
|
||||
return PublicKey(std::move(public_key));
|
||||
}
|
||||
|
||||
Result<SecureString> Ed25519::PrivateKey::as_pem(Slice password) const {
|
||||
return Status::Error("Not supported");
|
||||
}
|
||||
|
||||
Result<Ed25519::PrivateKey> Ed25519::PrivateKey::from_pem(Slice pem, Slice password) {
|
||||
return Status::Error("Not supported");
|
||||
}
|
||||
|
||||
Result<SecureString> Ed25519::PrivateKey::sign(Slice data) const {
|
||||
crypto::Ed25519::PrivateKey private_key;
|
||||
if (!private_key.import_private_key(Slice(octet_string_).ubegin())) {
|
||||
return Status::Error("Bad private key");
|
||||
}
|
||||
SecureString signature(crypto::Ed25519::sign_bytes, '\0');
|
||||
if (!private_key.sign_message(signature.as_mutable_slice(), data)) {
|
||||
return Status::Error("Failed to sign message");
|
||||
}
|
||||
return std::move(signature);
|
||||
}
|
||||
|
||||
Status Ed25519::PublicKey::verify_signature(Slice data, Slice signature) const {
|
||||
if (signature.size() != crypto::Ed25519::sign_bytes) {
|
||||
return Status::Error("Signature has invalid length");
|
||||
}
|
||||
|
||||
crypto::Ed25519::PublicKey public_key;
|
||||
if (!public_key.import_public_key(Slice(octet_string_).ubegin())) {
|
||||
return Status::Error("Bad public key");
|
||||
}
|
||||
if (public_key.check_message_signature(signature, data)) {
|
||||
return Status::OK();
|
||||
}
|
||||
return Status::Error("Wrong signature");
|
||||
}
|
||||
|
||||
Result<SecureString> Ed25519::compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key) {
|
||||
crypto::Ed25519::PrivateKey tmp_private_key;
|
||||
if (!tmp_private_key.import_private_key(Slice(private_key.as_octet_string()).ubegin())) {
|
||||
return Status::Error("Bad private key");
|
||||
}
|
||||
crypto::Ed25519::PublicKey tmp_public_key;
|
||||
if (!tmp_public_key.import_public_key(Slice(public_key.as_octet_string()).ubegin())) {
|
||||
return Status::Error("Bad public key");
|
||||
}
|
||||
SecureString shared_secret(32, '\0');
|
||||
if (!tmp_private_key.compute_shared_secret(shared_secret.as_mutable_slice(), tmp_public_key)) {
|
||||
return Status::Error("Failed to compute shared secret");
|
||||
}
|
||||
return std::move(shared_secret);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace td
|
||||
|
||||
#endif
|
72
crypto/Ed25519.h
Normal file
72
crypto/Ed25519.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#if TD_HAVE_OPENSSL
|
||||
|
||||
namespace td {
|
||||
|
||||
class Ed25519 {
|
||||
public:
|
||||
class PublicKey {
|
||||
public:
|
||||
static constexpr size_t LENGTH = 32;
|
||||
|
||||
explicit PublicKey(SecureString octet_string);
|
||||
|
||||
SecureString as_octet_string() const;
|
||||
|
||||
Status verify_signature(Slice data, Slice signature) const;
|
||||
|
||||
private:
|
||||
SecureString octet_string_;
|
||||
};
|
||||
|
||||
class PrivateKey {
|
||||
public:
|
||||
static constexpr size_t LENGTH = 32;
|
||||
|
||||
explicit PrivateKey(SecureString octet_string);
|
||||
|
||||
SecureString as_octet_string() const;
|
||||
|
||||
Result<PublicKey> get_public_key() const;
|
||||
|
||||
Result<SecureString> sign(Slice data) const;
|
||||
|
||||
Result<SecureString> as_pem(Slice password) const;
|
||||
|
||||
static Result<PrivateKey> from_pem(Slice pem, Slice password);
|
||||
|
||||
private:
|
||||
SecureString octet_string_;
|
||||
};
|
||||
|
||||
static Result<PrivateKey> generate_private_key();
|
||||
|
||||
static Result<SecureString> compute_shared_secret(const PublicKey &public_key, const PrivateKey &private_key);
|
||||
};
|
||||
|
||||
} // namespace td
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue