Merge pull request #131 from moneroexamples/use_xmregcore

xmregcore integarated and the openmonero updated to work with `release-v0.13` akak v0.14.0.0. of monero.
pull/135/head
moneroexamples 5 years ago committed by GitHub
commit e0cbce31ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "src/xmregcore"]
path = src/xmregcore
url = https://github.com/moneroexamples/xmregcore.git

@ -1,4 +1,4 @@
# Generated by YCM Generator at 2019-01-02 17:01:50.568923
# 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.
@ -45,7 +45,7 @@ flags = [
'-I/home/mwo2/monero/external/easylogging++',
'-I/home/mwo2/monero/src',
'-I/home/mwo2/openmonero/ext/restbed/source',
'-I/tmp/tmp9cWyau/gen',
'-I/home/mwo2/openmonero/src/xmregcore',
'-I/usr/include/mysql',
'-I/usr/local/include',
'-I/usr/local/include/mysql',
@ -54,7 +54,7 @@ flags = [
'-Weffc++',
'-Wextra',
'-Wno-unknown-pragmas',
'-std=c++11',
'-std=c++14',
'-std=gnu++14',
'-isystem', '/home/mwo2/openmonero/ext/restbed/dependency/asio/asio/include',
'-isystem', '/home/mwo2/openmonero/ext/restbed/dependency/kashmir',

@ -6,6 +6,7 @@ set(PROJECT_NAME
project(${PROJECT_NAME})
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_BUILD_TYPE Debug)
if(CMAKE_SIZEOF_VOID_P EQUAL "4")
add_definitions(-DMDB_VL32)
@ -15,6 +16,8 @@ if (NOT MONERO_DIR)
set(MONERO_DIR ~/monero)
endif()
set( CMAKE_EXPORT_COMPILE_COMMANDS ON )
option(BUILD_TESTS "Build tests for the project" OFF)
message(STATUS MONERO_DIR ": ${MONERO_DIR}")
@ -31,6 +34,8 @@ set(MY_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake"
list(APPEND CMAKE_MODULE_PATH "${MY_CMAKE_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/src/xmregcore/cmake")
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${MONERO_BUILD_DIR}"
CACHE PATH "Add Monero directory for library searching")
@ -47,15 +52,17 @@ if (${BUILD_TESTS})
'${CMAKE_SOURCE_DIR}/tests/*')
endif()
find_package(Monero)
find_package(MYSQL)
if (NOT MYSQL_INCLUDE_DIR)
message(SEND_ERROR "MySQL libraries not found! Please install mysql++/mysqlpp libraries")
message(SEND_ERROR "MySQL libraries not found!
Please install mysql++/mysqlpp libraries")
return()
endif()
include_directories(${MYSQL_INCLUDE_DIR})
# include boost headers
@ -79,7 +86,8 @@ link_directories(
create_git_version()
configure_files(${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_BINARY_DIR}/config)
configure_files(${CMAKE_CURRENT_SOURCE_DIR}/config
${CMAKE_CURRENT_BINARY_DIR}/config)
# find boost
@ -96,6 +104,11 @@ find_package(Boost COMPONENTS
REQUIRED)
# add XMREGCORE submodule
set(BUILD_XMREGCORE_TESTS OFF CACHE INTERNAL "")
add_subdirectory(src/xmregcore)
# add src/ subfolder
add_subdirectory(src/)
@ -109,36 +122,24 @@ set(SOURCE_FILES
add_executable(${PROJECT_NAME}
${SOURCE_FILES})
target_include_directories(${PROJECT_NAME}
PRIVATE src/xmregcore)
# include monero headers
target_include_monero_directories(${PROJECT_NAME})
set(LIBRARIES
myxrm
myxrmcore
${Monero_LIBRARIES}
restbed
wallet
cryptonote_core
blockchain_db
cryptonote_protocol
cryptonote_basic
daemonizer
cncrypto
blocks
lmdb
ringct
ringct_basic
common
mnemonics
epee
easylogging
mysqlpp
mysqlclient
device
epee
checkpoints
version
sodium
${Boost_LIBRARIES}
sodium
pthread
unbound
curl
cncrypto
ssl
crypto)

@ -106,7 +106,7 @@ sudo apt install libmysql++-dev
# go to home folder if still in ~/monero
cd ~
git clone https://github.com/moneroexamples/openmonero.git
git clone --recursive https://github.com/moneroexamples/openmonero.git
cd openmonero

@ -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,99 +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)
# message("${dirname} ${srcDir}")
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("${dirname}${filename}" ALL DEPENDS ${resource} ${output})
endforeach()
endmacro(resource_dir)

@ -34,7 +34,7 @@
"wallet_import" :
{
"_comment": "if fee is 0, then importing is free. fee is in base 1e12, e.g., 0.1 xmr is 0.1 x 1e12 = 100000000000",
"fee" : 0,
"fee" : 1000000,
"testnet" :
{
"address" : "9tzmPMTViHYM3z6NAgQni1Qm1Emzxy5hQFibPgWD3LVTAz91yok5Eni1pH6zKhBHzpTU15GZooPHSGHXFvFuXEdmEG2sWAZ",
@ -58,7 +58,7 @@
"max_number_of_blocks_to_import" : 132000,
"mysql_ping_every_seconds" : 200,
"_comment": "if the threadpool_size (no of threads) below is 0, its size is automaticly set based on your cpu. If its not 0, the value specified is used instead",
"blockchain_treadpool_size" : 0,
"blockchain_treadpool_size" : 1,
"ssl" :
{
"enable" : false,

File diff suppressed because it is too large Load Diff

@ -442,7 +442,14 @@ var cnUtil = (function(initConfig) {
first = seed; //only input reduced seeds or this will not give you the result you want
}
keys.spend = this.generate_keys(first);
var second = this.cn_fast_hash(first);
var second;
if (seed.length !== 64) {
second = this.cn_fast_hash(first);
} else {
second = this.cn_fast_hash(keys.spend.sec);
}
keys.view = this.generate_keys(second);
keys.public_addr = this.pubkeys_to_string(keys.spend.pub, keys.view.pub);
return keys;

@ -5,8 +5,8 @@
#ifndef OPENMONERO_BLOCKCHAINSETUP_H
#define OPENMONERO_BLOCKCHAINSETUP_H
#include "monero_headers.h"
#include "tools.h"
#include "src/monero_headers.h"
#include "utils.h"
#include <string>

@ -3,8 +3,6 @@ cmake_minimum_required(VERSION 3.2)
project(myxrm)
set(SOURCE_FILES
MicroCore.cpp
tools.cpp
CmdLineOptions.cpp
CurrentBlockchainStatus.cpp
db/MySqlConnector.cpp
@ -12,15 +10,15 @@ set(SOURCE_FILES
db/ssqlses.cpp
OpenMoneroRequests.cpp
TxSearch.cpp
RPCCalls.cpp
OutputInputIdentification.cpp
version.h.in
RPCCalls.cpp
omversion.h.in
BlockchainSetup.cpp
ThreadRAII.cpp
db/MysqlPing.cpp
TxUnlockChecker.cpp
UniversalIdentifier.cpp
RandomOutputs.cpp)
db/MysqlPing.cpp
TxUnlockChecker.cpp
utils.cpp
RandomOutputs.cpp)
# make static library called libmyxrm
# that we are going to link to
@ -28,3 +26,12 @@ set(SOURCE_FILES
add_library(myxrm
STATIC
${SOURCE_FILES})
target_include_monero_directories(myxrm)
target_include_directories(myxrm PRIVATE "xmregcore")
#target_include_directories(myxmr
# PUBLIC
#${MONERO_SOURCE_DIR}/contrib/epee/include)

@ -3,7 +3,7 @@
//
#include "CurrentBlockchainStatus.h"
#include "PaymentSearcher.hpp"
#include "src/UniversalIdentifier.hpp"
#undef MONERO_DEFAULT_LOG_CATEGORY
@ -273,6 +273,25 @@ CurrentBlockchainStatus::get_output_tx_and_index(
return future_result.get();
}
void
CurrentBlockchainStatus::get_output_tx_and_index(
uint64_t amount,
std::vector<uint64_t> const& offsets,
std::vector<tx_out_index>& indices) const
{
auto future_result = thread_pool->submit(
[this](auto amount,
auto const& offsets,
auto& indices)
-> void
{
this->mcore
->get_output_tx_and_index(
amount, offsets, indices);
}, amount, std::cref(offsets),
std::ref(indices));
}
bool
CurrentBlockchainStatus::get_tx_with_output(
uint64_t output_idx, uint64_t amount,
@ -329,7 +348,7 @@ CurrentBlockchainStatus::get_output_keys(
absolute_offsets, outputs);
return true;
}
catch (const OUTPUT_DNE& e)
catch (std::exception const& e)
{
OMERROR << "get_output_keys: " << e.what();
}
@ -669,40 +688,45 @@ CurrentBlockchainStatus::search_if_payment_made(
return false;
}
PaymentSearcher<crypto::hash8> tx_searcher {
bc_setup.import_payment_address,
bc_setup.import_payment_viewkey};
for (auto&& tx: txs_to_check)
{
auto identifier = make_identifier(
tx,
make_unique<Output>(
&bc_setup.import_payment_address,
&bc_setup.import_payment_viewkey),
make_unique<IntegratedPaymentID>(
&bc_setup.import_payment_address,
&bc_setup.import_payment_viewkey));
identifier.identify();
auto payment_id = identifier.get<IntegratedPaymentID>()->get();
if (payment_id == expected_payment_id)
{
auto amount_paid = identifier.get<Output>()->get_total();
auto found_amount_pair = std::make_pair(0ull, std::cend(txs_to_check));
if (amount_paid >= desired_amount)
{
try
{
found_amount_pair
= tx_searcher.search(expected_payment_id, txs_to_check);
}
catch (PaymentSearcherException const& e)
{
OMERROR << e.what();
return false;
}
string tx_hash_str = pod_to_hex(
get_transaction_hash(tx));
if (found_amount_pair.first >= desired_amount)
{
string tx_hash_str = pod_to_hex(
get_transaction_hash(*found_amount_pair.second));
OMINFO << " Payment id check in tx: " << tx_hash_str
<< " found: " << amount_paid;
OMINFO << " Payment id check in tx: "
<< tx_hash_str
<< " found: " << found_amount_pair.first;
// the payment has been made.
tx_hash_with_payment = tx_hash_str;
// the payment has been made.
tx_hash_with_payment = tx_hash_str;
OMINFO << "Import payment done";
OMINFO << "Import payment done";
return true;
return true;
}
}
}
return false;
}
@ -807,7 +831,7 @@ CurrentBlockchainStatus::get_searched_blk_no(const string& address,
if (!search_thread_exist(address))
{
// thread does not exist
OMERROR << "thread for " << address << " does not exist";
OMERROR << "thread for " << address.substr(0,6) << " does not exist";
return false;
}
@ -826,7 +850,7 @@ CurrentBlockchainStatus::get_known_outputs_keys(
if (!search_thread_exist(address))
{
// thread does not exist
OMERROR << "thread for " << address << " does not exist";
OMERROR << "thread for " << address.substr(0,6) << " does not exist";
return false;
}
@ -857,7 +881,8 @@ CurrentBlockchainStatus::get_xmr_address_viewkey(
if (!search_thread_exist(address_str))
{
// thread does not exist
OMERROR << "thread for " << address_str << " does not exist";
OMERROR << "thread for " << address_str.substr(0,6)
<< " does not exist";
return false;
}
@ -879,7 +904,8 @@ CurrentBlockchainStatus::find_txs_in_mempool(
if (searching_threads.count(address_str) == 0)
{
// thread does not exist
OMERROR << "thread for " << address_str << " does not exist";
OMERROR << "thread for "
<< address_str.substr(0,6) << " does not exist";
return false;
}
@ -1212,5 +1238,39 @@ CurrentBlockchainStatus::get_txs_in_blocks(
return true;
}
MicroCoreAdapter::MicroCoreAdapter(CurrentBlockchainStatus* _cbs)
: cbs {_cbs}
{}
void
MicroCoreAdapter::get_output_key(uint64_t amount,
vector<uint64_t> const& absolute_offsets,
vector<cryptonote::output_data_t>& outputs)
/*const */
{
cbs->get_output_keys(amount, absolute_offsets, outputs);
}
void
MicroCoreAdapter::get_output_tx_and_index(
uint64_t amount,
std::vector<uint64_t> const& offsets,
std::vector<tx_out_index>& indices)
const
{
cbs->get_output_tx_and_index(amount, offsets, indices);
}
bool
MicroCoreAdapter::get_tx(crypto::hash const& tx_hash, transaction& tx)
const
{
return cbs->get_tx(tx_hash, tx);
}
}

@ -3,12 +3,12 @@
#define MYSQLPP_SSQLS_NO_STATICS 1
#include "om_log.h"
#include "MicroCore.h"
#include "src/MicroCore.h"
#include "db/ssqlses.h"
#include "TxUnlockChecker.h"
#include "BlockchainSetup.h"
#include "TxSearch.h"
#include "tools.h"
#include "utils.h"
#include "ThreadRAII.h"
#include "RPCCalls.h"
#include "db/MySqlAccounts.h"
@ -120,6 +120,12 @@ public:
get_output_tx_and_index(uint64_t amount,
uint64_t index) const;
virtual void
get_output_tx_and_index(
uint64_t amount,
std::vector<uint64_t> const& offsets,
std::vector<tx_out_index>& indices) const;
virtual bool
get_output_keys(const uint64_t& amount,
const vector<uint64_t>& absolute_offsets,
@ -353,5 +359,38 @@ protected:
};
// small adapter class that will anable using
// BlockchainCurrentStatus inside UniversalAdapter
// for locating inputs. We do this becasuse
// BlockchainCurrentStatus is using a thread pool
// to access MicroCore and blockchain. So we don't want
// to miss on that. Also UnversalAdapter for Inputs
// takes AbstractCore interface
class MicroCoreAdapter : public AbstractCore
{
public:
MicroCoreAdapter(CurrentBlockchainStatus* _cbs);
virtual void
get_output_key(uint64_t amount,
vector<uint64_t> const& absolute_offsets,
vector<cryptonote::output_data_t>& outputs)
/*const*/ override;
virtual void
get_output_tx_and_index(
uint64_t amount,
std::vector<uint64_t> const& offsets,
std::vector<tx_out_index>& indices)
const override;
virtual bool
get_tx(crypto::hash const& tx_hash, transaction& tx)
const override;
private:
CurrentBlockchainStatus* cbs {};
};
}

@ -1,243 +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,245 +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(uint64_t amount,
vector<uint64_t> const& absolute_offsets,
vector<cryptonote::output_data_t>& outputs)
{
core_storage.get_db()
.get_output_key(epee::span<const uint64_t>(&amount, 1),
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 std::vector<block>
//get_blocks_range(const uint64_t& h1, const uint64_t& h2) const
//{
//std::vector<std::pair<cryptonote::blobdata,block>> blobblocks;
//std::vector<blobdata> txs;
//vector<block> blocks;
//{
//std::lock_guard<std::mutex> lock(mtx1);
//cout << "tid: " << std::this_thread::get_id() << endl;;
//core_storage.get_blocks(h1, h2-h1+1, blobblocks, txs);
//}
//blocks.reserve(blobblocks.size());
//for (auto const& bpair: blobblocks)
//blocks.push_back(std::move(bpair.second));
//return blocks;
//}
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).front();
}
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 void
get_output_tx_and_index(
const uint64_t& amount,
const std::vector<uint64_t>& offsets,
std::vector<tx_out_index>& indices) const
{
// tx_hash , index in tx
// tx_out_index is std::pair<crypto::hash, uint64_t>;
core_storage.get_db().get_output_tx_and_index(
amount, offsets, indices);
}
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() = default;
};
}
#endif //XMREG01_MICROCORE_H

@ -6,9 +6,12 @@
#include "OpenMoneroRequests.h"
#include "src/UniversalIdentifier.hpp"
#include "db/ssqlses.h"
#include "OutputInputIdentification.h"
#include "version.h"
#include "../gen/omversion.h"
namespace xmreg
{
@ -67,53 +70,21 @@ OpenMoneroRequests::login(const shared_ptr<Session> session, const Bytes & body)
}
// a placeholder for exciting or new account data
XmrAccount acc;
uint64_t acc_id {0};
// marks if this is new account creation or not
bool new_account_created {false};
auto acc = select_account(xmr_address, view_key, false);
// first check if new account
// select this account if its existing one
if (!xmr_accounts->select(xmr_address, acc))
if (!acc)
{
// account does not exist, so create new one
// for this address
uint64_t current_blockchain_height = get_current_blockchain_height();
// initialize current blockchain timestamp with current time
// in a moment we will try to get last block timestamp
// to replace this value. But if it fails, we just use current
// timestamp
uint64_t current_blockchain_timestamp = std::time(nullptr);
// get last block so we have its timestamp when
// createing the account
block last_blk;
if (current_bc_status->get_block(current_blockchain_height, last_blk))
{
current_blockchain_timestamp = last_blk.timestamp;
}
DateTime blk_timestamp_mysql_format
= XmrTransaction::timestamp_to_DateTime(
current_blockchain_timestamp);
// create new account
XmrAccount new_account(
mysqlpp::null,
xmr_address,
make_hash(view_key),
current_blockchain_height, /* for scanned_block_height */
blk_timestamp_mysql_format,
current_blockchain_height);
// insert the new account into the mysql
if ((acc_id = xmr_accounts->insert(new_account)) == 0)
if (!(acc = create_account(xmr_address, view_key)))
{
// if creating account failed
j_response = json {{"status", "error"},
@ -129,13 +100,13 @@ OpenMoneroRequests::login(const shared_ptr<Session> session, const Bytes & body)
// their first install
new_account_created = true;
} // if (!xmr_accounts->select(xmr_address, acc))
} // if (!acc)
// so by now new account has been created or it already exists
// so we just login into it.
if (login_and_start_search_thread(xmr_address, view_key, acc, j_response))
if (login_and_start_search_thread(xmr_address, view_key, *acc, j_response))
{
// if successfuly logged in and created search thread
j_response["status"] = "success";
@ -207,25 +178,13 @@ OpenMoneroRequests::get_address_txs(
// for this to continue, search thread must have already been
// created and still exisits.
// if (current_bc_status->search_thread_exist(xmr_address))
// {
if (login_and_start_search_thread(xmr_address, view_key, acc, j_response))
{
// populate acc and check view_key
// if (!login_and_start_search_thread(xmr_address, view_key, acc, j_response))
// {
// // some error with loggin in or search thread start
// session_close(session, j_response.dump());
// return;
// }
// before fetching txs, check if provided view key
// is correct. this is simply to ensure that
// we cant fetch an account's txs using only address.
// knowlage of the viewkey is also needed.
uint64_t total_received {0};
uint64_t total_received_unlocked {0};
@ -1008,7 +967,7 @@ OpenMoneroRequests::import_wallet_request(
}
catch (json::exception const& e)
{
OMERROR << "json exception: " << e.what();
OMWARN << "json exception: " << e.what();
session_close(session, j_response, UNPROCESSABLE_ENTITY,
e.what());
return;
@ -1023,20 +982,22 @@ OpenMoneroRequests::import_wallet_request(
j_response["error"] = "Some error occured";
// get account from mysql db if exists
auto xmr_account = select_account(xmr_address);
auto xmr_account = select_account(xmr_address, view_key);
if (!xmr_account)
{
// if creation failed, just close the session
session_close(session, j_response, UNPROCESSABLE_ENTITY,
"The account does not exists!");
"The account login or creation failed!");
return;
}
// if import_fee is zero, we just import the wallet.
auto import_fee = current_bc_status->get_bc_setup().import_fee;
// we dont care about any databases or anything, as importing
// wallet is free.
// just reset the scanned block height in mysql and finish.
if (current_bc_status->get_bc_setup().import_fee == 0)
if (import_fee == 0)
{
// change search blk number in the search thread
if (!current_bc_status->set_new_searched_blk_no(xmr_address, 0))
@ -1134,6 +1095,7 @@ OpenMoneroRequests::import_wallet_request(
// front end should give proper message in this case
j_response["request_fulfilled"] = request_fulfilled;
j_response["import_fee"] = 0;
j_response["status"] = "Wallet already imported or "
"in the progress.";
j_response["new_request"] = false;
@ -1271,7 +1233,8 @@ OpenMoneroRequests::import_recent_wallet_request(
}
catch (json::exception const& e)
{
OMERROR << "json exception: " << e.what();
OMERROR << xmr_address.substr(0,6)
<< ": json exception: " << e.what();
session_close(session, j_response, UNPROCESSABLE_ENTITY,
e.what());
return;
@ -1291,12 +1254,23 @@ OpenMoneroRequests::import_recent_wallet_request(
+ j_request["no_blocks_to_import"].get<string>()
+ " into number";
cerr << msg << '\n';
OMERROR << xmr_address.substr(0,6) + ": " + msg;
j_response["Error"] = msg;
session_close(session, j_response);
return;
}
// get account from mysql db if exists
auto xmr_account = select_account(xmr_address, view_key);
if (!xmr_account)
{
// if creation failed, just close the session
session_close(session, j_response, UNPROCESSABLE_ENTITY,
"The account login or creation failed!");
return;
}
// make sure that we dont import more that the maximum alowed no of blocks
no_blocks_to_import = std::min(no_blocks_to_import,
@ -1307,52 +1281,45 @@ OpenMoneroRequests::import_recent_wallet_request(
= std::min(no_blocks_to_import,
current_bc_status->get_current_blockchain_height());
XmrAccount acc;
XmrAccount& acc = *xmr_account;
if (xmr_accounts->select(xmr_address, acc))
{
XmrAccount updated_acc = acc;
XmrAccount updated_acc = acc;
// make sure scanned_block_height is larger than
// no_blocks_to_import so we dont
// end up with overflowing uint64_t.
// make sure scanned_block_height is larger than
// no_blocks_to_import so we dont
// end up with overflowing uint64_t.
if (updated_acc.scanned_block_height >= no_blocks_to_import)
if (updated_acc.scanned_block_height >= no_blocks_to_import)
{
// repetead calls to import_recent_wallet_request will be
// moving the scanning backward.
// not sure yet if any protection is needed to
// make sure that a user does not
// go back too much back by importing his/hers
// wallet multiple times in a row.
updated_acc.scanned_block_height
= updated_acc.scanned_block_height - no_blocks_to_import;
if (xmr_accounts->update(acc, updated_acc))
{
// repetead calls to import_recent_wallet_request will be
// moving the scanning backward.
// not sure yet if any protection is needed to
// make sure that a user does not
// go back too much back by importing his/hers
// wallet multiple times in a row.
updated_acc.scanned_block_height
= updated_acc.scanned_block_height - no_blocks_to_import;
if (xmr_accounts->update(acc, updated_acc))
// change search blk number in the search thread
if (!current_bc_status
->set_new_searched_blk_no(xmr_address,
updated_acc.scanned_block_height))
{
// change search blk number in the search thread
if (!current_bc_status
->set_new_searched_blk_no(xmr_address,
updated_acc.scanned_block_height))
{
cerr << "Updating searched_blk_no failed!" << endl;
j_response["Error"] = "Updating searched_blk_no failed!";
}
else
{
// if success, makre that request was successful;
request_fulfilled = true;
}
OMERROR << xmr_address.substr(0,6)
<< ": updating searched_blk_no failed!" << endl;
j_response["Error"] = "Updating searched_blk_no failed!";
}
else
{
// if success, makre that request was successful;
request_fulfilled = true;
}
}
} // if (updated_acc.scanned_block_height > no_blocks_to_import)
}
else
{
cerr << "Updating account with new scanned_block_height failed!\n";
j_response["status"]
= "Updating account with new scanned_block_height failed!";
}
} // if (updated_acc.scanned_block_height > no_blocks_to_import)
if (request_fulfilled)
{
@ -1364,7 +1331,8 @@ OpenMoneroRequests::import_recent_wallet_request(
string response_body = j_response.dump();
auto response_headers = make_headers({{ "Content-Length",
std::to_string(response_body.size())}});
std::to_string(
response_body.size())}});
session->close( OK, response_body, response_headers);
}
@ -1398,7 +1366,7 @@ OpenMoneroRequests::get_tx(
}
catch (json::exception const& e)
{
cerr << "json exception: " << e.what() << '\n';
OMWARN << "json exception: " << e.what();
session_close(session, j_response);
return;
}
@ -1454,278 +1422,275 @@ OpenMoneroRequests::get_tx(
tx_found = true;
}
if (tx_found)
if (!tx_found)
{
crypto::hash tx_hash = get_transaction_hash(tx);
// if creation failed, just close the session
session_close(session, j_response, UNPROCESSABLE_ENTITY,
" Cant get tx details for" + tx_hash_str);
return;
}
// return tx hash. can be used to check if we acctually
// delivered the tx that was requested
j_response["tx_hash"] = pod_to_hex(tx_hash);
// return tx hash. can be used to check if we acctually
// delivered the tx that was requested
j_response["tx_hash"] = pod_to_hex(tx_hash);
j_response["pub_key"] = pod_to_hex(
xmreg::get_tx_pub_key_from_received_outs(tx));
j_response["pub_key"] = pod_to_hex(
xmreg::get_tx_pub_key_from_received_outs(tx));
bool coinbase = is_coinbase(tx);
bool coinbase = is_coinbase(tx);
j_response["coinbase"] = coinbase;
j_response["coinbase"] = coinbase;
// key images of inputs
vector<txin_to_key> input_key_imgs;
// key images of inputs
vector<txin_to_key> input_key_imgs;
// public keys and xmr amount of outputs
vector<pair<txout_to_key, uint64_t>> output_pub_keys;
// public keys and xmr amount of outputs
vector<pair<txout_to_key, uint64_t>> output_pub_keys;
uint64_t xmr_inputs;
uint64_t xmr_outputs;
uint64_t num_nonrct_inputs;
uint64_t fee {0};
uint64_t mixin_no;
uint64_t size;
uint64_t xmr_inputs;
uint64_t xmr_outputs;
uint64_t num_nonrct_inputs;
uint64_t fee {0};
uint64_t mixin_no;
uint64_t size;
// sum xmr in inputs and ouputs in the given tx
array<uint64_t, 4> const& sum_data = xmreg::summary_of_in_out_rct(
tx, output_pub_keys, input_key_imgs);
// sum xmr in inputs and ouputs in the given tx
array<uint64_t, 4> const& sum_data = xmreg::summary_of_in_out_rct(
tx, output_pub_keys, input_key_imgs);
xmr_outputs = sum_data[0];
xmr_inputs = sum_data[1];
mixin_no = sum_data[2];
num_nonrct_inputs = sum_data[3];
xmr_outputs = sum_data[0];
xmr_inputs = sum_data[1];
mixin_no = sum_data[2];
num_nonrct_inputs = sum_data[3];
j_response["xmr_outputs"] = xmr_outputs;
j_response["xmr_inputs"] = xmr_inputs;
j_response["mixin_no"] = mixin_no;
j_response["num_of_outputs"] = output_pub_keys.size();
j_response["num_of_inputs"] = input_key_imgs.size();
j_response["xmr_outputs"] = xmr_outputs;
j_response["xmr_inputs"] = xmr_inputs;
j_response["mixin_no"] = mixin_no;
j_response["num_of_outputs"] = output_pub_keys.size();
j_response["num_of_inputs"] = input_key_imgs.size();
if (!coinbase && tx.vin.size() > 0)
if (!coinbase && tx.vin.size() > 0)
{
// check if not miner tx
// i.e., for blocks without any user transactions
if (tx.vin.at(0).type() != typeid(txin_gen))
{
// check if not miner tx
// i.e., for blocks without any user transactions
if (tx.vin.at(0).type() != typeid(txin_gen))
{
// get tx fee
fee = get_tx_fee(tx);
}
// get tx fee
fee = get_tx_fee(tx);
}
}
j_response["fee"] = fee;
j_response["fee"] = fee;
// get tx size in bytes
size = get_object_blobsize(tx);
// get tx size in bytes
size = get_object_blobsize(tx);
j_response["size"] = size;
j_response["size"] = size;
// to be field later on using data from OutputInputIdentification
j_response["total_sent"] = "0";
j_response["total_received"] = "0";
// to be field later on using data from OutputInputIdentification
j_response["total_sent"] = "0";
j_response["total_received"] = "0";
int64_t tx_height {-1};
int64_t tx_height {-1};
int64_t no_confirmations {-1};
int64_t no_confirmations {-1};
if (current_bc_status->get_tx_block_height(tx_hash, tx_height))
{
// get the current blockchain height. Just to check
uint64_t bc_height = get_current_blockchain_height();
if (current_bc_status->get_tx_block_height(tx_hash, tx_height))
{
// get the current blockchain height. Just to check
uint64_t bc_height = get_current_blockchain_height();
no_confirmations = bc_height - tx_height;
}
no_confirmations = bc_height - tx_height;
}
// Class that is responsible for identification of our outputs
// and inputs in a given tx.
j_response["payment_id"] = string {};
j_response["timestamp"] = default_timestamp;
address_parse_info address_info;
secret_key viewkey;
// to get info about recived xmr in this tx, we calculate it from
// scrach, i.e., search for outputs. We could get this info
// directly from the database, but doing it again here, is a good way
// to double check tx data in the frontend, and also maybe try doing
// it differently than before. Its not great, since we reinvent
// the wheel
// but its worth double checking
// the mysql data, and also allows for new
// implementation in the frontend.
if (current_bc_status->get_xmr_address_viewkey(
xmr_address, address_info, viewkey))
{
OutputInputIdentification oi_identification {
&address_info, &viewkey, &tx, tx_hash,
coinbase};
// Class that is responsible for identification of our outputs
// and inputs in a given tx.
oi_identification.identify_outputs();
j_response["payment_id"] = string {};
j_response["timestamp"] = default_timestamp;
uint64_t total_received {0};
address_parse_info address_info;
secret_key viewkey;
// we just get total amount recieved. we have viewkey,
// so this must be correct and front end does not
// need to do anything to check this.
for (auto& out_info: oi_identification.identified_outputs)
{
total_received += out_info.amount;
}
MicroCoreAdapter mcore_addapter {current_bc_status.get()};
j_response["total_received"] = std::to_string(total_received);
// to get info about recived xmr in this tx, we calculate it from
// scrach, i.e., search for outputs. We could get this info
// directly from the database, but doing it again here, is a good way
// to double check tx data in the frontend, and also maybe try doing
// it differently than before. Its not great, since we reinvent
// the wheel
// but its worth double checking
// the mysql data, and also allows for new
// implementation in the frontend.
if (current_bc_status->get_xmr_address_viewkey(
xmr_address, address_info, viewkey))
{
auto identifier = make_identifier(tx,
make_unique<Output>(&address_info, &viewkey));
json j_spent_outputs = json::array();
identifier.identify();
auto const& outputs_identified
= identifier.get<Output>()->get();
// to get spendings, we need to have our key_images. but
// the backend does not have spendkey, so it cant determine
// which key images are really ours or not. this is the task
// for the frontend. however, backend can only provide guesses and
// nessessery data to the frontend to filter out incorrect
// guesses.
//
// for input identification, we will use our mysql. its just much
// faster to use it here, than before. but first we need to
// get account id of the user asking for tx details.
auto total_received = calc_total_xmr(outputs_identified);
// a placeholder for exciting or new account data
XmrAccount acc;
j_response["total_received"] = std::to_string(total_received);
json j_spent_outputs = json::array();
// to get spendings, we need to have our key_images. but
// the backend does not have spendkey, so it cant determine
// which key images are really ours or not. this is the task
// for the frontend. however, backend can only provide guesses and
// nessessery data to the frontend to filter out incorrect
// guesses.
//
// for input identification, we will use our mysql. its just much
// faster to use it here, than before. but first we need to
// get account id of the user asking for tx details.
// a placeholder for exciting or new account data
XmrAccount acc;
// select this account if its existing one
if (xmr_accounts->select(xmr_address, acc))
{
// if user exist, get tx data from database
// this will work only for tx in the blockchain,
// not those in the mempool.
// select this account if its existing one
if (xmr_accounts->select(xmr_address, acc))
if (!tx_in_mempool)
{
// if user exist, get tx data from database
// this will work only for tx in the blockchain,
// not those in the mempool.
// if not in mempool, but in blockchain, just
// get data aout key images from the mysql
if (!tx_in_mempool)
XmrTransaction xmr_tx;
if (xmr_accounts->tx_exists(
acc.id.data, tx_hash_str, xmr_tx))
{
// if not in mempool, but in blockchain, just
// get data aout key images from the mysql
j_response["payment_id"] = xmr_tx.payment_id;
j_response["timestamp"]
= static_cast<uint64_t>(xmr_tx.timestamp*1e3);
XmrTransaction xmr_tx;
vector<XmrInput> inputs;
if (xmr_accounts->tx_exists(
acc.id.data, tx_hash_str, xmr_tx))
if (xmr_accounts->select_for_tx(
xmr_tx.id.data, inputs))
{
j_response["payment_id"] = xmr_tx.payment_id;
j_response["timestamp"]
= static_cast<uint64_t>(xmr_tx.timestamp*1e3);
json j_spent_outputs = json::array();
vector<XmrInput> inputs;
uint64_t total_spent {0};
if (xmr_accounts->select_for_tx(
xmr_tx.id.data, inputs))
for (XmrInput input: inputs)
{
json j_spent_outputs = json::array();
uint64_t total_spent {0};
XmrOutput out;
for (XmrInput input: inputs)
if (xmr_accounts
->select_by_primary_id(
input.output_id, out))
{
XmrOutput out;
total_spent += input.amount;
if (xmr_accounts
->select_by_primary_id(
input.output_id, out))
{
total_spent += input.amount;
j_spent_outputs.push_back({
{"amount" , std::to_string(input.amount)},
{"key_image" , input.key_image},
{"tx_pub_key" , out.tx_pub_key},
{"out_index" , out.out_index},
{"mixin" , out.mixin}});
}
j_spent_outputs.push_back({
{"amount" , std::to_string(input.amount)},
{"key_image" , input.key_image},
{"tx_pub_key" , out.tx_pub_key},
{"out_index" , out.out_index},
{"mixin" , out.mixin}});
}
} // for (XmrInput input: inputs)
} // for (XmrInput input: inputs)
j_response["total_sent"] = std::to_string(total_spent);
j_response["total_sent"] = std::to_string(total_spent);
j_response["spent_outputs"] = j_spent_outputs;
j_response["spent_outputs"] = j_spent_outputs;
} // if (xmr_accounts->select_inputs_
} // if (xmr_accounts->select_inputs_
} // if (xmr_accounts->tx_exists(acc.id
} // if (xmr_accounts->tx_exists(acc.id
} // if (!tx_in_mempool)
else
{
// if tx in mempool, mysql will not have this tx, so
// we cant pull info about key images from mysql for this tx.
// we have to redo this info from basically from scrach.
} // if (!tx_in_mempool)
else
unordered_map<public_key, uint64_t> known_outputs_keys;
if (current_bc_status->get_known_outputs_keys(
xmr_address, known_outputs_keys))
{
// if tx in mempool, mysql will not have this tx, so
// we cant pull info about key images from mysql for this tx.
// we got known_outputs_keys from the search thread.
// so now we can use OutputInputIdentification to
// get info about inputs.
// Class that is resposnible for idenficitaction
// of our outputs
// and inputs in a given tx.
auto identifier = make_identifier(tx,
make_unique<Input>(&address_info, &viewkey,
&known_outputs_keys,
&mcore_addapter));
identifier.identify();
auto const& inputs_identfied
= identifier.get<Input>()->get();
// we have to redo this info from basically from scrach.
json j_spent_outputs = json::array();
unordered_map<public_key, uint64_t> known_outputs_keys;
uint64_t total_spent {0};
if (current_bc_status->get_known_outputs_keys(
xmr_address, known_outputs_keys))
for (auto& in_info: inputs_identfied)
{
// we got known_outputs_keys from the search thread.
// so now we can use OutputInputIdentification to
// get info about inputs.
// Class that is resposnible for idenficitaction
// of our outputs
// and inputs in a given tx.
OutputInputIdentification oi_identification
{&address_info, &viewkey, &tx, tx_hash,
coinbase};
// no need mutex here, as this will be exectued only
// after the above. there is no threads here.
oi_identification.identify_inputs(known_outputs_keys,
current_bc_status.get());
json j_spent_outputs = json::array();
// need to get output info from mysql, as we need
// to know output's amount, its orginal
// tx public key and its index in that tx
XmrOutput out;
uint64_t total_spent {0};
string out_pub_key
= pod_to_hex(in_info.out_pub_key);
for (auto& in_info: oi_identification.identified_inputs)
if (xmr_accounts->output_exists(out_pub_key, out))
{
total_spent += out.amount;
// need to get output info from mysql, as we need
// to know output's amount, its orginal
// tx public key and its index in that tx
XmrOutput out;
string out_pub_key
= pod_to_hex(in_info.out_pub_key);
if (xmr_accounts->output_exists(out_pub_key, out))
{
total_spent += out.amount;
j_spent_outputs.push_back({
{"amount" , std::to_string(in_info.amount)},
{"key_image" , pod_to_hex(in_info.key_img)},
{"tx_pub_key" , out.tx_pub_key},
{"out_index" , out.out_index},
{"mixin" , out.mixin}});
}
j_spent_outputs.push_back({
{"amount" , std::to_string(in_info.amount)},
{"key_image" , in_info.key_img},
{"tx_pub_key" , out.tx_pub_key},
{"out_index" , out.out_index},
{"mixin" , out.mixin}});
}
} // for (auto& in_info: oi_identification
} // for (auto& in_info: oi_identification
j_response["total_sent"] = std::to_string(total_spent);
j_response["total_sent"] = std::to_string(total_spent);
j_response["spent_outputs"] = j_spent_outputs;
j_response["spent_outputs"] = j_spent_outputs;
} //if (current_bc_status->get_known_outputs_keys(
// xmr_address, known_outputs_keys))
} //if (current_bc_status->get_known_outputs_keys(
// xmr_address, known_outputs_keys))
} // else
} // else
} // if (xmr_accounts->select(xmr_address, acc))
} // if (xmr_accounts->select(xmr_address, acc))
} // if (current_bc_status->get_xmr_add
} // if (current_bc_status->get_xmr_add
j_response["tx_height"] = tx_height;
j_response["no_confirmations"] = no_confirmations;
j_response["status"] = "OK";
j_response["error"] = "";
}
else
{
cerr << "Cant get tx details for tx hash! : " << tx_hash_str << '\n';
j_response["status"] = "Cant get tx details for tx hash! : " + tx_hash_str;
}
j_response["tx_height"] = tx_height;
j_response["no_confirmations"] = no_confirmations;
j_response["status"] = "OK";
j_response["error"] = "";
string response_body = j_response.dump();
@ -1748,7 +1713,7 @@ OpenMoneroRequests::get_version(
{"last_git_commit_hash", string {GIT_COMMIT_HASH}},
{"last_git_commit_date", string {GIT_COMMIT_DATETIME}},
{"git_branch_name" , string {GIT_BRANCH_NAME}},
{"monero_version_full" , string {MONERO_VERSION_FULL}},
{"monero_version_full" , string {"MONERO_VERSION_FULL"}},
{"api" , OPENMONERO_RPC_VERSION},
{"testnet" , current_bc_status->get_bc_setup().net_type
== network_type::TESTNET},
@ -1839,7 +1804,7 @@ OpenMoneroRequests::body_to_json(const Bytes & body)
uint64_t
OpenMoneroRequests::get_current_blockchain_height()
OpenMoneroRequests::get_current_blockchain_height() const
{
return current_bc_status->get_current_blockchain_height();
}
@ -1949,7 +1914,7 @@ OpenMoneroRequests::parse_request(
const Bytes& body,
vector<string>& values_map,
json& j_request,
json& j_response)
json& j_response) const
{
try
{
@ -1984,23 +1949,139 @@ OpenMoneroRequests::parse_request(
}
}
boost::optional<XmrAccount>
OpenMoneroRequests::create_account(
string const& xmr_address,
string const& view_key) const
{
boost::optional<XmrAccount> acc = XmrAccount{};
if (xmr_accounts->select(xmr_address, *acc))
{
// if acc already exist, just return
// existing one
return acc;
}
uint64_t current_blockchain_height = get_current_blockchain_height();
// initialize current blockchain timestamp with current time
// in a moment we will try to get last block timestamp
// to replace this value. But if it fails, we just use current
// timestamp
uint64_t current_blockchain_timestamp = std::time(nullptr);
// get last block so we have its timestamp when
// createing the account
block last_blk;
if (current_bc_status->get_block(current_blockchain_height, last_blk))
{
current_blockchain_timestamp = last_blk.timestamp;
}
DateTime blk_timestamp_mysql_format
= XmrTransaction::timestamp_to_DateTime(
current_blockchain_timestamp);
// create new account
acc = XmrAccount(
mysqlpp::null,
xmr_address,
make_hash(view_key),
current_blockchain_height, /* for scanned_block_height */
blk_timestamp_mysql_format,
current_blockchain_height);
uint64_t acc_id {0};
// insert the new account into the mysql
if ((acc_id = xmr_accounts->insert(*acc)) == 0)
{
// if creating account failed
OMERROR << xmr_address.substr(0,6) + ": account creation failed";
return {};
}
// add acc database id
acc->id = acc_id;
// add also the view_key into acc object. its needs to be done
// as we dont store viewkeys in the database
acc->viewkey = view_key;
return acc;
}
boost::optional<XmrAccount>
OpenMoneroRequests::select_account(
string const& xmr_address) const
string const& xmr_address,
string const& view_key,
bool create_if_notfound) const
{
boost::optional<XmrAccount> acc = XmrAccount{};
if (!xmr_accounts->select(xmr_address, *acc))
{
OMERROR << xmr_address.substr(0,6) +
": address does not exists!";
OMINFO << xmr_address.substr(0,6) +
": address does not exists";
return acc;
if (!create_if_notfound)
return {};
// for this address
if (!(acc = create_account(xmr_address, view_key)))
return {};
// once account has been created
// make and start a search thread for it
if (!make_search_thread(*acc))
return {};
}
// also need to check if view key matches
string viewkey_hash = make_hash(view_key);
if (viewkey_hash != acc->viewkey_hash)
{
OMWARN << xmr_address.substr(0,6) +
": viewkey does not match " +
"the one in database!";
return {};
}
return acc;
}
bool
OpenMoneroRequests::make_search_thread(
XmrAccount& acc) const
{
if (current_bc_status->search_thread_exist(acc.address))
{
return true;
}
std::unique_ptr<TxSearch> tx_search;
try
{
tx_search = std::make_unique<TxSearch>(
acc, current_bc_status);
}
catch (std::exception const& e)
{
OMERROR << acc.address.substr(0,6)
+ ": txSearch construction faild.";
return false;
}
return current_bc_status->start_tx_search_thread(
acc, std::move(tx_search));
}
boost::optional<XmrPayment>
OpenMoneroRequests::select_payment(
XmrAccount const& xmr_account) const

@ -8,12 +8,8 @@
#include <iostream>
#include <functional>
#include "version.h"
#include "CurrentBlockchainStatus.h"
#include "db/MySqlAccounts.h"
#include "../gen/version.h"
#include "../ext/restbed/source/restbed"
@ -135,7 +131,7 @@ public:
body_to_json(const Bytes & body);
inline uint64_t
get_current_blockchain_height();
get_current_blockchain_height() const;
private:
@ -151,10 +147,19 @@ private:
parse_request(const Bytes& body,
vector<string>& values_map,
json& j_request,
json& j_response);
json& j_response) const;
boost::optional<XmrAccount>
create_account(string const& xmr_address,
string const& view_key) const;
bool
make_search_thread(XmrAccount& acc) const;
boost::optional<XmrAccount>
select_account(string const& xmr_address) const;
select_account(string const& xmr_address,
string const& view_key,
bool create_if_notfound = true) const;
boost::optional<XmrPayment>
select_payment(XmrAccount const& xmr_account) const;

@ -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)
{
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))
{
OMWARN << "Cant get derived key for tx: "
<< pod_to_hex(tx_hash)
<< ", pub_tx_key: "
<< pod_to_hex(tx_pub_key);
static_assert(sizeof(derivation) == sizeof(rct::key),
"Mismatched sizes of key_derivation and rct::key");
// use identity derivation instead
// solution based on that found in wallet2.cpp in monero
// this will cause the tx output to be effectively skipped
memcpy(&derivation, rct::identity().bytes, sizeof(derivation));
}
}
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,
CurrentBlockchainStatus* current_bc_status)
{
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,249 +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:
// 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;
// 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);
/**
* 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,
CurrentBlockchainStatus* current_bc_status);
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;
};
//class BaseIdentifier {
//public:
// BaseIdentifier(address_parse_info const* _a,
// const secret_key* _v,
// const transaction* _tx)
// : address_info {_a}, viewkey {_v}, tx {_tx}
// {
// }
// virtual void identify() = 0;
//protected:
// // address and viewkey for this search thread.
// address_parse_info const* address_info;
// secret_key const* viewkey;
// // transaction that is beeing search
// transaction const* tx;
//};
//class OutputIdentifier : public BaseIdentifier
//{
// using BaseIdentifier::BaseIdentifier;
// using key_imgs_map = unordered_map<public_key, uint64_t>;
// // 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;
// };
//public:
// void
// set_known_outputs(key_imgs_map const* _known_outputs)
// {
// known_outputs_keys = _known_outputs;
// }
// void
// identify()
// {}
//private:
// key_imgs_map const* known_outputs_keys {nullptr};
//};
//class InpputIdentifier : public BaseIdentifier
//{
// using BaseIdentifier::BaseIdentifier;
// // 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;
// };
//public:
// void
// identify()
// {}
//};
}

@ -1,127 +0,0 @@
#pragma once
#include "om_log.h"
#include "OutputInputIdentification.h"
#include "UniversalIdentifier.hpp"
#include <map>
#include <utility>
namespace xmreg
{
class PaymentSearcherException: public std::runtime_error
{
using std::runtime_error::runtime_error;
};
/**
* Class for searching transactions having given payment_id
* This is primarly used to check if a payment was made
* for importing wallet
*/
template<typename Hash_T>
class PaymentSearcher
{
public:
PaymentSearcher(
address_parse_info const& _address_info,
secret_key const& _viewkey):
address_info {_address_info},
viewkey {_viewkey}
{}
template<template<typename T,
typename A = std::allocator<T>>
class Cont_T>
std::pair<uint64_t, typename Cont_T<transaction>::const_iterator>
search(Hash_T const& expected_payment_id,
Cont_T<transaction> const& txs,
bool skip_coinbase = true)
{
//auto null_hash = null_hash_T();
uint64_t found_amount {0};
Hash_T null_hash {};
// iterator to last txs that we found containing
// our payment
auto found_tx_it = std::cend(txs);
for (auto it = std::cbegin(txs);
it != std::cend(txs); ++it)
{
auto const& tx = *it;
bool is_coinbase_tx = is_coinbase(tx);
if (skip_coinbase && is_coinbase_tx)
continue;
auto identifier = make_identifier(tx,
make_unique<Output>(&address_info, &viewkey),
make_unique<IntegratedPaymentID>(&address_info, &viewkey));
auto tx_pub_key = identifier.get_tx_pub_key();
identifier.template get<IntegratedPaymentID>()
->identify(tx, tx_pub_key);
auto pay_id = identifier.template get<IntegratedPaymentID>()
->get();
// we have pay_id. it can be crypto::hash8 or crypto:hash
// so naw we need to perform comparison of the pay_id found
// with the expected value of payment_id
// for hash8 we need to do decoding of the pay_id, as it is
// encoded
if (pay_id != expected_payment_id)
continue;
// if everything ok with payment id, we proceed with
// checking how much xmr we got in that tx.
// for each output, in a tx, check if it belongs
// to the given account of specific address and viewkey
identifier.template get<Output>()->identify(tx, tx_pub_key);
auto const& outputs_found
= identifier.template get<Output>()->get();
if (!outputs_found.empty())
{ // nothing was found
make_pair(found_amount, found_tx_it);
}
// now add the found outputs into Outputs tables
for (auto& out_info: outputs_found)
found_amount += out_info.amount;
if (found_amount > 0)
found_tx_it = it;
}
return make_pair(found_amount, found_tx_it);
}
virtual ~PaymentSearcher() = default;
private:
address_parse_info const& address_info;
secret_key const& viewkey;
};
}

@ -6,7 +6,7 @@
#ifndef CROWXMR_RPCCALLS_H
#define CROWXMR_RPCCALLS_H
#include "monero_headers.h"
#include "src/monero_headers.h"
#include <mutex>
#include <chrono>

@ -2,7 +2,7 @@
#define RANDOMOUTPUTS_H
#include "om_log.h"
#include "MicroCore.h"
#include "src/MicroCore.h"
namespace xmreg

File diff suppressed because it is too large Load Diff

@ -1,7 +1,6 @@
#pragma once
#include "db/MySqlAccounts.h"
#include "OutputInputIdentification.h"
#include <memory>
#include <mutex>
@ -98,7 +97,7 @@ public:
// make default constructor. useful in testing
TxSearch() = default;
TxSearch(XmrAccount& _acc,
TxSearch(XmrAccount const& _acc,
std::shared_ptr<CurrentBlockchainStatus> _current_bc_status);
virtual void

@ -1,7 +1,7 @@
#ifndef TXUNLOCKCHECKER_H
#define TXUNLOCKCHECKER_H
#include "monero_headers.h"
#include "src/monero_headers.h"
namespace xmreg
{

@ -1,352 +0,0 @@
#include "UniversalIdentifier.hpp"
namespace xmreg
{
void
Output::identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys)
{
auto tx_is_coinbase = is_coinbase(tx);
key_derivation derivation;
if (!generate_key_derivation(tx_pub_key,
*get_viewkey(), derivation))
{
throw std::runtime_error("generate_key_derivation failed");
}
// since introduction of subaddresses, a tx can
// have extra public keys, thus we need additional
// derivations
vector<key_derivation> additional_derivations;
if (!additional_tx_pub_keys.empty())
{
additional_derivations.resize(additional_tx_pub_keys.size());
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
{
if (!generate_key_derivation(additional_tx_pub_keys[i],
*get_viewkey(),
additional_derivations[i]))
{
throw std::runtime_error("additional generate_key_derivation failed");
}
}
}
for (auto i = 0u; i < tx.vout.size(); ++i)
{
// i will act as output indxes in the tx
if (tx.vout[i].target.type() != typeid(txout_to_key))
continue;
// get tx input key
txout_to_key const& txout_key
= boost::get<txout_to_key>(tx.vout[i].target);
uint64_t amount = tx.vout[i].amount;
// 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,
i,
get_address()->address.m_spend_public_key,
generated_tx_pubkey);
// cout << pod_to_hex(derivation) << ", " << i << ", "
// << pod_to_hex(get_address()->address.m_spend_public_key) << ", "
// << pod_to_hex(txout_key.key) << " == "
// << pod_to_hex(generated_tx_pubkey) << '\n' << '\n';
// check if generated public key matches the current output's key
bool mine_output = (txout_key.key == generated_tx_pubkey);
auto with_additional = false;
if (!mine_output && !additional_tx_pub_keys.empty())
{
// check for output using additional tx public keys
derive_public_key(additional_derivations[i],
i,
get_address()->address.m_spend_public_key,
generated_tx_pubkey);
mine_output = (txout_key.key == generated_tx_pubkey);
with_additional = true;
}
// placeholder variable for ringct outputs info
// that we need to save in database
rct::key rtc_outpk {0};
rct::key rtc_mask {0};
rct::key rtc_amount {0};
// 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)
{
// 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 = tx.rct_signatures.outPk[i].mask;
rtc_mask = tx.rct_signatures.ecdhInfo[i].mask;
rtc_amount = tx.rct_signatures.ecdhInfo[i].amount;
rct::key mask = tx.rct_signatures
.ecdhInfo[i].mask;
auto r = decode_ringct(tx.rct_signatures,
!with_additional ? derivation
: additional_derivations[i],
i,
mask,
rct_amount_val);
if (!r)
{
throw std::runtime_error(
"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(
info{
txout_key.key, amount, i, derivation,
rtc_outpk, rtc_mask, rtc_amount
});
total_xmr += amount;
} // if (mine_output)
} // for (uint64_t i = 0; i < tx.vout.size(); ++i)
}
void Input::identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys)
{
auto search_misses {0};
auto input_no = tx.vin.size();
for (auto i = 0u; i < input_no; ++i)
{
if(tx.vin[i].type() != typeid(txin_to_key))
continue;
// get tx input key
txin_to_key const& in_key
= boost::get<txin_to_key>(tx.vin[i]);
// get absolute offsets of mixins
vector<uint64_t> absolute_offsets
= relative_output_offsets_to_absolute(
in_key.key_offsets);
// get public keys of outputs used in the mixins that
// match to the offests
vector<output_data_t> mixin_outputs;
// this can THROW if no outputs are found
mcore->get_output_key(in_key.amount,
absolute_offsets,
mixin_outputs);
// indicates whether we found any matching mixin in the current input
auto found_a_match {false};
// for each found output public key check if its ours or not
for (auto count = 0u; count < absolute_offsets.size(); ++count)
{
// get basic information about mixn's output
output_data_t const& output_data
= mixin_outputs.at(count);
// 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->find(output_data.pubkey);
if (it != known_outputs->end())
{
// this seems to be our mixin.
// save it into identified_inputs vector
identified_inputs.push_back(info {
in_key.k_image,
it->second, // amount
output_data.pubkey});
total_xmr += it->second;
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 (auto i = 0u; i < input_no; ++i)
}
void RealInput::identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys)
{
auto search_misses {0};
auto input_no = tx.vin.size();
for (auto i = 0u; i < input_no; ++i)
{
if(tx.vin[i].type() != typeid(txin_to_key))
continue;
// get tx input key
txin_to_key const& in_key
= boost::get<cryptonote::txin_to_key>(tx.vin[i]);
// get absolute offsets of mixins
auto absolute_offsets
= relative_output_offsets_to_absolute(
in_key.key_offsets);
//tx_out_index is pair::<transaction hash, output index>
vector<tx_out_index> indices;
// get tx hashes and indices in the txs for the
// given outputs of mixins
// this cant THROW DB_EXCEPTION
mcore->get_output_tx_and_index(
in_key.amount, absolute_offsets, indices);
// placeholder for information about key image that
// we will find as ours
unique_ptr<info> key_image_info {nullptr};
// for each found mixin tx, check if any key image
// generated using our outputs in the mixin tx
// matches the given key image in the current tx
for (auto const& txi : indices)
{
auto const& mixin_tx_hash = txi.first;
auto const& output_index_in_tx = txi.second;
transaction mixin_tx;
if (!mcore->get_tx(mixin_tx_hash, mixin_tx))
{
throw std::runtime_error("Cant get tx: "
+ pod_to_hex(mixin_tx_hash));
}
// use Output universal identifier to identify our outputs
// in a mixin tx
auto identifier = make_identifier(
mixin_tx,
make_unique<Output>(get_address(), get_viewkey()));
identifier.identify();
for (auto const& found_output: identifier.get<Output>()->get())
{
// generate key_image using this output
// to check for sure if the given key image is ours
// or not
crypto::key_image key_img_generated;
if (!xmreg::generate_key_image(found_output.derivation,
found_output.idx_in_tx, /* position in the tx */
*spendkey,
get_address()->address.m_spend_public_key,
key_img_generated))
{
throw std::runtime_error("Cant generate key image for output: "
+ pod_to_hex(found_output.pub_key));
}
// now check if current key image in the tx which we
// analyze matches generated key image
if (in_key.k_image == key_img_generated)
{
// this is our key image if they are equal!
key_image_info.reset(new info {key_img_generated,
found_output.amount,
found_output.pub_key});
break;
}
} // auto const& found_output: identifier.get<Output>()->get_outputs()
// if key_image_info has been populated, there is no
// reason to keep check remaning outputs in the mixin tx
// instead add its info to identified_inputs and move on
// to the next key image
if (key_image_info)
{
identified_inputs.push_back(*key_image_info);
total_xmr += key_image_info->amount;
break;
}
} // for (auto const& txi : indices)
} // for (auto i = 0u; i < input_no; ++i)
}
}

@ -1,332 +0,0 @@
#pragma once
#include "om_log.h"
#include "tools.h"
#include "MicroCore.h"
#include <tuple>
#include <utility>
namespace xmreg
{
using namespace std;
class AbstractIdentifier
{
public:
virtual void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) = 0;
};
class BaseIdentifier : public AbstractIdentifier
{
public:
BaseIdentifier(
address_parse_info const* _address,
secret_key const* _viewkey)
: address_info {_address}, viewkey {_viewkey}
{}
virtual void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) = 0;
inline auto get_address() const {return address_info;}
inline auto get_viewkey() const {return viewkey;}
inline auto get_total() const {return total_xmr;}
virtual ~BaseIdentifier() = default;
protected:
address_parse_info const* address_info {nullptr};
secret_key const* viewkey {nullptr};
uint64_t total_xmr {0};
};
/**
* @brief The Output class identifies our
* outputs in a given tx
*/
class Output : public BaseIdentifier
{
public:
Output(address_parse_info const* _address,
secret_key const* _viewkey)
: BaseIdentifier(_address, _viewkey)
{}
void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) override;
inline auto get() const
{
return identified_outputs;
}
struct info
{
public_key pub_key;
uint64_t amount;
uint64_t idx_in_tx;
key_derivation derivation;
rct::key rtc_outpk;
rct::key rtc_mask;
rct::key rtc_amount;
friend std::ostream& operator<<(std::ostream& os, info const& _info);
};
protected:
uint64_t total_received {0};
vector<info> identified_outputs;
};
/**
* @brief The Input class identifies our possible
* inputs (key images) in a given tx
*/
class Input : public BaseIdentifier
{
public:
//output_pubk , amount
using known_outputs_t = unordered_map<public_key, uint64_t>;
Input(address_parse_info const* _a,
secret_key const* _viewkey,
known_outputs_t const* _known_outputs,
MicroCore* _mcore)
: BaseIdentifier(_a, _viewkey),
known_outputs {_known_outputs},
mcore {_mcore}
{}
void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) override;
inline auto get() const
{
return identified_inputs;
}
struct info
{
key_image key_img;
uint64_t amount;
public_key out_pub_key;
friend std::ostream& operator<<(std::ostream& os, info const& _info);
};
protected:
secret_key const* viewkey {nullptr};
known_outputs_t const* known_outputs {nullptr};
MicroCore* mcore {nullptr};
vector<info> identified_inputs;
};
/**
* Spendkey is optional. But if we have it,
* we can for sure determine which key images
* are ours or not. This is especially useful
* in unit testing, since we can compare wether
* guessed key images do contain all our key images
*/
class RealInput : public Input
{
public:
RealInput(address_parse_info const* _a,
secret_key const* _viewkey,
secret_key const* _spendkey,
MicroCore* _mcore)
: Input(_a, _viewkey, nullptr, _mcore),
spendkey {_spendkey}
{}
void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) override;
protected:
secret_key const* spendkey {nullptr};
};
template <typename HashT>
class PaymentID : public BaseIdentifier
{
public:
PaymentID(address_parse_info const* _address,
secret_key const* _viewkey)
: BaseIdentifier(_address, _viewkey)
{}
void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) override
{
cout << "PaymentID decryption: "
+ pod_to_hex(payment_id) << endl;
// get payment id. by default we are intrested
// in short ids from integrated addresses
auto payment_id_tuple = xmreg::get_payment_id(tx);
payment_id = std::get<HashT>(payment_id_tuple);
// if no payment_id found, return
if (payment_id == null_hash)
return;
// decrypt integrated payment id. if its legacy payment id
// nothing will happen.
if (!decrypt(payment_id, tx_pub_key))
{
throw std::runtime_error("Cant decrypt pay_id: "
+ pod_to_hex(payment_id));
}
}
inline bool
decrypt(crypto::hash& p_id,
public_key const& tx_pub_key) const
{
// don't need to do anything for legacy payment ids
return true;
}
inline bool
decrypt(crypto::hash8& p_id,
public_key const& tx_pub_key) const
{
// overload for short payment id,
// the we are going to decrypt
return xmreg::encrypt_payment_id(
p_id, tx_pub_key, *get_viewkey());
}
inline auto get() const {return payment_id;}
private:
HashT payment_id {};
HashT null_hash {};
};
using LegacyPaymentID = PaymentID<crypto::hash>;
using IntegratedPaymentID = PaymentID<crypto::hash8>;
template<typename... T>
class ModularIdentifier
{
public:
tuple<unique_ptr<T>...> identifiers;
ModularIdentifier(transaction const& _tx,
unique_ptr<T>... args)
: identifiers {move(args)...},
tx {_tx}
{
// having tx public key is very common for all identifiers
// so we can get it here, instead of just obtaining it
// for each identifier seprately
tx_pub_key = get_tx_pub_key_from_received_outs(tx);
// multi-output txs can have some additional public keys
// in the extra field. So we also get them, just in case
additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
}
void identify()
{
auto b = {(std::get<unique_ptr<T>>(
identifiers)->identify(
tx, tx_pub_key, additional_tx_pub_keys),
true)...};
(void) b;
}
// overload to get value from tuple by type
template <typename U>
auto* const get()
{
return std::get<unique_ptr<U>>(identifiers).get();
}
// overload to get value from tuple by number
template <size_t No>
auto* const get()
{
return std::get<No>(identifiers).get();
}
inline auto get_tx_pub_key() const {return tx_pub_key;}
private:
transaction const& tx;
public_key tx_pub_key;
vector<public_key> additional_tx_pub_keys;
};
/**
* A helper function to create ModularIdentifier object
*/
template<typename... T>
auto make_identifier(transaction const& tx, T&&... identifiers)
{
return ModularIdentifier<typename T::element_type...>(
tx, std::forward<T>(identifiers)...);
}
template <typename T>
auto
calc_total_xmr(T&& infos)
{
uint64_t total_xmr {0};
for (auto const& info: infos)
total_xmr += info.amount;
return total_xmr;
}
inline std::ostream&
operator<<(std::ostream& os, xmreg::Output::info const& _info)
{
return os << _info.idx_in_tx << ", "
<< pod_to_hex(_info.pub_key) << ", "
<< _info.amount;
}
inline std::ostream&
operator<<(std::ostream& os, xmreg::Input::info const& _info)
{
return os << pod_to_hex(_info.key_img) << ", "
<< pod_to_hex(_info.out_pub_key) << ", "
<< _info.amount;
}
}

@ -255,6 +255,8 @@ MySqlAccounts::select(const string& address, XmrAccount& account)
vector<XmrAccount> res;
query.storein(res, address);
//while(query.more_results());
if (!res.empty())
{
account = std::move(res.at(0));

@ -5,7 +5,7 @@
#ifndef RESTBED_XMR_MYSQLACCOUNTS_H
#define RESTBED_XMR_MYSQLACCOUNTS_H
#include "../tools.h"
#include "../utils.h"
#include "MySqlConnector.h"

@ -5,7 +5,7 @@
#ifndef RESTBED_XMR_SSQLSES_H
#define RESTBED_XMR_SSQLSES_H
#include "../../ext/json.hpp"
#include "ext/json.hpp"
#include <mysql++/mysql++.h>
#include <mysql++/ssqls.h>

@ -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

@ -2,7 +2,7 @@
// Created by marcin on 5/11/15.
//
#include "tools.h"
#include "utils.h"
#include <codecvt>
@ -955,50 +955,6 @@ parse_crow_post_data(const string& req_body)
return body;
}
// based on
// crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const
public_key
get_tx_pub_key_from_received_outs(const transaction &tx)
{
std::vector<tx_extra_field> tx_extra_fields;
if(!parse_tx_extra(tx.extra, tx_extra_fields))
{
// Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
}
// Due to a previous bug, there might be more than one tx pubkey in extra, one being
// the result of a previously discarded signature.
// For speed, since scanning for outputs is a slow process, we check whether extra
// contains more than one pubkey. If not, the first one is returned. If yes, they're
// checked for whether they yield at least one output
tx_extra_pub_key pub_key_field;
if (!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 0))
{
return null_pkey;
}
public_key tx_pub_key = pub_key_field.pub_key;
bool two_found = find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, 1);
if (!two_found)
{
// easy case, just one found
return tx_pub_key;
}
else
{
// just return second one if there are two.
// this does not require private view key, as
// its not needed for my use case.
return pub_key_field.pub_key;
}
return null_pkey;
}
//string

@ -13,9 +13,9 @@
#define REMOVE_HASH_BRAKETS(a_hash) \
a_hash.substr(1, a_hash.size()-2)
#include "monero_headers.h"
#include "src/monero_headers.h"
#include "../ext/json.hpp"
#include "ext/json.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
@ -226,11 +226,6 @@ map<std::string, std::string>
parse_crow_post_data(const string& req_body);
// based on
// crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const
public_key
get_tx_pub_key_from_received_outs(const transaction &tx);
//string
//xmr_amount_to_str(const uint64_t& xmr_amount, string format="{:0.12f}");

@ -0,0 +1 @@
Subproject commit 1290af5d8b8cd71bc221bf908ee9feb8d2b4d2c4

@ -14,6 +14,11 @@ macro(add_om_test _TEST_NAME)
gmock gmock_main
${LIBRARIES})
target_include_monero_directories(${_TEST_NAME}_tests)
target_include_directories(${_TEST_NAME}_tests
PRIVATE ../src/xmregcore)
add_test(NAME ${_TEST_NAME}_tests COMMAND ${_TEST_NAME}_tests)
endmacro()
@ -24,7 +29,6 @@ add_om_test(mysql)
add_om_test(microcore)
add_om_test(bcstatus)
add_om_test(txsearch)
add_om_test(universalidentifier)
SETUP_TARGET_FOR_COVERAGE(
NAME mysql_cov
@ -42,10 +46,6 @@ SETUP_TARGET_FOR_COVERAGE(
NAME txsearch_cov
EXECUTABLE txsearch_tests)
SETUP_TARGET_FOR_COVERAGE(
NAME universalidentifier_cov
EXECUTABLE universalidentifier_tests)
add_custom_target(cov
COMMAND ;
DEPENDS mysql_cov microcore_cov bcstatus_cov txsearch_cov

@ -1,7 +1,7 @@
#ifndef JSONTX_H
#define JSONTX_H
#include "../src/tools.h"
#include "../src/utils.h"
namespace xmreg
{

@ -1,5 +1,5 @@
#include "../src/MicroCore.h"
#include "src/MicroCore.h"
#include "../src/CurrentBlockchainStatus.h"
#include "../src/ThreadRAII.h"

@ -1,5 +1,7 @@
#pragma once
#include "src/UniversalIdentifier.hpp"
#include <string>
#define RAND_TX_HASH() \

@ -2,7 +2,7 @@
// Created by mwo on 15/06/18.
//
#include "../src/MicroCore.h"
#include "src/MicroCore.h"
#include "../src/BlockchainSetup.h"

@ -1,7 +1,7 @@
#pragma once
#include "../src/MicroCore.h"
#include "src/MicroCore.h"
#include "../src/CurrentBlockchainStatus.h"
#include "../src/ThreadRAII.h"
@ -48,8 +48,8 @@ public:
bool(uint64_t height, block& blk));
MOCK_CONST_METHOD2(get_blocks_range,
std::vector<block>(const uint64_t& h1,
const uint64_t& h2));
std::vector<block>(uint64_t h1,
uint64_t h2));
MOCK_CONST_METHOD3(get_transactions,
bool(const std::vector<crypto::hash>& txs_ids,
@ -66,11 +66,11 @@ public:
uint64_t& tx_id));
MOCK_CONST_METHOD2(get_output_tx_and_index,
tx_out_index(uint64_t const& amount,
uint64_t const& index));
tx_out_index(uint64_t amount,
uint64_t index));
MOCK_CONST_METHOD3(get_output_tx_and_index,
void(const uint64_t& amount,
void(uint64_t amount,
const std::vector<uint64_t> &offsets,
std::vector<tx_out_index> &indices));
@ -88,7 +88,7 @@ public:
uint64_t global_amount_index));
MOCK_CONST_METHOD1(get_tx_amount_output_indices,
std::vector<uint64_t>(uint64_t const& tx_id));
std::vector<uint64_t>(uint64_t tx_id));
MOCK_CONST_METHOD2(get_random_outs_for_amounts,
bool(COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request const& req,
@ -99,7 +99,7 @@ public:
COMMAND_RPC_GET_OUTPUTS_BIN::response& res));
MOCK_CONST_METHOD1(get_dynamic_base_fee_estimate,
uint64_t(uint64_t const& grace_blocks));
uint64_t(uint64_t grace_blocks));
MOCK_CONST_METHOD2(get_mempool_txs,
bool(vector<tx_info>& tx_infos,

@ -2,7 +2,7 @@
// Created by mwo on 15/06/18.
//
#include "../src/MicroCore.h"
#include "src/MicroCore.h"
#include "../src/OpenMoneroRequests.h"
#include "../src/db/MysqlPing.h"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save