commit
ca8265f123
@ -0,0 +1,4 @@
|
||||
[submodule "src/xmregcore"]
|
||||
path = src/xmregcore
|
||||
url = https://github.com/moneroexamples/xmregcore
|
||||
branch = master
|
@ -0,0 +1,159 @@
|
||||
# Generated by YCM Generator at 2019-02-04 16:43:28.957650
|
||||
|
||||
# This file is NOT licensed under the GPLv3, which is the license for the rest
|
||||
# of YouCompleteMe.
|
||||
#
|
||||
# Here's the license text for this file:
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
import os
|
||||
import ycm_core
|
||||
|
||||
flags = [
|
||||
'-x',
|
||||
'c++',
|
||||
'-DASIO_STANDALONE=YES',
|
||||
'-DBUILD_SSL=TRUE',
|
||||
'-I/home/mwo2/monero/build',
|
||||
'-I/home/mwo2/monero/contrib/epee/include',
|
||||
'-I/home/mwo2/monero/external',
|
||||
'-I/home/mwo2/monero/external/db_drivers/liblmdb',
|
||||
'-I/home/mwo2/monero/external/easylogging++',
|
||||
'-I/home/mwo2/monero/src',
|
||||
'-I/home/mwo2/openmonero/ext/restbed/source',
|
||||
'-I/home/mwo2/openmonero/src/xmregcore',
|
||||
'-I/usr/include/mysql',
|
||||
'-I/usr/local/include',
|
||||
'-I/usr/local/include/mysql',
|
||||
'-I/usr/local/opt/openssl/include',
|
||||
'-Wall',
|
||||
'-Weffc++',
|
||||
'-Wextra',
|
||||
'-Wno-unknown-pragmas',
|
||||
'-std=c++14',
|
||||
'-std=gnu++14',
|
||||
'-isystem', '/home/mwo2/openmonero/ext/restbed/dependency/asio/asio/include',
|
||||
'-isystem', '/home/mwo2/openmonero/ext/restbed/dependency/kashmir',
|
||||
]
|
||||
|
||||
|
||||
# Set this to the absolute path to the folder (NOT the file!) containing the
|
||||
# compile_commands.json file to use that instead of 'flags'. See here for
|
||||
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
#
|
||||
# You can get CMake to generate this file for you by adding:
|
||||
# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
|
||||
# to your CMakeLists.txt file.
|
||||
#
|
||||
# Most projects will NOT need to set this to anything; you can just change the
|
||||
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
|
||||
compilation_database_folder = ''
|
||||
|
||||
if os.path.exists( compilation_database_folder ):
|
||||
database = ycm_core.CompilationDatabase( compilation_database_folder )
|
||||
else:
|
||||
database = None
|
||||
|
||||
SOURCE_EXTENSIONS = [ '.C', '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
|
||||
|
||||
def DirectoryOfThisScript():
|
||||
return os.path.dirname( os.path.abspath( __file__ ) )
|
||||
|
||||
|
||||
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
|
||||
if not working_directory:
|
||||
return list( flags )
|
||||
new_flags = []
|
||||
make_next_absolute = False
|
||||
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
|
||||
for flag in flags:
|
||||
new_flag = flag
|
||||
|
||||
if make_next_absolute:
|
||||
make_next_absolute = False
|
||||
if not flag.startswith( '/' ):
|
||||
new_flag = os.path.join( working_directory, flag )
|
||||
|
||||
for path_flag in path_flags:
|
||||
if flag == path_flag:
|
||||
make_next_absolute = True
|
||||
break
|
||||
|
||||
if flag.startswith( path_flag ):
|
||||
path = flag[ len( path_flag ): ]
|
||||
new_flag = path_flag + os.path.join( working_directory, path )
|
||||
break
|
||||
|
||||
if new_flag:
|
||||
new_flags.append( new_flag )
|
||||
return new_flags
|
||||
|
||||
|
||||
def IsHeaderFile( filename ):
|
||||
extension = os.path.splitext( filename )[ 1 ]
|
||||
return extension in [ '.H', '.h', '.hxx', '.hpp', '.hh' ]
|
||||
|
||||
|
||||
def GetCompilationInfoForFile( filename ):
|
||||
# The compilation_commands.json file generated by CMake does not have entries
|
||||
# for header files. So we do our best by asking the db for flags for a
|
||||
# corresponding source file, if any. If one exists, the flags for that file
|
||||
# should be good enough.
|
||||
if IsHeaderFile( filename ):
|
||||
basename = os.path.splitext( filename )[ 0 ]
|
||||
for extension in SOURCE_EXTENSIONS:
|
||||
replacement_file = basename + extension
|
||||
if os.path.exists( replacement_file ):
|
||||
compilation_info = database.GetCompilationInfoForFile(
|
||||
replacement_file )
|
||||
if compilation_info.compiler_flags_:
|
||||
return compilation_info
|
||||
return None
|
||||
return database.GetCompilationInfoForFile( filename )
|
||||
|
||||
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
if database:
|
||||
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
|
||||
# python list, but a "list-like" StringVec object
|
||||
compilation_info = GetCompilationInfoForFile( filename )
|
||||
if not compilation_info:
|
||||
return None
|
||||
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute(
|
||||
compilation_info.compiler_flags_,
|
||||
compilation_info.compiler_working_dir_ )
|
||||
|
||||
else:
|
||||
relative_to = DirectoryOfThisScript()
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
|
||||
|
||||
return {
|
||||
'flags': final_flags,
|
||||
'do_cache': True
|
||||
}
|
||||
|
@ -1,77 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# CMake helper for the majority of the cpp-ethereum modules.
|
||||
#
|
||||
# This module defines
|
||||
# Monero_XXX_LIBRARIES, the libraries needed to use ethereum.
|
||||
# Monero_FOUND, If false, do not try to use ethereum.
|
||||
#
|
||||
# File addetped from cpp-ethereum
|
||||
#
|
||||
# The documentation for cpp-ethereum is hosted at http://cpp-ethereum.org
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
# This file is part of cpp-ethereum.
|
||||
#
|
||||
# cpp-ethereum 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
# (c) 2014-2016 cpp-ethereum contributors.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
set(LIBS common;blocks;cryptonote_basic;cryptonote_core;
|
||||
cryptonote_protocol;daemonizer;mnemonics;epee;lmdb;device;
|
||||
blockchain_db;ringct;wallet;cncrypto;easylogging;version;checkpoints)
|
||||
|
||||
set(Xmr_INCLUDE_DIRS "${CPP_MONERO_DIR}")
|
||||
|
||||
# if the project is a subset of main cpp-ethereum project
|
||||
# use same pattern for variables as Boost uses
|
||||
|
||||
foreach (l ${LIBS})
|
||||
|
||||
string(TOUPPER ${l} L)
|
||||
|
||||
find_library(Xmr_${L}_LIBRARY
|
||||
NAMES ${l}
|
||||
PATHS ${CMAKE_LIBRARY_PATH}
|
||||
PATH_SUFFIXES "/src/${l}" "/src/" "/external/db_drivers/lib${l}" "/lib" "/src/crypto" "/contrib/epee/src" "/external/easylogging++/"
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
set(Xmr_${L}_LIBRARIES ${Xmr_${L}_LIBRARY})
|
||||
|
||||
message(STATUS FindMonero " Xmr_${L}_LIBRARIES ${Xmr_${L}_LIBRARY}")
|
||||
|
||||
add_library(${l} STATIC IMPORTED)
|
||||
set_property(TARGET ${l} PROPERTY IMPORTED_LOCATION ${Xmr_${L}_LIBRARIES})
|
||||
|
||||
endforeach()
|
||||
|
||||
|
||||
if (EXISTS ${MONERO_BUILD_DIR}/src/ringct/libringct_basic.a)
|
||||
message(STATUS FindMonero " found libringct_basic.a")
|
||||
add_library(ringct_basic STATIC IMPORTED)
|
||||
set_property(TARGET ringct_basic
|
||||
PROPERTY IMPORTED_LOCATION ${MONERO_BUILD_DIR}/src/ringct/libringct_basic.a)
|
||||
endif()
|
||||
|
||||
message(STATUS ${MONERO_SOURCE_DIR}/build)
|
||||
|
||||
# include monero headers
|
||||
include_directories(
|
||||
${MONERO_SOURCE_DIR}/src
|
||||
${MONERO_SOURCE_DIR}/external
|
||||
${MONERO_SOURCE_DIR}/build
|
||||
${MONERO_SOURCE_DIR}/external/easylogging++
|
||||
${MONERO_SOURCE_DIR}/contrib/epee/include
|
||||
${MONERO_SOURCE_DIR}/external/db_drivers/liblmdb)
|
@ -1,96 +0,0 @@
|
||||
|
||||
macro(configure_files srcDir destDir)
|
||||
message(STATUS "Configuring directory ${destDir}")
|
||||
make_directory(${destDir})
|
||||
|
||||
file(GLOB templateFiles RELATIVE ${srcDir} ${srcDir}/*)
|
||||
foreach(templateFile ${templateFiles})
|
||||
set(srcTemplatePath ${srcDir}/${templateFile})
|
||||
if(NOT IS_DIRECTORY ${srcTemplatePath})
|
||||
message(STATUS "Configuring file ${templateFile}")
|
||||
configure_file(
|
||||
${srcTemplatePath}
|
||||
${destDir}/${templateFile}
|
||||
@ONLY)
|
||||
endif(NOT IS_DIRECTORY ${srcTemplatePath})
|
||||
endforeach(templateFile)
|
||||
endmacro(configure_files)
|
||||
|
||||
macro(create_git_version)
|
||||
# Get the current working branch
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_BRANCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# http://xit0.org/2013/04/cmake-use-git-branch-and-commit-details-in-project/
|
||||
# Get the latest abbreviated commit hash of the working branch
|
||||
execute_process(
|
||||
COMMAND git log -1 --format=%h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Get the date and time of last commit
|
||||
execute_process(
|
||||
COMMAND git log -1 --format=%cd --date=short
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_DATETIME
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Get current branch name
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_BRANCH_NAME
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/src/version.h.in
|
||||
${CMAKE_BINARY_DIR}/gen/version.h
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR}/gen)
|
||||
|
||||
endmacro(create_git_version)
|
||||
|
||||
|
||||
|
||||
macro(resource_dir srcDir)
|
||||
# Scan through resource folder for updated files and copy if none existing or changed
|
||||
file (GLOB_RECURSE resources "${srcDir}/*.*")
|
||||
foreach(resource ${resources})
|
||||
get_filename_component(filename ${resource} NAME)
|
||||
get_filename_component(dir ${resource} DIRECTORY)
|
||||
get_filename_component(dirname ${dir} NAME)
|
||||
|
||||
set(topdir ${dirname})
|
||||
|
||||
set (output "")
|
||||
|
||||
while(NOT ${dirname} STREQUAL ${srcDir})
|
||||
get_filename_component(path_component ${dir} NAME)
|
||||
set (output "${path_component}/${output}")
|
||||
get_filename_component(dir ${dir} DIRECTORY)
|
||||
get_filename_component(dirname ${dir} NAME)
|
||||
endwhile()
|
||||
|
||||
set(output "${CMAKE_CURRENT_BINARY_DIR}/${topdir}/${filename}")
|
||||
|
||||
add_custom_command(
|
||||
COMMENT "Moving updated resource-file '${filename}' to ${output}"
|
||||
OUTPUT ${output}
|
||||
DEPENDS ${resource}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${resource}
|
||||
${output}
|
||||
)
|
||||
add_custom_target(${filename} ALL DEPENDS ${resource} ${output})
|
||||
|
||||
endforeach()
|
||||
endmacro(resource_dir)
|
@ -1,18 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
# now build myext library from other files
|
||||
project(myext)
|
||||
|
||||
# first build mstch template library
|
||||
add_subdirectory("restbed")
|
||||
|
||||
set(SOURCE_FILES
|
||||
format.cc)
|
||||
|
||||
# make static library called libmyxrm
|
||||
# that we are going to link to
|
||||
# in the root CMakeLists.txt file
|
||||
add_library(myext
|
||||
STATIC
|
||||
${SOURCE_FILES})
|
||||
|
||||
|
@ -0,0 +1,254 @@
|
||||
/**
|
||||
* The ThreadPool class.
|
||||
* Keeps a set of threads constantly waiting to execute incoming jobs.
|
||||
* source: http://roar11.com/2016/01/a-platform-independent-thread-pool-using-c14/
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef THREADPOOL_HPP
|
||||
#define THREADPOOL_HPP
|
||||
|
||||
#include "ThreadSafeQueue.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace TP
|
||||
{
|
||||
class ThreadPool
|
||||
{
|
||||
private:
|
||||
class IThreadTask
|
||||
{
|
||||
public:
|
||||
IThreadTask(void) = default;
|
||||
virtual ~IThreadTask(void) = default;
|
||||
IThreadTask(const IThreadTask& rhs) = delete;
|
||||
IThreadTask& operator=(const IThreadTask& rhs) = delete;
|
||||
IThreadTask(IThreadTask&& other) = default;
|
||||
IThreadTask& operator=(IThreadTask&& other) = default;
|
||||
|
||||
/**
|
||||
* Run the task.
|
||||
*/
|
||||
virtual void execute() = 0;
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
class ThreadTask: public IThreadTask
|
||||
{
|
||||
public:
|
||||
ThreadTask(Func&& func)
|
||||
:m_func{std::move(func)}
|
||||
{
|
||||
}
|
||||
|
||||
~ThreadTask(void) override = default;
|
||||
ThreadTask(const ThreadTask& rhs) = delete;
|
||||
ThreadTask& operator=(const ThreadTask& rhs) = delete;
|
||||
ThreadTask(ThreadTask&& other) = default;
|
||||
ThreadTask& operator=(ThreadTask&& other) = default;
|
||||
|
||||
/**
|
||||
* Run the task.
|
||||
*/
|
||||
void execute() override
|
||||
{
|
||||
m_func();
|
||||
}
|
||||
|
||||
private:
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* A wrapper around a std::future that adds the behavior of futures returned from
|
||||
std::async.
|
||||
* Specifically, this object will block and wait for execution to finish before going out
|
||||
of scope.
|
||||
*/
|
||||
template <typename T>
|
||||
class TaskFuture
|
||||
{
|
||||
public:
|
||||
TaskFuture(std::future<T>&& future)
|
||||
:m_future{std::move(future)}
|
||||
{
|
||||
}
|
||||
|
||||
TaskFuture(const TaskFuture& rhs) = delete;
|
||||
TaskFuture& operator=(const TaskFuture& rhs) = delete;
|
||||
TaskFuture(TaskFuture&& other) = default;
|
||||
TaskFuture& operator=(TaskFuture&& other) = default;
|
||||
~TaskFuture(void)
|
||||
{
|
||||
if(m_future.valid())
|
||||
{
|
||||
m_future.get();
|
||||
}
|
||||
}
|
||||
|
||||
auto get(void)
|
||||
{
|
||||
return m_future.get();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::future<T> m_future;
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
ThreadPool(void)
|
||||
:ThreadPool{std::max(std::thread::hardware_concurrency()/2, 2u) - 1u}
|
||||
{
|
||||
/*
|
||||
* Always create at least one thread. If hardware_concurrency() returns 0,
|
||||
* subtracting one would turn it to UINT_MAX, so get the maximum of
|
||||
* hardware_concurrency() and 2 before subtracting 1.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
explicit ThreadPool(const std::uint32_t numThreads)
|
||||
:m_done{false},
|
||||
m_workQueue{},
|
||||
m_threads{}
|
||||
{
|
||||
try
|
||||
{
|
||||
for(std::uint32_t i = 0u; i < numThreads; ++i)
|
||||
{
|
||||
m_threads.emplace_back(&ThreadPool::worker, this);
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
destroy();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-copyable.
|
||||
*/
|
||||
ThreadPool(const ThreadPool& rhs) = delete;
|
||||
|
||||
/**
|
||||
* Non-assignable.
|
||||
*/
|
||||
ThreadPool& operator=(const ThreadPool& rhs) = delete;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~ThreadPool(void)
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
auto queueSize() const
|
||||
{
|
||||
return m_workQueue.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a job to be run by the thread pool.
|
||||
*/
|
||||
template <typename Func, typename... Args>
|
||||
auto submit(Func&& func, Args&&... args)
|
||||
{
|
||||
auto boundTask = std::bind(std::forward<Func>(func), std::forward<Args>(args)...);
|
||||
using ResultType = std::result_of_t<decltype(boundTask)()>;
|
||||
using PackagedTask = std::packaged_task<ResultType()>;
|
||||
using TaskType = ThreadTask<PackagedTask>;
|
||||
|
||||
PackagedTask task{std::move(boundTask)};
|
||||
TaskFuture<ResultType> result{task.get_future()};
|
||||
m_workQueue.push(std::make_unique<TaskType>(std::move(task)));
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constantly running function each thread uses to acquire work items from the queue.
|
||||
*/
|
||||
void worker(void)
|
||||
{
|
||||
while(!m_done)
|
||||
{
|
||||
std::unique_ptr<IThreadTask> pTask{nullptr};
|
||||
if(m_workQueue.waitPop(pTask))
|
||||
{
|
||||
pTask->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the queue and joins all running threads.
|
||||
*/
|
||||
void destroy(void)
|
||||
{
|
||||
m_done = true;
|
||||
m_workQueue.invalidate();
|
||||
for(auto& thread : m_threads)
|
||||
{
|
||||
if(thread.joinable())
|
||||
{
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_bool m_done;
|
||||
ThreadSafeQueue<std::unique_ptr<IThreadTask>> m_workQueue;
|
||||
std::vector<std::thread> m_threads;
|
||||
};
|
||||
|
||||
namespace DefaultThreadPool
|
||||
{
|
||||
/**
|
||||
* Get the default thread pool for the application.
|
||||
* This pool is created with std::thread::hardware_concurrency() - 1 threads.
|
||||
*/
|
||||
inline ThreadPool& getThreadPool(void)
|
||||
{
|
||||
static ThreadPool defaultPool;
|
||||
return defaultPool;
|
||||
}
|
||||
|
||||
inline auto queueSize()
|
||||
{
|
||||
return getThreadPool().queueSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a job to the default thread pool.
|
||||
*/
|
||||
template <typename Func, typename... Args>
|
||||
inline auto submitJob(Func&& func, Args&&... args)
|
||||
{
|
||||
return getThreadPool().submit(
|
||||
std::forward<Func>(func),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* The ThreadSafeQueue class.
|
||||
* Provides a wrapper around a basic queue to provide thread safety.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef THREADSAFEQUEUE_HPP
|
||||
#define THREADSAFEQUEUE_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
namespace TP
|
||||
{
|
||||
template <typename T>
|
||||
class ThreadSafeQueue
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~ThreadSafeQueue(void)
|
||||
{
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the first value in the queue.
|
||||
* Returns true if a value was successfully written to the out parameter, false
|
||||
otherwise.
|
||||
*/
|
||||
bool tryPop(T& out)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
if(m_queue.empty() || !m_valid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
out = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first value in the queue.
|
||||
* Will block until a value is available unless clear is called or the instance is
|
||||
destructed.
|
||||
* Returns true if a value was successfully written to the out parameter, false
|
||||
otherwise.
|
||||
*/
|
||||
bool waitPop(T& out)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{m_mutex};
|
||||
m_condition.wait(lock, [this]()
|
||||
{
|
||||
return !m_queue.empty() || !m_valid;
|
||||
});
|
||||
/*
|
||||
* Using the condition in the predicate ensures that spurious wakeups with a valid
|
||||
* but empty queue will not proceed, so only need to check for validity before
|
||||
proceeding.
|
||||
*/
|
||||
if(!m_valid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
out = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a new value onto the queue.
|
||||
*/
|
||||
void push(T value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
m_queue.push(std::move(value));
|
||||
m_condition.notify_one();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not the queue is empty.
|
||||
*/
|
||||
bool empty(void) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_queue.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all items from the queue.
|
||||
*/
|
||||
void clear(void)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
while(!m_queue.empty())
|
||||
{
|
||||
m_queue.pop();
|
||||
}
|
||||
m_condition.notify_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the queue.
|
||||
* Used to ensure no conditions are being waited on in waitPop when
|
||||
* a thread or the application is trying to exit.
|
||||
* The queue is invalid after calling this method and it is an error
|
||||
* to continue using a queue after this method has been called.
|
||||
*/
|
||||
void invalidate(void)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
m_valid = false;
|
||||
m_condition.notify_all();
|
||||
|
||||
}
|
||||
|
||||
auto size() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_queue.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this queue is valid.
|
||||
*/
|
||||
bool isValid(void) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_bool m_valid{true};
|
||||
mutable std::mutex m_mutex;
|
||||
std::queue<T> m_queue;
|
||||
std::condition_variable m_condition;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,544 +0,0 @@
|
||||
/*
|
||||
Formatting library for C++
|
||||
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
|
||||
#if defined(_WIN32) && defined(__MINGW32__)
|
||||
# include <cstring>
|
||||
#endif
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
|
||||
# include <windows.h>
|
||||
# else
|
||||
# define NOMINMAX
|
||||
# include <windows.h>
|
||||
# undef NOMINMAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
using fmt::internal::Arg;
|
||||
|
||||
#if FMT_EXCEPTIONS
|
||||
# define FMT_TRY try
|
||||
# define FMT_CATCH(x) catch (x)
|
||||
#else
|
||||
# define FMT_TRY if (true)
|
||||
# define FMT_CATCH(x) if (false)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4127) // conditional expression is constant
|
||||
# pragma warning(disable: 4702) // unreachable code
|
||||
// Disable deprecation warning for strerror. The latter is not called but
|
||||
// MSVC fails to detect it.
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
// Dummy implementations of strerror_r and strerror_s called if corresponding
|
||||
// system functions are not available.
|
||||
static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
|
||||
return fmt::internal::Null<>();
|
||||
}
|
||||
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
|
||||
return fmt::internal::Null<>();
|
||||
}
|
||||
|
||||
namespace fmt {
|
||||
|
||||
FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}
|
||||
FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {}
|
||||
FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {}
|
||||
|
||||
namespace {
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# define FMT_SNPRINTF snprintf
|
||||
#else // _MSC_VER
|
||||
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
# define FMT_SNPRINTF fmt_snprintf
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||
# define FMT_SWPRINTF snwprintf
|
||||
#else
|
||||
# define FMT_SWPRINTF swprintf
|
||||
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||
|
||||
const char RESET_COLOR[] = "\x1b[0m";
|
||||
|
||||
typedef void (*FormatFunc)(Writer &, int, StringRef);
|
||||
|
||||
// Portable thread-safe version of strerror.
|
||||
// Sets buffer to point to a string describing the error code.
|
||||
// This can be either a pointer to a string stored in buffer,
|
||||
// or a pointer to some static immutable string.
|
||||
// Returns one of the following values:
|
||||
// 0 - success
|
||||
// ERANGE - buffer is not large enough to store the error message
|
||||
// other - failure
|
||||
// Buffer should be at least of size 1.
|
||||
int safe_strerror(
|
||||
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
|
||||
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
|
||||
|
||||
class StrError {
|
||||
private:
|
||||
int error_code_;
|
||||
char *&buffer_;
|
||||
std::size_t buffer_size_;
|
||||
|
||||
// A noop assignment operator to avoid bogus warnings.
|
||||
void operator=(const StrError &) {}
|
||||
|
||||
// Handle the result of XSI-compliant version of strerror_r.
|
||||
int handle(int result) {
|
||||
// glibc versions before 2.13 return result in errno.
|
||||
return result == -1 ? errno : result;
|
||||
}
|
||||
|
||||
// Handle the result of GNU-specific version of strerror_r.
|
||||
int handle(char *message) {
|
||||
// If the buffer is full then the message is probably truncated.
|
||||
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
|
||||
return ERANGE;
|
||||
buffer_ = message;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Handle the case when strerror_r is not available.
|
||||
int handle(internal::Null<>) {
|
||||
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
|
||||
}
|
||||
|
||||
// Fallback to strerror_s when strerror_r is not available.
|
||||
int fallback(int result) {
|
||||
// If the buffer is full then the message is probably truncated.
|
||||
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
|
||||
ERANGE : result;
|
||||
}
|
||||
|
||||
// Fallback to strerror if strerror_r and strerror_s are not available.
|
||||
int fallback(internal::Null<>) {
|
||||
errno = 0;
|
||||
buffer_ = strerror(error_code_);
|
||||
return errno;
|
||||
}
|
||||
|
||||
public:
|
||||
StrError(int err_code, char *&buf, std::size_t buf_size)
|
||||
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
|
||||
|
||||
int run() {
|
||||
// Suppress a warning about unused strerror_r.
|
||||
strerror_r(0, FMT_NULL, "");
|
||||
return handle(strerror_r(error_code_, buffer_, buffer_size_));
|
||||
}
|
||||
};
|
||||
return StrError(error_code, buffer, buffer_size).run();
|
||||
}
|
||||
|
||||
void format_error_code(Writer &out, int error_code,
|
||||
StringRef message) FMT_NOEXCEPT {
|
||||
// Report error code making sure that the output fits into
|
||||
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
|
||||
// bad_alloc.
|
||||
out.clear();
|
||||
static const char SEP[] = ": ";
|
||||
static const char ERROR_STR[] = "error ";
|
||||
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
|
||||
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
|
||||
typedef internal::IntTraits<int>::MainType MainType;
|
||||
MainType abs_value = static_cast<MainType>(error_code);
|
||||
if (internal::is_negative(error_code)) {
|
||||
abs_value = 0 - abs_value;
|
||||
++error_code_size;
|
||||
}
|
||||
error_code_size += internal::count_digits(abs_value);
|
||||
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
|
||||
out << message << SEP;
|
||||
out << ERROR_STR << error_code;
|
||||
assert(out.size() <= internal::INLINE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void report_error(FormatFunc func, int error_code,
|
||||
StringRef message) FMT_NOEXCEPT {
|
||||
MemoryWriter full_message;
|
||||
func(full_message, error_code, message);
|
||||
// Use Writer::data instead of Writer::c_str to avoid potential memory
|
||||
// allocation.
|
||||
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
|
||||
std::fputc('\n', stderr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
// This method is used to preserve binary compatibility with fmt 3.0.
|
||||
// It can be removed in 4.0.
|
||||
FMT_FUNC void format_system_error(
|
||||
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
fmt::format_system_error(out, error_code, message);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
FMT_FUNC void SystemError::init(
|
||||
int err_code, CStringRef format_str, ArgList args) {
|
||||
error_code_ = err_code;
|
||||
MemoryWriter w;
|
||||
format_system_error(w, err_code, format(format_str, args));
|
||||
std::runtime_error &base = *this;
|
||||
base = std::runtime_error(w.str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int internal::CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, T value) {
|
||||
if (width == 0) {
|
||||
return precision < 0 ?
|
||||
FMT_SNPRINTF(buffer, size, format, value) :
|
||||
FMT_SNPRINTF(buffer, size, format, precision, value);
|
||||
}
|
||||
return precision < 0 ?
|
||||
FMT_SNPRINTF(buffer, size, format, width, value) :
|
||||
FMT_SNPRINTF(buffer, size, format, width, precision, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int internal::CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, T value) {
|
||||
if (width == 0) {
|
||||
return precision < 0 ?
|
||||
FMT_SWPRINTF(buffer, size, format, value) :
|
||||
FMT_SWPRINTF(buffer, size, format, precision, value);
|
||||
}
|
||||
return precision < 0 ?
|
||||
FMT_SWPRINTF(buffer, size, format, width, value) :
|
||||
FMT_SWPRINTF(buffer, size, format, width, precision, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const char internal::BasicData<T>::DIGITS[] =
|
||||
"0001020304050607080910111213141516171819"
|
||||
"2021222324252627282930313233343536373839"
|
||||
"4041424344454647484950515253545556575859"
|
||||
"6061626364656667686970717273747576777879"
|
||||
"8081828384858687888990919293949596979899";
|
||||
|
||||
#define FMT_POWERS_OF_10(factor) \
|
||||
factor * 10, \
|
||||
factor * 100, \
|
||||
factor * 1000, \
|
||||
factor * 10000, \
|
||||
factor * 100000, \
|
||||
factor * 1000000, \
|
||||
factor * 10000000, \
|
||||
factor * 100000000, \
|
||||
factor * 1000000000
|
||||
|
||||
template <typename T>
|
||||
const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
|
||||
0, FMT_POWERS_OF_10(1)
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
|
||||
0,
|
||||
FMT_POWERS_OF_10(1),
|
||||
FMT_POWERS_OF_10(ULongLong(1000000000)),
|
||||
// Multiply several constants instead of using a single long long constant
|
||||
// to avoid warnings about C++98 not supporting long long.
|
||||
ULongLong(1000000000) * ULongLong(1000000000) * 10
|
||||
};
|
||||
|
||||
FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
|
||||
(void)type;
|
||||
if (std::isprint(static_cast<unsigned char>(code))) {
|
||||
FMT_THROW(FormatError(
|
||||
format("unknown format code '{}' for {}", code, type)));
|
||||
}
|
||||
FMT_THROW(FormatError(
|
||||
format("unknown format code '\\x{:02x}' for {}",
|
||||
static_cast<unsigned>(code), type)));
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
|
||||
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
|
||||
if (s.size() > INT_MAX)
|
||||
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
|
||||
int s_size = static_cast<int>(s.size());
|
||||
int length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
|
||||
if (length == 0)
|
||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||
buffer_.resize(length + 1);
|
||||
length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
|
||||
if (length == 0)
|
||||
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
|
||||
buffer_[length] = 0;
|
||||
}
|
||||
|
||||
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
|
||||
if (int error_code = convert(s)) {
|
||||
FMT_THROW(WindowsError(error_code,
|
||||
"cannot convert string from UTF-16 to UTF-8"));
|
||||
}
|
||||
}
|
||||
|
||||
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
|
||||
if (s.size() > INT_MAX)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
int s_size = static_cast<int>(s.size());
|
||||
int length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_.resize(length + 1);
|
||||
length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_FUNC void WindowsError::init(
|
||||
int err_code, CStringRef format_str, ArgList args) {
|
||||
error_code_ = err_code;
|
||||
MemoryWriter w;
|
||||
internal::format_windows_error(w, err_code, format(format_str, args));
|
||||
std::runtime_error &base = *this;
|
||||
base = std::runtime_error(w.str());
|
||||
}
|
||||
|
||||
FMT_FUNC void internal::format_windows_error(
|
||||
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
|
||||
buffer.resize(INLINE_BUFFER_SIZE);
|
||||
for (;;) {
|
||||
wchar_t *system_message = &buffer[0];
|
||||
int result = FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);
|
||||
if (result != 0) {
|
||||
UTF16ToUTF8 utf8_message;
|
||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||
out << message << ": " << utf8_message;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
break; // Can't get error message, report error code instead.
|
||||
buffer.resize(buffer.size() * 2);
|
||||
}
|
||||
} FMT_CATCH(...) {}
|
||||
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
|
||||
}
|
||||
|
||||
#endif // FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC void format_system_error(
|
||||
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
|
||||
buffer.resize(internal::INLINE_BUFFER_SIZE);
|
||||
for (;;) {
|
||||
char *system_message = &buffer[0];
|
||||
int result = safe_strerror(error_code, system_message, buffer.size());
|
||||
if (result == 0) {
|
||||
out << message << ": " << system_message;
|
||||
return;
|
||||
}
|
||||
if (result != ERANGE)
|
||||
break; // Can't get error message, report error code instead.
|
||||
buffer.resize(buffer.size() * 2);
|
||||
}
|
||||
} FMT_CATCH(...) {}
|
||||
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void internal::ArgMap<Char>::init(const ArgList &args) {
|
||||
if (!map_.empty())
|
||||
return;
|
||||
typedef internal::NamedArg<Char> NamedArg;
|
||||
const NamedArg *named_arg = FMT_NULL;
|
||||
bool use_values =
|
||||
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
|
||||
if (use_values) {
|
||||
for (unsigned i = 0;/*nothing*/; ++i) {
|
||||
internal::Arg::Type arg_type = args.type(i);
|
||||
switch (arg_type) {
|
||||
case internal::Arg::NONE:
|
||||
return;
|
||||
case internal::Arg::NAMED_ARG:
|
||||
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
|
||||
map_.push_back(Pair(named_arg->name, *named_arg));
|
||||
break;
|
||||
default:
|
||||
/*nothing*/;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
|
||||
internal::Arg::Type arg_type = args.type(i);
|
||||
if (arg_type == internal::Arg::NAMED_ARG) {
|
||||
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
||||
map_.push_back(Pair(named_arg->name, *named_arg));
|
||||
}
|
||||
}
|
||||
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
|
||||
switch (args.args_[i].type) {
|
||||
case internal::Arg::NONE:
|
||||
return;
|
||||
case internal::Arg::NAMED_ARG:
|
||||
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
||||
map_.push_back(Pair(named_arg->name, *named_arg));
|
||||
break;
|
||||
default:
|
||||
/*nothing*/;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void internal::FixedBuffer<Char>::grow(std::size_t) {
|
||||
FMT_THROW(std::runtime_error("buffer overflow"));
|
||||
}
|
||||
|
||||
FMT_FUNC Arg internal::FormatterBase::do_get_arg(
|
||||
unsigned arg_index, const char *&error) {
|
||||
Arg arg = args_[arg_index];
|
||||
switch (arg.type) {
|
||||
case Arg::NONE:
|
||||
error = "argument index out of range";
|
||||
break;
|
||||
case Arg::NAMED_ARG:
|
||||
arg = *static_cast<const internal::Arg*>(arg.pointer);
|
||||
break;
|
||||
default:
|
||||
/*nothing*/;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
FMT_FUNC void report_system_error(
|
||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
||||
// 'fmt::' is for bcc32.
|
||||
report_error(format_system_error, error_code, message);
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC void report_windows_error(
|
||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
||||
// 'fmt::' is for bcc32.
|
||||
report_error(internal::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
|
||||
MemoryWriter w;
|
||||
w.write(format_str, args);
|
||||
std::fwrite(w.data(), 1, w.size(), f);
|
||||
}
|
||||
|
||||
FMT_FUNC void print(CStringRef format_str, ArgList args) {
|
||||
print(stdout, format_str, args);
|
||||
}
|
||||
|
||||
FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
|
||||
char escape[] = "\x1b[30m";
|
||||
escape[3] = static_cast<char>('0' + c);
|
||||
std::fputs(escape, stdout);
|
||||
print(format, args);
|
||||
std::fputs(RESET_COLOR, stdout);
|
||||
}
|
||||
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
|
||||
template struct internal::BasicData<void>;
|
||||
|
||||
// Explicit instantiations for char.
|
||||
|
||||
template void internal::FixedBuffer<char>::grow(std::size_t);
|
||||
|
||||
template void internal::ArgMap<char>::init(const ArgList &args);
|
||||
|
||||
template int internal::CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, double value);
|
||||
|
||||
template int internal::CharTraits<char>::format_float(
|
||||
char *buffer, std::size_t size, const char *format,
|
||||
unsigned width, int precision, long double value);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
|
||||
|
||||
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
|
||||
|
||||
template int internal::CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, double value);
|
||||
|
||||
template int internal::CharTraits<wchar_t>::format_float(
|
||||
wchar_t *buffer, std::size_t size, const wchar_t *format,
|
||||
unsigned width, int precision, long double value);
|
||||
|
||||
#endif // FMT_HEADER_ONLY
|
||||
|
||||
} // namespace fmt
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,241 +0,0 @@
|
||||
//
|
||||
// Created by mwo on 5/11/15.
|
||||
//
|
||||
|
||||
#include "MicroCore.h"
|
||||
|
||||
|
||||
namespace xmreg
|
||||
{
|
||||
|
||||
/**
|
||||
* The constructor is interesting, as
|
||||
* m_mempool and m_blockchain_storage depend
|
||||
* on each other.
|
||||
*
|
||||
* So basically m_mempool is initialized with
|
||||
* reference to Blockchain (i.e., Blockchain&)
|
||||
* and m_blockchain_storage is initialized with
|
||||
* reference to m_mempool (i.e., tx_memory_pool&)
|
||||
*
|
||||
* The same is done in cryptonode::core.
|
||||
*/
|
||||
MicroCore::MicroCore():
|
||||
m_mempool(core_storage),
|
||||
core_storage(m_mempool),
|
||||
m_device {&hw::get_device("default")}
|
||||
{
|
||||
|
||||
}
|
||||
/**
|
||||
* Initialized the MicroCore object.
|
||||
*
|
||||
* Create BlockchainLMDB on the heap.
|
||||
* Open database files located in blockchain_path.
|
||||
* Initialize m_blockchain_storage with the BlockchainLMDB object.
|
||||
*/
|
||||
bool
|
||||
MicroCore::init(const string& _blockchain_path, network_type nt)
|
||||
{
|
||||
blockchain_path = _blockchain_path;
|
||||
|
||||
nettype = nt;
|
||||
|
||||
std::unique_ptr<BlockchainDB> db = std::make_unique<BlockchainLMDB>();
|
||||
|
||||
try
|
||||
{
|
||||
// try opening lmdb database files
|
||||
db->open(blockchain_path, DBF_RDONLY);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
cerr << "Error opening database: " << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if the blockchain database
|
||||
// is successful opened
|
||||
if(!db->is_open())
|
||||
return false;
|
||||
|
||||
// initialize Blockchain object to manage
|
||||
// the database.
|
||||
if (!core_storage.init(db.release(), nettype))
|
||||
{
|
||||
cerr << "Error opening database: core_storage->init(db, nettype)\n" ;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_mempool.init())
|
||||
{
|
||||
cerr << "Error opening database: m_mempool.init()\n" ;
|
||||
return false;
|
||||
}
|
||||
|
||||
initialization_succeded = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get m_blockchain_storage.
|
||||
* Initialize m_blockchain_storage with the BlockchainLMDB object.
|
||||
*/
|
||||
Blockchain const&
|
||||
MicroCore::get_core() const
|
||||
{
|
||||
return core_storage;
|
||||
}
|
||||
|
||||
tx_memory_pool const&
|
||||
MicroCore::get_mempool() const
|
||||
{
|
||||
return m_mempool;
|
||||
}
|
||||
|
||||
bool
|
||||
MicroCore::get_block_from_height(uint64_t height, block& blk) const
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
blk = core_storage.get_db().get_block_from_height(height);
|
||||
}
|
||||
catch (const exception& e)
|
||||
{
|
||||
cerr << e.what() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MicroCore::get_block_complete_entry(block const& b, block_complete_entry& bce)
|
||||
{
|
||||
bce.block = cryptonote::block_to_blob(b);
|
||||
|
||||
for (const auto &tx_hash: b.tx_hashes)
|
||||
{
|
||||
transaction tx;
|
||||
|
||||
if (!get_tx(tx_hash, tx))
|
||||
return false;
|
||||
|
||||
cryptonote::blobdata txblob = tx_to_blob(tx);
|
||||
|
||||
bce.txs.push_back(txblob);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MicroCore::get_tx(crypto::hash const& tx_hash, transaction& tx) const
|
||||
{
|
||||
if (core_storage.have_tx(tx_hash))
|
||||
{
|
||||
// get transaction with given hash
|
||||
tx = core_storage.get_db().get_tx(tx_hash);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MicroCore::get_output_histogram(
|
||||
vector<uint64_t> const& amounts,
|
||||
uint64_t min_count,
|
||||
histogram_map& histogram,
|
||||
bool unlocked,
|
||||
uint64_t recent_cutoff) const
|
||||
{
|
||||
try
|
||||
{
|
||||
histogram = core_storage.get_output_histogram(
|
||||
amounts,
|
||||
unlocked,
|
||||
recent_cutoff,
|
||||
min_count);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
cerr << e.what() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MicroCore::get_output_histogram(
|
||||
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request const& req,
|
||||
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res) const
|
||||
{
|
||||
// based on bool core_rpc_server::on_get_output_histogram(const ...
|
||||
|
||||
MicroCore::histogram_map histogram;
|
||||
|
||||
if (!get_output_histogram(req.amounts,
|
||||
req.min_count,
|
||||
histogram,
|
||||
req.unlocked,
|
||||
req.recent_cutoff))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
res.histogram.clear();
|
||||
res.histogram.reserve(histogram.size());
|
||||
|
||||
for (auto const& i: histogram)
|
||||
{
|
||||
if (std::get<0>(i.second)
|
||||
>= req.min_count
|
||||
&& (std::get<0>(i.second) <= req.max_count
|
||||
|| req.max_count == 0))
|
||||
res.histogram.push_back(
|
||||
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry(
|
||||
i.first,
|
||||
std::get<0>(i.second),
|
||||
std::get<1>(i.second),
|
||||
std::get<2>(i.second)));
|
||||
}
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
hw::device* const
|
||||
MicroCore::get_device() const
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
bool
|
||||
MicroCore::init_success() const
|
||||
{
|
||||
return initialization_succeded;
|
||||
}
|
||||
|
||||
MicroCore::~MicroCore()
|
||||
{
|
||||
//cout << "\n\nMicroCore::~MicroCore()\n\n";
|
||||
|
||||
if (initialization_succeded)
|
||||
{
|
||||
//core_storage.get_db().safesyncmode(true);
|
||||
if (core_storage.get_db().is_open())
|
||||
core_storage.get_db().close();
|
||||
//cout << "\n\n core_storage.get_db().close();;\n\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,212 +0,0 @@
|
||||
//
|
||||
// Created by mwo on 5/11/15.
|
||||
//
|
||||
|
||||
#ifndef XMREG01_MICROCORE_H
|
||||
#define XMREG01_MICROCORE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
#include "monero_headers.h"
|
||||
#include "tools.h"
|
||||
|
||||
namespace xmreg
|
||||
{
|
||||
using namespace cryptonote;
|
||||
using namespace crypto;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* Micro version of cryptonode::core class
|
||||
* Micro version of constructor,
|
||||
* init and destructor are implemted.
|
||||
*
|
||||
* Just enough to read the blockchain
|
||||
* database for use in the example.
|
||||
*/
|
||||
class MicroCore {
|
||||
|
||||
string blockchain_path;
|
||||
|
||||
tx_memory_pool m_mempool;
|
||||
Blockchain core_storage;
|
||||
|
||||
hw::device* m_device;
|
||||
|
||||
network_type nettype;
|
||||
|
||||
bool initialization_succeded {false};
|
||||
|
||||
public:
|
||||
|
||||
// <amoumt,
|
||||
// tuple<total_instances, unlocked_instances, recent_instances>
|
||||
using histogram_map = std::map<uint64_t,
|
||||
std::tuple<uint64_t, uint64_t, uint64_t>>;
|
||||
|
||||
MicroCore();
|
||||
|
||||
/**
|
||||
* Initialized the MicroCore object.
|
||||
*
|
||||
* Create BlockchainLMDB on the heap.
|
||||
* Open database files located in blockchain_path.
|
||||
* Initialize m_blockchain_storage with the BlockchainLMDB object.
|
||||
*/
|
||||
virtual bool
|
||||
init(const string& _blockchain_path, network_type nt);
|
||||
|
||||
virtual Blockchain const&
|
||||
get_core() const;
|
||||
|
||||
virtual tx_memory_pool const&
|
||||
get_mempool() const;
|
||||
|
||||
virtual hw::device* const
|
||||
get_device() const;
|
||||
|
||||
virtual void
|
||||
get_output_key(const uint64_t& amount,
|
||||
const vector<uint64_t>& absolute_offsets,
|
||||
vector<cryptonote::output_data_t>& outputs)
|
||||
{
|
||||
core_storage.get_db()
|
||||
.get_output_key(amount, absolute_offsets, outputs);
|
||||
}
|
||||
|
||||
virtual output_data_t
|
||||
get_output_key(uint64_t amount,
|
||||
uint64_t global_amount_index)
|
||||
{
|
||||
return core_storage.get_db()
|
||||
.get_output_key(amount, global_amount_index);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
get_transactions(
|
||||
const std::vector<crypto::hash>& txs_ids,
|
||||
std::vector<transaction>& txs,
|
||||
std::vector<crypto::hash>& missed_txs) const
|
||||
{
|
||||
return core_storage.get_transactions(txs_ids, txs, missed_txs);
|
||||
}
|
||||
|
||||
virtual std::vector<block>
|
||||
get_blocks_range(const uint64_t& h1, const uint64_t& h2) const
|
||||
{
|
||||
return core_storage.get_db().get_blocks_range(h1, h2);
|
||||
}
|
||||
|
||||
virtual uint64_t
|
||||
get_tx_unlock_time(crypto::hash const& tx_hash) const
|
||||
{
|
||||
return core_storage.get_db().get_tx_unlock_time(tx_hash);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
have_tx(crypto::hash const& tx_hash) const
|
||||
{
|
||||
return core_storage.have_tx(tx_hash);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
tx_exists(crypto::hash const& tx_hash, uint64_t& tx_id) const
|
||||
{
|
||||
return core_storage.get_db().tx_exists(tx_hash, tx_id);
|
||||
}
|
||||
|
||||
virtual tx_out_index
|
||||
get_output_tx_and_index(uint64_t const& amount, uint64_t const& index) const
|
||||
{
|
||||
return core_storage.get_db().get_output_tx_and_index(amount, index);
|
||||
}
|
||||
|
||||
virtual uint64_t
|
||||
get_tx_block_height(crypto::hash const& tx_hash) const
|
||||
{
|
||||
return core_storage.get_db().get_tx_block_height(tx_hash);
|
||||
}
|
||||
|
||||
virtual std::vector<uint64_t>
|
||||
get_tx_amount_output_indices(uint64_t const& tx_id) const
|
||||
{
|
||||
return core_storage.get_db().get_tx_amount_output_indices(tx_id);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
get_mempool_txs(
|
||||
std::vector<tx_info>& tx_infos,
|
||||
std::vector<spent_key_image_info>& key_image_infos) const
|
||||
{
|
||||
return m_mempool.get_transactions_and_spent_keys_info(
|
||||
tx_infos, key_image_infos);
|
||||
}
|
||||
|
||||
virtual uint64_t
|
||||
get_current_blockchain_height() const
|
||||
{
|
||||
return core_storage.get_current_blockchain_height();
|
||||
}
|
||||
|
||||
|
||||
virtual bool
|
||||
get_output_histogram(
|
||||
vector<uint64_t> const& amounts,
|
||||
uint64_t min_count,
|
||||
histogram_map& histogram,
|
||||
bool unlocked = true,
|
||||
uint64_t recent_cutoff = 0) const;
|
||||
|
||||
|
||||
// mimicks core_rpc_server::on_get_output_histogram(..)
|
||||
virtual bool
|
||||
get_output_histogram(
|
||||
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request const& req,
|
||||
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res) const;
|
||||
|
||||
|
||||
virtual bool
|
||||
get_outs(COMMAND_RPC_GET_OUTPUTS_BIN::request const& req,
|
||||
COMMAND_RPC_GET_OUTPUTS_BIN::response& res) const
|
||||
{
|
||||
return core_storage.get_outs(req, res);
|
||||
}
|
||||
|
||||
virtual uint64_t
|
||||
get_dynamic_base_fee_estimate(uint64_t const& grace_blocks) const
|
||||
{
|
||||
return core_storage.get_dynamic_base_fee_estimate(grace_blocks);
|
||||
}
|
||||
|
||||
bool
|
||||
get_block_complete_entry(block const& b, block_complete_entry& bce);
|
||||
|
||||
virtual bool
|
||||
get_block_from_height(uint64_t height, block& blk) const;
|
||||
|
||||
virtual bool
|
||||
get_tx(crypto::hash const& tx_hash, transaction& tx) const;
|
||||
|
||||
virtual bool
|
||||
decrypt_payment_id(crypto::hash8 &payment_id,
|
||||
public_key const& public_key,
|
||||
secret_key const& secret_key)
|
||||
{
|
||||
return m_device->decrypt_payment_id(payment_id,
|
||||
public_key,
|
||||
secret_key);
|
||||
}
|
||||
|
||||
|
||||
virtual bool
|
||||
init_success() const;
|
||||
|
||||
virtual ~MicroCore();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //XMREG01_MICROCORE_H
|
@ -1,49 +0,0 @@
|
||||
//
|
||||
// Created by mwo on 12/07/18.
|
||||
//
|
||||
|
||||
#include "easylogging++.h"
|
||||
#include "om_log.h"
|
||||
|
||||
#include "MysqlPing.h"
|
||||
|
||||
|
||||
namespace xmreg
|
||||
{
|
||||
|
||||
MysqlPing::MysqlPing(
|
||||
std::shared_ptr<MySqlConnector> _conn,
|
||||
uint64_t _ping_time)
|
||||
: conn {_conn}, ping_time {_ping_time}
|
||||
{}
|
||||
|
||||
void
|
||||
MysqlPing::operator()()
|
||||
{
|
||||
while (keep_looping)
|
||||
{
|
||||
std::this_thread::sleep_for(chrono::seconds(ping_time));
|
||||
|
||||
if (auto c = conn.lock())
|
||||
{
|
||||
if (!c->ping())
|
||||
{
|
||||
OMERROR << "Pinging mysql failed. Stoping mysql pinging thread.";
|
||||
why_stoped = StopReason::PingFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
OMINFO << "Mysql ping successful." ;
|
||||
}
|
||||
else
|
||||
{
|
||||
OMERROR << "std::weak_ptr<MySqlConnector> conn expired!";
|
||||
why_stoped = StopReason::PointerExpired;
|
||||
break;
|
||||
}
|
||||
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,280 +0,0 @@
|
||||
//
|
||||
// Created by mwo on 13/02/17.
|
||||
//
|
||||
|
||||
#include "OutputInputIdentification.h"
|
||||
|
||||
|
||||
namespace xmreg
|
||||
{
|
||||
|
||||
OutputInputIdentification::OutputInputIdentification(
|
||||
const address_parse_info* _a,
|
||||
const secret_key* _v,
|
||||
const transaction* _tx,
|
||||
crypto::hash const& _tx_hash,
|
||||
bool is_coinbase,
|
||||
std::shared_ptr<CurrentBlockchainStatus> _current_bc_status)
|
||||
: current_bc_status {_current_bc_status}
|
||||
{
|
||||
address_info = _a;
|
||||
viewkey = _v;
|
||||
tx = _tx;
|
||||
|
||||
tx_pub_key = xmreg::get_tx_pub_key_from_received_outs(*tx);
|
||||
|
||||
tx_is_coinbase = is_coinbase;
|
||||
tx_hash = _tx_hash;
|
||||
|
||||
is_rct = (tx->version == 2);
|
||||
|
||||
if (is_rct)
|
||||
{
|
||||
rct_type = tx->rct_signatures.type;
|
||||
}
|
||||
|
||||
|
||||
if (!generate_key_derivation(tx_pub_key, *viewkey, derivation))
|
||||
{
|
||||
OMERROR << "Cant get derived key for: " << "\n"
|
||||
<< "pub_tx_key: " << get_tx_pub_key_str() << " and "
|
||||
<< "prv_view_key" << viewkey;;
|
||||
|
||||
//throw OutputInputIdentificationException(
|
||||
// "Cant get derived key for a tx");
|
||||
|
||||
status = INTERNAL_STATUS::CANT_DERIVE_KEY;
|
||||
return;
|
||||
}
|
||||
|
||||
status = INTERNAL_STATUS::OK;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
OutputInputIdentification::get_mixin_no()
|
||||
{
|
||||
if (mixin_no == 0 && !tx_is_coinbase)
|
||||
mixin_no = xmreg::get_mixin_no(*tx);
|
||||
|
||||
return mixin_no;
|
||||
}
|
||||
|
||||
void
|
||||
OutputInputIdentification::identify_outputs()
|
||||
{
|
||||
// <public_key , amount , out idx>
|
||||
vector<tuple<txout_to_key, uint64_t, uint64_t>> outputs
|
||||
= get_ouputs_tuple(*tx);
|
||||
|
||||
for (auto& out: outputs)
|
||||
{
|
||||
txout_to_key const& txout_k = std::get<0>(out);
|
||||
uint64_t amount = std::get<1>(out);
|
||||
uint64_t output_idx_in_tx = std::get<2>(out);
|
||||
|
||||
// get the tx output public key
|
||||
// that normally would be generated for us,
|
||||
// if someone had sent us some xmr.
|
||||
public_key generated_tx_pubkey;
|
||||
|
||||
derive_public_key(derivation,
|
||||
output_idx_in_tx,
|
||||
address_info->address.m_spend_public_key,
|
||||
generated_tx_pubkey);
|
||||
|
||||
// check if generated public key matches the current output's key
|
||||
bool mine_output = (txout_k.key == generated_tx_pubkey);
|
||||
|
||||
// placeholder variable for ringct outputs info
|
||||
// that we need to save in database
|
||||
string rtc_outpk;
|
||||
string rtc_mask;
|
||||
string rtc_amount;
|
||||
|
||||
// if mine output has RingCT, i.e., tx version is 2
|
||||
// need to decode its amount. otherwise its zero.
|
||||
if (mine_output && tx->version == 2)
|
||||
{
|
||||
// initialize with regular amount value
|
||||
// for ringct, except coinbase, it will be 0
|
||||
uint64_t rct_amount_val = amount;
|
||||
|
||||
// cointbase txs have amounts in plain sight.
|
||||
// so use amount from ringct, only for non-coinbase txs
|
||||
if (!tx_is_coinbase)
|
||||
{
|
||||
bool r;
|
||||
|
||||
// for ringct non-coinbase txs, these values are given
|
||||
// with txs.
|
||||
// coinbase ringctx dont have this information. we will provide
|
||||
// them only when needed, in get_unspent_outputs. So go there
|
||||
// to see how we deal with ringct coinbase txs when we spent
|
||||
// them
|
||||
// go to CurrentBlockchainStatus::construct_output_rct_field
|
||||
// to see how we deal with coinbase ringct that are used
|
||||
// as mixins
|
||||
rtc_outpk = pod_to_hex(tx->rct_signatures
|
||||
.outPk[output_idx_in_tx].mask);
|
||||
rtc_mask = pod_to_hex(tx->rct_signatures
|
||||
.ecdhInfo[output_idx_in_tx].mask);
|
||||
rtc_amount = pod_to_hex(tx->rct_signatures
|
||||
.ecdhInfo[output_idx_in_tx].amount);
|
||||
|
||||
rct::key mask = tx->rct_signatures
|
||||
.ecdhInfo[output_idx_in_tx].mask;
|
||||
|
||||
r = decode_ringct(tx->rct_signatures,
|
||||
tx_pub_key,
|
||||
*viewkey,
|
||||
output_idx_in_tx,
|
||||
mask,
|
||||
rct_amount_val);
|
||||
|
||||
if (!r)
|
||||
{
|
||||
OMERROR << "Cant decode ringCT!";
|
||||
throw OutputInputIdentificationException(
|
||||
"Cant decode ringCT!");
|
||||
}
|
||||
|
||||
amount = rct_amount_val;
|
||||
|
||||
} // if (!tx_is_coinbase)
|
||||
|
||||
} // if (mine_output && tx.version == 2)
|
||||
|
||||
if (mine_output)
|
||||
{
|
||||
total_received += amount;
|
||||
|
||||
identified_outputs.emplace_back(
|
||||
output_info{
|
||||
txout_k.key, amount, output_idx_in_tx,
|
||||
rtc_outpk, rtc_mask, rtc_amount
|
||||
});
|
||||
|
||||
} // if (mine_output)
|
||||
|
||||
} // for (const auto& out: outputs)
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OutputInputIdentification::identify_inputs(
|
||||
unordered_map<public_key, uint64_t> const& known_outputs_keys)
|
||||
{
|
||||
vector<txin_to_key> input_key_imgs = xmreg::get_key_images(*tx);
|
||||
|
||||
size_t search_misses {0};
|
||||
|
||||
// make timescale maps for mixins in input
|
||||
for (txin_to_key const& in_key: input_key_imgs)
|
||||
{
|
||||
// get absolute offsets of mixins
|
||||
std::vector<uint64_t> absolute_offsets
|
||||
= cryptonote::relative_output_offsets_to_absolute(
|
||||
in_key.key_offsets);
|
||||
|
||||
// get public keys of outputs used in the mixins that
|
||||
// match to the offests
|
||||
std::vector<cryptonote::output_data_t> mixin_outputs;
|
||||
|
||||
if (!current_bc_status->get_output_keys(in_key.amount,
|
||||
absolute_offsets,
|
||||
mixin_outputs))
|
||||
{
|
||||
OMERROR << "Mixins key images not found";
|
||||
continue;
|
||||
}
|
||||
|
||||
// indicates whether we found any matching mixin in the current input
|
||||
bool found_a_match {false};
|
||||
|
||||
// for each found output public key check if its ours or not
|
||||
for (size_t count = 0; count < absolute_offsets.size(); ++count)
|
||||
{
|
||||
// get basic information about mixn's output
|
||||
cryptonote::output_data_t const& output_data
|
||||
= mixin_outputs[count];
|
||||
|
||||
//cout << " - output_public_key_str: "
|
||||
// << output_public_key_str;
|
||||
|
||||
// before going to the mysql, check our known outputs cash
|
||||
// if the key exists. Its much faster than going to mysql
|
||||
// for this.
|
||||
|
||||
auto it = known_outputs_keys.find(output_data.pubkey);
|
||||
|
||||
if (it != known_outputs_keys.end())
|
||||
{
|
||||
// this seems to be our mixin.
|
||||
// save it into identified_inputs vector
|
||||
|
||||
identified_inputs.push_back(input_info {
|
||||
pod_to_hex(in_key.k_image),
|
||||
it->second, // amount
|
||||
output_data.pubkey});
|
||||
|
||||
//cout << "\n\n" << it->second << endl;
|
||||
|
||||
found_a_match = true;
|
||||
}
|
||||
|
||||
} // for (const cryptonote::output_data_t& output_data: outputs)
|
||||
|
||||
if (found_a_match == false)
|
||||
{
|
||||
// if we didnt find any match, break of the look.
|
||||
// there is no reason to check remaining key images
|
||||
// as when we spent something, our outputs should be
|
||||
// in all inputs in a given txs. Thus, if a single input
|
||||
// is without our output, we can assume this tx does
|
||||
// not contain any of our spendings.
|
||||
|
||||
// just to be sure before we break out of this loop,
|
||||
// do it only after two misses
|
||||
|
||||
if (++search_misses > 2)
|
||||
break;
|
||||
}
|
||||
|
||||
} // for (txin_to_key const& in_key: input_key_imgs)
|
||||
|
||||
}
|
||||
|
||||
|
||||
string const&
|
||||
OutputInputIdentification::get_tx_hash_str()
|
||||
{
|
||||
if (tx_hash_str.empty())
|
||||
tx_hash_str = pod_to_hex(tx_hash);
|
||||
|
||||
return tx_hash_str;
|
||||
}
|
||||
|
||||
|
||||
string const&
|
||||
OutputInputIdentification::get_tx_prefix_hash_str()
|
||||
{
|
||||
if (tx_prefix_hash_str.empty())
|
||||
{
|
||||
tx_prefix_hash = get_transaction_prefix_hash(*tx);
|
||||
tx_prefix_hash_str = pod_to_hex(tx_prefix_hash);
|
||||
}
|
||||
|
||||
return tx_prefix_hash_str;
|
||||
}
|
||||
|
||||
string const&
|
||||
OutputInputIdentification::get_tx_pub_key_str()
|
||||
{
|
||||
if (tx_pub_key_str.empty())
|
||||
tx_pub_key_str = pod_to_hex(tx_pub_key);
|
||||
|
||||
return tx_pub_key_str;
|
||||
}
|
||||
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
//
|
||||
// Created by mwo on 13/02/17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CurrentBlockchainStatus.h"
|
||||
#include "tools.h"
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace xmreg
|
||||
{
|
||||
|
||||
|
||||
class OutputInputIdentificationException: public std::runtime_error
|
||||
{
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This class takes user address, viewkey
|
||||
* and searches for outputs in a given tx
|
||||
* and possible spendings/inputs.
|
||||
*
|
||||
* It is the key class for identification of incoming monero
|
||||
* and candidate outcoming xmr for a user in a blockchain and in
|
||||
* mempool.
|
||||
*
|
||||
* searching for our incoming and outgoing xmr has two components.
|
||||
*
|
||||
* FIRST. to search for the incoming xmr, we use address, viewkey and
|
||||
* outputs public key. Its straight forward, as this is what viewkey was
|
||||
* designed to do.
|
||||
*
|
||||
* SECOND. Searching for spendings (i.e., key images) is more difficult,
|
||||
* because we dont have spendkey. But what we can do is, we can look for
|
||||
* candidate key images. And this can be achieved by checking if any mixin
|
||||
* in associated with the given key image, is our output. If it is our output,
|
||||
* then we assume its our key image (i.e. we spend this output). Off course
|
||||
* this is only
|
||||
* assumption as our outputs can be used in key images of others for their
|
||||
* mixin purposes. Thus, we sent to the frontend the list of key images
|
||||
* that we think are yours, and the frontend, because it has spendkey,
|
||||
* can filter out false positives.
|
||||
*/
|
||||
class OutputInputIdentification
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// quick workaround to issue: 128
|
||||
// so that search threads dont terminate
|
||||
// when an error of creating derived key occurs
|
||||
enum class INTERNAL_STATUS {FAIL, OK, CANT_DERIVE_KEY};
|
||||
|
||||
// define a structure to keep information about found
|
||||
// outputs that we can need in later parts.
|
||||
struct output_info
|
||||
{
|
||||
public_key pub_key;
|
||||
uint64_t amount;
|
||||
uint64_t idx_in_tx;
|
||||
string rtc_outpk;
|
||||
string rtc_mask;
|
||||
string rtc_amount;
|
||||
};
|
||||
|
||||
// define a structure to keep information about found
|
||||
// inputs that we can need in later parts.
|
||||
struct input_info
|
||||
{
|
||||
string key_img;
|
||||
uint64_t amount;
|
||||
public_key out_pub_key;
|
||||
};
|
||||
|
||||
crypto::hash tx_hash;
|
||||
crypto::hash tx_prefix_hash;
|
||||
public_key tx_pub_key;
|
||||
|
||||
string tx_hash_str;
|
||||
string tx_prefix_hash_str;
|
||||
string tx_pub_key_str;
|
||||
|
||||
bool tx_is_coinbase;
|
||||
|
||||
bool is_rct;
|
||||
uint8_t rct_type;
|
||||
|
||||
uint64_t total_received {0};
|
||||
|
||||
uint64_t mixin_no {0};
|
||||
|
||||
// for each output, in a tx, check if it belongs
|
||||
// to the given account of specific address and viewkey
|
||||
|
||||
// public transaction key is combined with our viewkey
|
||||
// to create, so called, derived key.
|
||||
key_derivation derivation;
|
||||
|
||||
|
||||
vector<output_info> identified_outputs;
|
||||
vector<input_info> identified_inputs;
|
||||
|
||||
std::shared_ptr<CurrentBlockchainStatus> current_bc_status;
|
||||
|
||||
INTERNAL_STATUS status = INTERNAL_STATUS::FAIL;
|
||||
|
||||
// default constructor. Useful for unit tests
|
||||
OutputInputIdentification() = default;
|
||||
|
||||
OutputInputIdentification(const address_parse_info* _a,
|
||||
const secret_key* _v,
|
||||
const transaction* _tx,
|
||||
crypto::hash const& _tx_hash,
|
||||
bool is_coinbase,
|
||||
std::shared_ptr<CurrentBlockchainStatus>
|
||||
_current_bc_status);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* FIRST step. search for the incoming xmr using address, viewkey and
|
||||
* outputs public keys.
|
||||
*/
|
||||
virtual void
|
||||
identify_outputs();
|
||||
|
||||
|
||||
/**
|
||||
* SECOND step. search for possible our inputs.
|
||||
* We do this by comparing mixin public keys with
|
||||
* our known output keys. If a metch is found, we assume
|
||||
* that associated input is ours
|
||||
*
|
||||
* The known_outputs_keys parameter is optional. But when we have
|
||||
* it, the identification is faster as we just check mixins public keys
|
||||
* if they are in known_outputs_keys.
|
||||
*
|
||||
* searching without known_outputs_keys is not implemented yet here
|
||||
* but it was done for the onion explorer. so later basically just
|
||||
* copy and past here.
|
||||
*
|
||||
* known_outputs_keys is pair of <output public key, output amount>
|
||||
*
|
||||
*/
|
||||
virtual void
|
||||
identify_inputs(unordered_map<public_key, uint64_t> const&
|
||||
known_outputs_keys);
|
||||
|
||||
virtual string const&
|
||||
get_tx_hash_str();
|
||||
|
||||
virtual string const&
|
||||
get_tx_prefix_hash_str();
|
||||
|
||||
virtual string const&
|
||||
get_tx_pub_key_str();
|
||||
|
||||
virtual uint64_t
|
||||
get_mixin_no();
|
||||
|
||||
virtual ~OutputInputIdentification() = default;
|
||||
|
||||
private:
|
||||
|
||||
// address and viewkey for this search thread.
|
||||
const address_parse_info* address_info;
|
||||
const secret_key* viewkey;
|
||||
|
||||
// transaction that is beeing search
|
||||
const transaction* tx;
|
||||
};
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,80 @@
|
||||
//
|
||||
// Created by mwo on 12/07/18.
|
||||
//
|
||||
|
||||
#include "easylogging++.h"
|
||||
#include "../om_log.h"
|
||||
|
||||
#include "MysqlPing.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace xmreg
|
||||
{
|
||||
|
||||
MysqlPing::MysqlPing(
|
||||
std::shared_ptr<MySqlConnector> _conn,
|
||||
seconds _ping_time, seconds _sleep_time)
|
||||
: conn {_conn}, ping_time {_ping_time},
|
||||
thread_sleep_time {_sleep_time}
|
||||
{}
|
||||
|
||||
void
|
||||
MysqlPing::operator()()
|
||||
{
|
||||
|
||||
// the while loop below is going to execute
|
||||
// faster than ping_time specified. The reason
|
||||
// is so that we can exit it in a timely manner
|
||||
// when keep_looping becomes false
|
||||
uint64_t between_ping_counter {0};
|
||||
|
||||
// if ping_time lower than thread_sleep_time,
|
||||
// use ping_time for thread_sleep_time
|
||||
thread_sleep_time = std::min(thread_sleep_time, ping_time);
|
||||
|
||||
// we are going to ping mysql every
|
||||
// no_of_loops_between_pings iterations
|
||||
// of the while loop
|
||||
uint64_t no_of_loops_between_pings
|
||||
= std::max<uint64_t>(1,
|
||||
ping_time.count()/thread_sleep_time.count()) - 1;
|
||||
|
||||
|
||||
while (keep_looping)
|
||||
{
|
||||
std::this_thread::sleep_for(thread_sleep_time);
|
||||
|
||||
if (++between_ping_counter <= no_of_loops_between_pings)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
between_ping_counter = 0;
|
||||
|
||||
if (auto c = conn.lock())
|
||||
{
|
||||
if (!c->ping())
|
||||
{
|
||||
OMERROR << "Pinging mysql failed. Stoping mysql pinging thread.";
|
||||
why_stoped = StopReason::PingFailed;
|
||||
break;
|
||||
}
|
||||
|
||||
OMINFO << "Mysql ping successful." ;
|
||||
}
|
||||
else
|
||||
{
|
||||
OMERROR << "std::weak_ptr<MySqlConnector> conn expired!";
|
||||
why_stoped = StopReason::PointerExpired;
|
||||
break;
|
||||
}
|
||||
|
||||
++counter;
|
||||
}
|
||||
|
||||
OMINFO << "Exiting Mysql ping thread loop.";
|
||||
}
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
//
|
||||
// Created by mwo on 5/11/15.
|
||||
//
|
||||
|
||||
#ifndef XMREG01_MONERO_HEADERS_H_H
|
||||
#define XMREG01_MONERO_HEADERS_H_H
|
||||
|
||||
#define DB_LMDB 2
|
||||
#define BLOCKCHAIN_DB DB_LMDB
|
||||
|
||||
|
||||
#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003"
|
||||
#define SIGNED_TX_PREFIX "Monero signed tx set\003"
|
||||
#define KEY_IMAGE_EXPORT_FILE_MAGIC "Monero key image export\002"
|
||||
#define OUTPUT_EXPORT_FILE_MAGIC "Monero output export\003"
|
||||
|
||||
#define FEE_ESTIMATE_GRACE_BLOCKS 10
|
||||
#define RECENT_OUTPUT_ZONE ((time_t)(RECENT_OUTPUT_DAYS * 86400))
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#include "net/http_client.h"
|
||||
#include "storages/http_abstract_invoke.h"
|
||||
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/blockchain.h"
|
||||
#include "blockchain_db/lmdb/db_lmdb.h"
|
||||
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
#include "serialization/binary_utils.h"
|
||||
|
||||
#include "ringct/rctTypes.h"
|
||||
#include "ringct/rctOps.h"
|
||||
#include "ringct/rctSigs.h"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
#include "common/base58.h"
|
||||
|
||||
#include "string_coding.h"
|
||||
|
||||
|
||||
#endif //XMREG01_MONERO_HEADERS_H_H
|
||||
|
@ -0,0 +1 @@
|
||||
Subproject commit 9562666a598b52b8f3c12cbedc73e79398f1599b
|
@ -0,0 +1,190 @@
|
||||
#include "JsonTx.h"
|
||||
|
||||
namespace xmreg
|
||||
{
|
||||
|
||||
JsonTx::JsonTx(json _jtx): jtx {std::move(_jtx)}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
JsonTx::JsonTx(string _path): jpath {std::move(_path)}
|
||||
{
|
||||
if (!read_config())
|
||||
{
|
||||
throw std::runtime_error("Cant read " + jpath);
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonTx::get_output_tx_and_index(
|
||||
uint64_t const& amount,
|
||||
vector<uint64_t> const& offsets,
|
||||
vector<tx_out_index>& indices) const
|
||||
{
|
||||
for (auto const& jinput: jtx["inputs"])
|
||||
{
|
||||
if (jinput["amount"] != amount
|
||||
&& jinput["absolute_offsets"] != offsets)
|
||||
continue;
|
||||
|
||||
for (auto const& jring_member: jinput["ring_members"])
|
||||
{
|
||||
crypto::hash tx_hash;
|
||||
|
||||
if (!hex_to_pod(jring_member["tx_hash"], tx_hash))
|
||||
throw std::runtime_error(
|
||||
"hex_to_pod(jring_member[\"tx_hash\"], tx_hash)");
|
||||
|
||||
indices.emplace_back(tx_hash, jring_member["output_index_in_tx"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JsonTx::get_tx(crypto::hash const& tx_hash,
|
||||
transaction& tx) const
|
||||
{
|
||||
for (auto const& jinput: jtx["inputs"])
|
||||
{
|
||||
for (auto const& jring_member: jinput["ring_members"])
|
||||
{
|
||||
if (jring_member["tx_hash"] != pod_to_hex(tx_hash))
|
||||
continue;
|
||||
|
||||
crypto::hash tx_hash_tmp; \
|
||||
crypto::hash tx_prefix_hash_tmp; \
|
||||
|
||||
if (!xmreg::hex_to_tx(jring_member["tx_hex"],
|
||||
tx, tx_hash_tmp, tx_prefix_hash_tmp))
|
||||
throw std::runtime_error(
|
||||
"xmreg::hex_to_tx(jring_member[\"tx_hash\"]");
|
||||
|
||||
(void) tx_hash_tmp;
|
||||
(void) tx_prefix_hash_tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
JsonTx::init()
|
||||
{
|
||||
ntype = cryptonote::network_type {jtx["nettype"]};
|
||||
|
||||
hex_to_pod(jtx["payment_id"], payment_id);
|
||||
hex_to_pod(jtx["payment_id8"], payment_id8);
|
||||
hex_to_pod(jtx["payment_id8e"], payment_id8e);
|
||||
|
||||
addr_and_viewkey_from_string(
|
||||
jtx["sender"]["address"], jtx["sender"]["viewkey"], \
|
||||
ntype, sender.address, sender.viewkey);
|
||||
|
||||
parse_str_secret_key(jtx["sender"]["spendkey"], sender.spendkey);
|
||||
|
||||
sender.amount = jtx["sender"]["amount"];
|
||||
sender.change = jtx["sender"]["change"];
|
||||
sender.ntype = ntype;
|
||||
|
||||
populate_outputs(jtx["sender"]["outputs"], sender.outputs);
|
||||
|
||||
for (auto const& jrecpient: jtx["recipient"])
|
||||
{
|
||||
recipients.push_back(account{});
|
||||
|
||||
addr_and_viewkey_from_string(
|
||||
jrecpient["address"], jrecpient["viewkey"], \
|
||||
ntype, recipients.back().address,
|
||||
recipients.back().viewkey);
|
||||
|
||||
parse_str_secret_key(jrecpient["spendkey"],
|
||||
recipients.back().spendkey);
|
||||
|
||||
recipients.back().amount = jrecpient["amount"];
|
||||
|
||||
recipients.back().is_subaddress = jrecpient["is_subaddress"];
|
||||
recipients.back().ntype = ntype;
|
||||
|
||||
populate_outputs(jrecpient["outputs"], recipients.back().outputs);
|
||||
}
|
||||
|
||||
if (!hex_to_tx(jtx["hex"], tx, tx_hash, tx_prefix_hash))
|
||||
{
|
||||
throw std::runtime_error("hex_to_tx(jtx[\"hex\"], tx, tx_hash, tx_prefix_hash)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
JsonTx::read_config()
|
||||
{
|
||||
if (!boost::filesystem::exists(jpath))
|
||||
{
|
||||
cerr << "Config file " << jpath << " does not exist\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// try reading and parsing json config file provided
|
||||
std::ifstream i(jpath);
|
||||
i >> jtx;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
cerr << "Cant parse json string as json: " << e.what() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
check_and_adjust_path(string& in_path)
|
||||
{
|
||||
if (!boost::filesystem::exists(in_path))
|
||||
in_path = "./tests/" + in_path;
|
||||
|
||||
return boost::filesystem::exists(in_path);
|
||||
}
|
||||
|
||||
boost::optional<JsonTx>
|
||||
construct_jsontx(string tx_hash)
|
||||
{
|
||||
string tx_path = "./tx/" + tx_hash + ".json";
|
||||
|
||||
if (!check_and_adjust_path(tx_path))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return JsonTx {tx_path};
|
||||
}
|
||||
|
||||
void
|
||||
JsonTx::populate_outputs(json const& joutputs, vector<output>& outs)
|
||||
{
|
||||
for (auto const& jout: joutputs)
|
||||
{
|
||||
public_key out_pk;
|
||||
|
||||
if (!hex_to_pod(jout[1], out_pk))
|
||||
{
|
||||
throw std::runtime_error("hex_to_pod(jout[1], out_pk)");
|
||||
}
|
||||
|
||||
output out {jout[0], out_pk, jout[2]};
|
||||
|
||||
outs.push_back(out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
#ifndef JSONTX_H
|
||||
#define JSONTX_H
|
||||
|
||||
#include "../src/utils.h"
|
||||
|
||||
namespace xmreg
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief reprsents txs found in tests/res/tx folder
|
||||
*
|
||||
* Usef for unit testing and mocking tx data, which
|
||||
* otherwise would need to be fetched from blockchain
|
||||
*
|
||||
*/
|
||||
class JsonTx
|
||||
{
|
||||
public:
|
||||
|
||||
struct output
|
||||
{
|
||||
uint64_t index {0};
|
||||
public_key pub_key;
|
||||
uint64_t amount {0};
|
||||
};
|
||||
|
||||
struct account
|
||||
{
|
||||
address_parse_info address {};
|
||||
secret_key viewkey {};
|
||||
secret_key spendkey {};
|
||||
bool is_subaddress {false};
|
||||
network_type ntype;
|
||||
uint64_t amount {0};
|
||||
uint64_t change {0};
|
||||
vector<output> outputs;
|
||||
|
||||
inline string
|
||||
address_str() const
|
||||
{
|
||||
return get_account_address_as_str(ntype,
|
||||
is_subaddress,
|
||||
address.address);
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, account const& _account);
|
||||
};
|
||||
|
||||
json jtx;
|
||||
|
||||
transaction tx;
|
||||
crypto::hash tx_hash {0}; \
|
||||
crypto::hash tx_prefix_hash {0};
|
||||
crypto::public_key tx_pub_key;
|
||||
crypto::hash payment_id {0};
|
||||
crypto::hash8 payment_id8 {0};
|
||||
crypto::hash8 payment_id8e {0};
|
||||
|
||||
string jpath;
|
||||
network_type ntype;
|
||||
|
||||
account sender;
|
||||
vector<account> recipients;
|
||||
|
||||
explicit JsonTx(json _jtx);
|
||||
explicit JsonTx(string _path);
|
||||
|
||||
// generate output which normaly is produced by
|
||||
// monero's get_output_tx_and_index and blockchain,
|
||||
// but here we use data from the tx json data file
|
||||
// need this for mocking blockchain calls in unit tests
|
||||
void
|
||||
get_output_tx_and_index(
|
||||
uint64_t const& amount,
|
||||
vector<uint64_t> const& offsets,
|
||||
vector<tx_out_index>& indices) const;
|
||||
|
||||
// will use data from the json file
|
||||
// to set tx. Used for mocking this operation
|
||||
// that is normaly done using blockchain
|
||||
bool
|
||||
get_tx(crypto::hash const& tx_hash,
|
||||
transaction& tx) const;
|
||||
|
||||
private:
|
||||
void init();
|
||||
bool read_config();
|
||||
void populate_outputs(json const& joutputs, vector<output>& outs);
|
||||
|
||||
};
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, JsonTx::account const& _account)
|
||||
{
|
||||
return os << _account.address_str();
|
||||
}
|
||||
|
||||
bool
|
||||
check_and_adjust_path(string& in_path);
|
||||
|
||||
|
||||
boost::optional<JsonTx>
|
||||
construct_jsontx(string tx_hash);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // JSONTX_H
|
@ -0,0 +1,7 @@
|
||||
# Test transaction data
|
||||
|
||||
Json files containing testing transactions data for unit tests.
|
||||
The were obtained using `Full ring member txs as hex` option in the onion explorer
|
||||
running wiht `--enable-as-hex` flag.
|
||||
|
||||
The wallet information were manual entered.
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,33 @@
|
||||
{
|
||||
"_comment": "Just a placeholder for some comment if needed later",
|
||||
"block": "0111010101010201010405626c6f636b0a050209098aab83e005e094b83d50e762b943df3158e9a87bc49f75ab9f2e800be380bd92bbaae477e84ac9844a02d08e0d01ff948e0d01b7de97a0f0bc0502472b5dcf3d976fa1b8e0d250a7c4e9dc52ae9db7b8fb00934f9dac800da9f89f2101b9e281d63f319b30ea87d789d324cbce8b5edfa6a8e00f001f8449d8ba2b71fe0000",
|
||||
"block_version": [9, 9],
|
||||
"hash": "f3c84fe925292ec5b4dc383d306d934214f4819611566051bca904d1cf4efceb",
|
||||
"hex": "02d08e0d01ff948e0d01b7de97a0f0bc0502472b5dcf3d976fa1b8e0d250a7c4e9dc52ae9db7b8fb00934f9dac800da9f89f2101b9e281d63f319b30ea87d789d324cbce8b5edfa6a8e00f001f8449d8ba2b71fe00",
|
||||
"inputs": [],
|
||||
"is_ringct": true,
|
||||
"nettype": 2,
|
||||
"payment_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"payment_id8": "0000000000000000",
|
||||
"payment_id8e": "0000000000000000",
|
||||
"rct_type": 0,
|
||||
"recipient": [{
|
||||
"_comment": "monerowalletstagenet3, coinbase tx",
|
||||
"address": "56heRv2ANffW1Py2kBkJDy8xnWqZsSrgjLygwjua2xc8Wbksead1NK1ehaYpjQhymGK4S8NPL9eLuJ16CuEJDag8Hq3RbPV",
|
||||
"amount": 24081949126455,
|
||||
"is_subaddress": false,
|
||||
"seed": "",
|
||||
"spendkey": "df0f5720ae0b69454ca7db35db677272c7c19513cd0dc4147b0e00792a10f406",
|
||||
"viewkey": "b45e6f38b2cd1c667459527decb438cdeadf9c64d93c8bccf40a9bf98943dc09",
|
||||
"outputs": [[0, "472b5dcf3d976fa1b8e0d250a7c4e9dc52ae9db7b8fb00934f9dac800da9f89f", 24081949126455]]
|
||||
}],
|
||||
"sender": {
|
||||
"_comment": "",
|
||||
"address": "",
|
||||
"amount": 0,
|
||||
"change": 0,
|
||||
"seed": "",
|
||||
"spendkey": "",
|
||||
"viewkey": ""
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue