Merge pull request #2044
0299cb77
Fix various oversights/bugs in ZMQ RPC server code (Thomas Winget)77986023
json serialization for rpc-relevant monero types (Thomas Winget)5c1e08fe
Refactor some things into more composable (smaller) functions (Thomas Winget)9ac2ad07
DRY refactoring (Thomas Winget)
This commit is contained in:
commit
591e53445b
|
@ -689,6 +689,16 @@ endif()
|
||||||
|
|
||||||
include(version.cmake)
|
include(version.cmake)
|
||||||
|
|
||||||
|
find_path(ZMQ_INCLUDE_PATH zmq.hpp)
|
||||||
|
find_library(ZMQ_LIB zmq)
|
||||||
|
|
||||||
|
if(NOT ZMQ_INCLUDE_PATH)
|
||||||
|
message(FATAL_ERROR "Could not find required header zmq.hpp")
|
||||||
|
endif()
|
||||||
|
if(NOT ZMQ_LIB)
|
||||||
|
message(FATAL_ERROR "Could not find require libzmq")
|
||||||
|
endif()
|
||||||
|
|
||||||
function (treat_warnings_as_errors dirs)
|
function (treat_warnings_as_errors dirs)
|
||||||
foreach(dir ${ARGV})
|
foreach(dir ${ARGV})
|
||||||
set_property(DIRECTORY ${dir}
|
set_property(DIRECTORY ${dir}
|
||||||
|
|
|
@ -107,6 +107,7 @@ endif()
|
||||||
add_subdirectory(mnemonics)
|
add_subdirectory(mnemonics)
|
||||||
if(NOT IOS)
|
if(NOT IOS)
|
||||||
add_subdirectory(rpc)
|
add_subdirectory(rpc)
|
||||||
|
add_subdirectory(serialization)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(wallet)
|
add_subdirectory(wallet)
|
||||||
if(NOT IOS)
|
if(NOT IOS)
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
// Copyright (c) 2016-2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// the loose definitions of types in this file are, well, loose.
|
||||||
|
//
|
||||||
|
// these helpers aren't here for absolute type certainty at compile-time,
|
||||||
|
// but rather to help with templated functions telling types apart.
|
||||||
|
|
||||||
|
namespace sfinae
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef char true_type;
|
||||||
|
|
||||||
|
struct false_type { true_type a[2]; };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_not_container
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
// does not have const iterator
|
||||||
|
template <typename C> static false_type c_iter(typename C::const_iterator*);
|
||||||
|
template <typename C> static true_type c_iter(...);
|
||||||
|
|
||||||
|
// does not have value_type
|
||||||
|
template <typename C> static false_type v_type(typename C::value_type*);
|
||||||
|
template <typename C> static true_type v_type(...);
|
||||||
|
|
||||||
|
// does not have key_type
|
||||||
|
template <typename C> static false_type k_type(typename C::key_type*);
|
||||||
|
template <typename C> static true_type k_type(...);
|
||||||
|
|
||||||
|
// does not have mapped_type
|
||||||
|
template <typename C> static false_type m_type(typename C::mapped_type*);
|
||||||
|
template <typename C> static true_type m_type(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const bool value = (
|
||||||
|
(
|
||||||
|
sizeof(c_iter<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(v_type<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(k_type<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(m_type<T>(0)) == sizeof(true_type)
|
||||||
|
)
|
||||||
|
|| std::is_same<T, std::string>::value
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_vector_like
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
// has const iterator
|
||||||
|
template <typename C> static true_type c_iter(typename C::const_iterator*);
|
||||||
|
template <typename C> static false_type c_iter(...);
|
||||||
|
|
||||||
|
// has value_type
|
||||||
|
template <typename C> static true_type v_type(typename C::value_type*);
|
||||||
|
template <typename C> static false_type v_type(...);
|
||||||
|
|
||||||
|
// does not have key_type
|
||||||
|
template <typename C> static false_type k_type(typename C::key_type*);
|
||||||
|
template <typename C> static true_type k_type(...);
|
||||||
|
|
||||||
|
// does not have mapped_type
|
||||||
|
template <typename C> static false_type m_type(typename C::mapped_type*);
|
||||||
|
template <typename C> static true_type m_type(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const bool value = (
|
||||||
|
sizeof(c_iter<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(v_type<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(k_type<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(m_type<T>(0)) == sizeof(true_type) &&
|
||||||
|
!std::is_same<T, std::string>::value
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_map_like
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
// has const iterator
|
||||||
|
template <typename C> static true_type c_iter(typename C::const_iterator*);
|
||||||
|
template <typename C> static false_type c_iter(...);
|
||||||
|
|
||||||
|
// has value_type
|
||||||
|
template <typename C> static true_type v_type(typename C::value_type*);
|
||||||
|
template <typename C> static false_type v_type(...);
|
||||||
|
|
||||||
|
// has key_type
|
||||||
|
template <typename C> static true_type k_type(typename C::key_type*);
|
||||||
|
template <typename C> static false_type k_type(...);
|
||||||
|
|
||||||
|
// has mapped_type
|
||||||
|
template <typename C> static true_type m_type(typename C::mapped_type*);
|
||||||
|
template <typename C> static false_type m_type(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const bool value = (
|
||||||
|
sizeof(c_iter<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(v_type<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(k_type<T>(0)) == sizeof(true_type) &&
|
||||||
|
sizeof(m_type<T>(0)) == sizeof(true_type) &&
|
||||||
|
!std::is_same<T, std::string>::value
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sfinae
|
|
@ -150,6 +150,7 @@ namespace config
|
||||||
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 19;
|
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 19;
|
||||||
uint16_t const P2P_DEFAULT_PORT = 18080;
|
uint16_t const P2P_DEFAULT_PORT = 18080;
|
||||||
uint16_t const RPC_DEFAULT_PORT = 18081;
|
uint16_t const RPC_DEFAULT_PORT = 18081;
|
||||||
|
uint16_t const ZMQ_RPC_DEFAULT_PORT = 18082;
|
||||||
boost::uuids::uuid const NETWORK_ID = { {
|
boost::uuids::uuid const NETWORK_ID = { {
|
||||||
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10
|
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10
|
||||||
} }; // Bender's nightmare
|
} }; // Bender's nightmare
|
||||||
|
@ -162,6 +163,7 @@ namespace config
|
||||||
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 54;
|
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 54;
|
||||||
uint16_t const P2P_DEFAULT_PORT = 28080;
|
uint16_t const P2P_DEFAULT_PORT = 28080;
|
||||||
uint16_t const RPC_DEFAULT_PORT = 28081;
|
uint16_t const RPC_DEFAULT_PORT = 28081;
|
||||||
|
uint16_t const ZMQ_RPC_DEFAULT_PORT = 28082;
|
||||||
boost::uuids::uuid const NETWORK_ID = { {
|
boost::uuids::uuid const NETWORK_ID = { {
|
||||||
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x11
|
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x11
|
||||||
} }; // Bender's daydream
|
} }; // Bender's daydream
|
||||||
|
|
|
@ -751,7 +751,7 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||||
m_timestamps = timestamps;
|
m_timestamps = timestamps;
|
||||||
m_difficulties = difficulties;
|
m_difficulties = difficulties;
|
||||||
}
|
}
|
||||||
size_t target = get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
|
size_t target = get_difficulty_target();
|
||||||
return next_difficulty(timestamps, difficulties, target);
|
return next_difficulty(timestamps, difficulties, target);
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
@ -1571,6 +1571,98 @@ void Blockchain::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_A
|
||||||
output_data_t data = m_db->get_output_key(amount, i);
|
output_data_t data = m_db->get_output_key(amount, i);
|
||||||
oen.out_key = data.pubkey;
|
oen.out_key = data.pubkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Blockchain::get_num_mature_outputs(uint64_t amount) const
|
||||||
|
{
|
||||||
|
uint64_t num_outs = m_db->get_num_outputs(amount);
|
||||||
|
// ensure we don't include outputs that aren't yet eligible to be used
|
||||||
|
// outpouts are sorted by height
|
||||||
|
while (num_outs > 0)
|
||||||
|
{
|
||||||
|
const tx_out_index toi = m_db->get_output_tx_and_index(amount, num_outs - 1);
|
||||||
|
const uint64_t height = m_db->get_tx_block_height(toi.first);
|
||||||
|
if (height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_db->height())
|
||||||
|
break;
|
||||||
|
--num_outs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_outs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint64_t> Blockchain::get_random_outputs(uint64_t amount, uint64_t count) const
|
||||||
|
{
|
||||||
|
uint64_t num_outs = get_num_mature_outputs(amount);
|
||||||
|
|
||||||
|
std::vector<uint64_t> indices;
|
||||||
|
|
||||||
|
std::unordered_set<uint64_t> seen_indices;
|
||||||
|
|
||||||
|
// if there aren't enough outputs to mix with (or just enough),
|
||||||
|
// use all of them. Eventually this should become impossible.
|
||||||
|
if (num_outs <= count)
|
||||||
|
{
|
||||||
|
for (uint64_t i = 0; i < num_outs; i++)
|
||||||
|
{
|
||||||
|
// get tx_hash, tx_out_index from DB
|
||||||
|
tx_out_index toi = m_db->get_output_tx_and_index(amount, i);
|
||||||
|
|
||||||
|
// if tx is unlocked, add output to indices
|
||||||
|
if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)))
|
||||||
|
{
|
||||||
|
indices.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// while we still need more mixins
|
||||||
|
while (indices.size() < count)
|
||||||
|
{
|
||||||
|
// if we've gone through every possible output, we've gotten all we can
|
||||||
|
if (seen_indices.size() == num_outs)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a random output index from the DB. If we've already seen it,
|
||||||
|
// return to the top of the loop and try again, otherwise add it to the
|
||||||
|
// list of output indices we've seen.
|
||||||
|
|
||||||
|
// triangular distribution over [a,b) with a=0, mode c=b=up_index_limit
|
||||||
|
uint64_t r = crypto::rand<uint64_t>() % ((uint64_t)1 << 53);
|
||||||
|
double frac = std::sqrt((double)r / ((uint64_t)1 << 53));
|
||||||
|
uint64_t i = (uint64_t)(frac*num_outs);
|
||||||
|
// just in case rounding up to 1 occurs after sqrt
|
||||||
|
if (i == num_outs)
|
||||||
|
--i;
|
||||||
|
|
||||||
|
if (seen_indices.count(i))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seen_indices.emplace(i);
|
||||||
|
|
||||||
|
// get tx_hash, tx_out_index from DB
|
||||||
|
tx_out_index toi = m_db->get_output_tx_and_index(amount, i);
|
||||||
|
|
||||||
|
// if the output's transaction is unlocked, add the output's index to
|
||||||
|
// our list.
|
||||||
|
if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)))
|
||||||
|
{
|
||||||
|
indices.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto::public_key Blockchain::get_output_key(uint64_t amount, uint64_t global_index) const
|
||||||
|
{
|
||||||
|
output_data_t data = m_db->get_output_key(amount, global_index);
|
||||||
|
return data.pubkey;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
// This function takes an RPC request for mixins and creates an RPC response
|
// This function takes an RPC request for mixins and creates an RPC response
|
||||||
// with the requested mixins.
|
// with the requested mixins.
|
||||||
|
@ -1585,80 +1677,18 @@ bool Blockchain::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUT
|
||||||
// from BlockchainDB where <n> is req.outs_count (number of mixins).
|
// from BlockchainDB where <n> is req.outs_count (number of mixins).
|
||||||
for (uint64_t amount : req.amounts)
|
for (uint64_t amount : req.amounts)
|
||||||
{
|
{
|
||||||
auto num_outs = m_db->get_num_outputs(amount);
|
|
||||||
// ensure we don't include outputs that aren't yet eligible to be used
|
|
||||||
// outpouts are sorted by height
|
|
||||||
while (num_outs > 0)
|
|
||||||
{
|
|
||||||
const tx_out_index toi = m_db->get_output_tx_and_index(amount, num_outs - 1);
|
|
||||||
const uint64_t height = m_db->get_tx_block_height(toi.first);
|
|
||||||
if (height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_db->height())
|
|
||||||
break;
|
|
||||||
--num_outs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create outs_for_amount struct and populate amount field
|
// create outs_for_amount struct and populate amount field
|
||||||
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount());
|
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount());
|
||||||
result_outs.amount = amount;
|
result_outs.amount = amount;
|
||||||
|
|
||||||
std::unordered_set<uint64_t> seen_indices;
|
std::vector<uint64_t> indices = get_random_outputs(amount, req.outs_count);
|
||||||
|
|
||||||
// if there aren't enough outputs to mix with (or just enough),
|
for (auto i : indices)
|
||||||
// use all of them. Eventually this should become impossible.
|
|
||||||
if (num_outs <= req.outs_count)
|
|
||||||
{
|
{
|
||||||
for (uint64_t i = 0; i < num_outs; i++)
|
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oe = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry());
|
||||||
{
|
|
||||||
// get tx_hash, tx_out_index from DB
|
|
||||||
tx_out_index toi = m_db->get_output_tx_and_index(amount, i);
|
|
||||||
|
|
||||||
// if tx is unlocked, add output to result_outs
|
oe.global_amount_index = i;
|
||||||
if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)))
|
oe.out_key = get_output_key(amount, i);
|
||||||
{
|
|
||||||
add_out_to_get_random_outs(result_outs, amount, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// while we still need more mixins
|
|
||||||
while (result_outs.outs.size() < req.outs_count)
|
|
||||||
{
|
|
||||||
// if we've gone through every possible output, we've gotten all we can
|
|
||||||
if (seen_indices.size() == num_outs)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a random output index from the DB. If we've already seen it,
|
|
||||||
// return to the top of the loop and try again, otherwise add it to the
|
|
||||||
// list of output indices we've seen.
|
|
||||||
|
|
||||||
// triangular distribution over [a,b) with a=0, mode c=b=up_index_limit
|
|
||||||
uint64_t r = crypto::rand<uint64_t>() % ((uint64_t)1 << 53);
|
|
||||||
double frac = std::sqrt((double)r / ((uint64_t)1 << 53));
|
|
||||||
uint64_t i = (uint64_t)(frac*num_outs);
|
|
||||||
// just in case rounding up to 1 occurs after sqrt
|
|
||||||
if (i == num_outs)
|
|
||||||
--i;
|
|
||||||
|
|
||||||
if (seen_indices.count(i))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
seen_indices.emplace(i);
|
|
||||||
|
|
||||||
// get tx_hash, tx_out_index from DB
|
|
||||||
tx_out_index toi = m_db->get_output_tx_and_index(amount, i);
|
|
||||||
|
|
||||||
// if the output's transaction is unlocked, add the output's index to
|
|
||||||
// our list.
|
|
||||||
if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)))
|
|
||||||
{
|
|
||||||
add_out_to_get_random_outs(result_outs, amount, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1816,6 +1846,15 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint64_t& index, crypto::public_key& key, rct::key& mask, bool& unlocked) const
|
||||||
|
{
|
||||||
|
const auto o_data = m_db->get_output_key(amount, index);
|
||||||
|
key = o_data.pubkey;
|
||||||
|
mask = o_data.commitment;
|
||||||
|
tx_out_index toi = m_db->get_output_tx_and_index(amount, index);
|
||||||
|
unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------
|
||||||
// This function takes a list of block hashes from another node
|
// This function takes a list of block hashes from another node
|
||||||
// on the network to find where the split point is between us and them.
|
// on the network to find where the split point is between us and them.
|
||||||
// This is used to see what to send another node that needs to sync.
|
// This is used to see what to send another node that needs to sync.
|
||||||
|
@ -2025,28 +2064,39 @@ void Blockchain::print_blockchain_outs(const std::string& file) const
|
||||||
// Find the split point between us and foreign blockchain and return
|
// Find the split point between us and foreign blockchain and return
|
||||||
// (by reference) the most recent common block hash along with up to
|
// (by reference) the most recent common block hash along with up to
|
||||||
// BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes.
|
// BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes.
|
||||||
bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const
|
bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height) const
|
||||||
{
|
{
|
||||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||||
|
|
||||||
// if we can't find the split point, return false
|
// if we can't find the split point, return false
|
||||||
if(!find_blockchain_supplement(qblock_ids, resp.start_height))
|
if(!find_blockchain_supplement(qblock_ids, start_height))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_db->block_txn_start(true);
|
m_db->block_txn_start(true);
|
||||||
resp.total_height = get_current_blockchain_height();
|
current_height = get_current_blockchain_height();
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for(size_t i = resp.start_height; i < resp.total_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++)
|
for(size_t i = start_height; i < current_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++)
|
||||||
{
|
{
|
||||||
resp.m_block_ids.push_back(m_db->get_block_hash_from_height(i));
|
hashes.push_back(m_db->get_block_hash_from_height(i));
|
||||||
}
|
}
|
||||||
resp.cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->height() - 1);
|
|
||||||
m_db->block_txn_stop();
|
m_db->block_txn_stop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const
|
||||||
|
{
|
||||||
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||||
|
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||||
|
|
||||||
|
bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height);
|
||||||
|
resp.cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->height() - 1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
//FIXME: change argument to std::vector, low priority
|
//FIXME: change argument to std::vector, low priority
|
||||||
// find split point between ours and foreign blockchain (or start at
|
// find split point between ours and foreign blockchain (or start at
|
||||||
|
@ -4086,6 +4136,11 @@ bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, ui
|
||||||
return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting);
|
return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Blockchain::get_difficulty_target() const
|
||||||
|
{
|
||||||
|
return get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const
|
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const
|
||||||
{
|
{
|
||||||
return m_db->get_output_histogram(amounts, unlocked, recent_cutoff);
|
return m_db->get_output_histogram(amounts, unlocked, recent_cutoff);
|
||||||
|
|
|
@ -366,6 +366,22 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool get_short_chain_history(std::list<crypto::hash>& ids) const;
|
bool get_short_chain_history(std::list<crypto::hash>& ids) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get recent block hashes for a foreign chain
|
||||||
|
*
|
||||||
|
* Find the split point between us and foreign blockchain and return
|
||||||
|
* (by reference) the most recent common block hash along with up to
|
||||||
|
* BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes.
|
||||||
|
*
|
||||||
|
* @param qblock_ids the foreign chain's "short history" (see get_short_chain_history)
|
||||||
|
* @param hashes the hashes to be returned, return-by-reference
|
||||||
|
* @param start_height the start height, return-by-reference
|
||||||
|
* @param current_height the current blockchain height, return-by-reference
|
||||||
|
*
|
||||||
|
* @return true if a block found in common, else false
|
||||||
|
*/
|
||||||
|
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get recent block hashes for a foreign chain
|
* @brief get recent block hashes for a foreign chain
|
||||||
*
|
*
|
||||||
|
@ -426,6 +442,35 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp);
|
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get number of outputs of an amount past the minimum spendable age
|
||||||
|
*
|
||||||
|
* @param amount the output amount
|
||||||
|
*
|
||||||
|
* @return the number of mature outputs
|
||||||
|
*/
|
||||||
|
uint64_t get_num_mature_outputs(uint64_t amount) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get random outputs (indices) for an amount
|
||||||
|
*
|
||||||
|
* @param amount the amount
|
||||||
|
* @param count the number of random outputs to choose
|
||||||
|
*
|
||||||
|
* @return the outputs' amount-global indices
|
||||||
|
*/
|
||||||
|
std::vector<uint64_t> get_random_outputs(uint64_t amount, uint64_t count) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the public key for an output
|
||||||
|
*
|
||||||
|
* @param amount the output amount
|
||||||
|
* @param global_index the output amount-global index
|
||||||
|
*
|
||||||
|
* @return the public key
|
||||||
|
*/
|
||||||
|
crypto::public_key get_output_key(uint64_t amount, uint64_t global_index) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief gets random outputs to mix with
|
* @brief gets random outputs to mix with
|
||||||
*
|
*
|
||||||
|
@ -457,6 +502,17 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res) const;
|
bool get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief gets an output's key and unlocked state
|
||||||
|
*
|
||||||
|
* @param amount in - the output amount
|
||||||
|
* @param index in - the output global amount index
|
||||||
|
* @param mask out - the output's RingCT mask
|
||||||
|
* @param key out - the output's key
|
||||||
|
* @param unlocked out - the output's unlocked state
|
||||||
|
*/
|
||||||
|
void get_output_key_mask_unlocked(const uint64_t& amount, const uint64_t& index, crypto::public_key& key, rct::key& mask, bool& unlocked) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief gets random ringct outputs to mix with
|
* @brief gets random ringct outputs to mix with
|
||||||
*
|
*
|
||||||
|
@ -774,6 +830,13 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const;
|
bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get difficulty target based on chain and hardfork version
|
||||||
|
*
|
||||||
|
* @return difficulty target
|
||||||
|
*/
|
||||||
|
uint64_t get_difficulty_target() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief remove transactions from the transaction pool (if present)
|
* @brief remove transactions from the transaction pool (if present)
|
||||||
*
|
*
|
||||||
|
|
|
@ -810,6 +810,13 @@ namespace cryptonote
|
||||||
return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4;
|
return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
bool core::are_key_images_spent_in_pool(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const
|
||||||
|
{
|
||||||
|
spent.clear();
|
||||||
|
|
||||||
|
return m_mempool.check_for_key_images(key_im, spent);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
std::pair<uint64_t, uint64_t> core::get_coinbase_tx_sum(const uint64_t start_offset, const size_t count)
|
std::pair<uint64_t, uint64_t> core::get_coinbase_tx_sum(const uint64_t start_offset, const size_t count)
|
||||||
{
|
{
|
||||||
uint64_t emission_amount = 0;
|
uint64_t emission_amount = 0;
|
||||||
|
@ -1200,6 +1207,11 @@ namespace cryptonote
|
||||||
return m_mempool.get_transactions_and_spent_keys_info(tx_infos, key_image_infos);
|
return m_mempool.get_transactions_and_spent_keys_info(tx_infos, key_image_infos);
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
bool core::get_pool_for_rpc(std::vector<cryptonote::rpc::tx_in_pool>& tx_infos, cryptonote::rpc::key_images_with_tx_hashes& key_image_infos) const
|
||||||
|
{
|
||||||
|
return m_mempool.get_pool_for_rpc(tx_infos, key_image_infos);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
bool core::get_short_chain_history(std::list<crypto::hash>& ids) const
|
bool core::get_short_chain_history(std::list<crypto::hash>& ids) const
|
||||||
{
|
{
|
||||||
return m_blockchain_storage.get_short_chain_history(ids);
|
return m_blockchain_storage.get_short_chain_history(ids);
|
||||||
|
|
|
@ -462,6 +462,13 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const;
|
bool get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copydoc tx_memory_pool::get_pool_for_rpc
|
||||||
|
*
|
||||||
|
* @note see tx_memory_pool::get_pool_for_rpc
|
||||||
|
*/
|
||||||
|
bool get_pool_for_rpc(std::vector<cryptonote::rpc::tx_in_pool>& tx_infos, cryptonote::rpc::key_images_with_tx_hashes& key_image_infos) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @copydoc tx_memory_pool::get_transactions_count
|
* @copydoc tx_memory_pool::get_transactions_count
|
||||||
*
|
*
|
||||||
|
@ -707,6 +714,16 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool are_key_images_spent(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const;
|
bool are_key_images_spent(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief check if multiple key images are spent in the transaction pool
|
||||||
|
*
|
||||||
|
* @param key_im list of key images to check
|
||||||
|
* @param spent return-by-reference result for each image checked
|
||||||
|
*
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
bool are_key_images_spent_in_pool(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get the number of blocks to sync in one go
|
* @brief get the number of blocks to sync in one go
|
||||||
*
|
*
|
||||||
|
|
|
@ -684,6 +684,65 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
|
bool tx_memory_pool::get_pool_for_rpc(std::vector<cryptonote::rpc::tx_in_pool>& tx_infos, cryptonote::rpc::key_images_with_tx_hashes& key_image_infos) const
|
||||||
|
{
|
||||||
|
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||||
|
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||||
|
m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
|
||||||
|
cryptonote::rpc::tx_in_pool txi;
|
||||||
|
txi.tx_hash = txid;
|
||||||
|
transaction tx;
|
||||||
|
if (!parse_and_validate_tx_from_blob(*bd, tx))
|
||||||
|
{
|
||||||
|
MERROR("Failed to parse tx from txpool");
|
||||||
|
// continue
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
txi.tx = tx;
|
||||||
|
txi.blob_size = meta.blob_size;
|
||||||
|
txi.fee = meta.fee;
|
||||||
|
txi.kept_by_block = meta.kept_by_block;
|
||||||
|
txi.max_used_block_height = meta.max_used_block_height;
|
||||||
|
txi.max_used_block_hash = meta.max_used_block_id;
|
||||||
|
txi.last_failed_block_height = meta.last_failed_height;
|
||||||
|
txi.last_failed_block_hash = meta.last_failed_id;
|
||||||
|
txi.receive_time = meta.receive_time;
|
||||||
|
txi.relayed = meta.relayed;
|
||||||
|
txi.last_relayed_time = meta.last_relayed_time;
|
||||||
|
txi.do_not_relay = meta.do_not_relay;
|
||||||
|
tx_infos.push_back(txi);
|
||||||
|
return true;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
for (const key_images_container::value_type& kee : m_spent_key_images) {
|
||||||
|
std::vector<crypto::hash> tx_hashes;
|
||||||
|
const std::unordered_set<crypto::hash>& kei_image_set = kee.second;
|
||||||
|
for (const crypto::hash& tx_id_hash : kei_image_set)
|
||||||
|
{
|
||||||
|
tx_hashes.push_back(tx_id_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const crypto::key_image& k_image = kee.first;
|
||||||
|
key_image_infos[k_image] = tx_hashes;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
bool tx_memory_pool::check_for_key_images(const std::vector<crypto::key_image>& key_images, std::vector<bool> spent) const
|
||||||
|
{
|
||||||
|
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||||
|
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||||
|
|
||||||
|
spent.clear();
|
||||||
|
|
||||||
|
for (const auto& image : key_images)
|
||||||
|
{
|
||||||
|
spent.push_back(m_spent_key_images.find(image) == m_spent_key_images.end() ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
bool tx_memory_pool::get_transaction(const crypto::hash& id, cryptonote::blobdata& txblob) const
|
bool tx_memory_pool::get_transaction(const crypto::hash& id, cryptonote::blobdata& txblob) const
|
||||||
{
|
{
|
||||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "blockchain_db/blockchain_db.h"
|
#include "blockchain_db/blockchain_db.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
#include "rpc/core_rpc_server_commands_defs.h"
|
#include "rpc/core_rpc_server_commands_defs.h"
|
||||||
|
#include "rpc/message_data_structs.h"
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
|
@ -268,6 +269,28 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool get_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const;
|
bool get_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get information about all transactions and key images in the pool
|
||||||
|
*
|
||||||
|
* see documentation on tx_in_pool and key_images_with_tx_hashes for more details
|
||||||
|
*
|
||||||
|
* @param tx_infos [out] the transactions' information
|
||||||
|
* @param key_image_infos [out] the spent key images' information
|
||||||
|
*
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
bool get_pool_for_rpc(std::vector<cryptonote::rpc::tx_in_pool>& tx_infos, cryptonote::rpc::key_images_with_tx_hashes& key_image_infos) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief check for presence of key images in the pool
|
||||||
|
*
|
||||||
|
* @param key_images [in] vector of key images to check
|
||||||
|
* @param spent [out] vector of bool to return
|
||||||
|
*
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
bool check_for_key_images(const std::vector<crypto::key_image>& key_images, std::vector<bool> spent) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get a specific transaction from the pool
|
* @brief get a specific transaction from the pool
|
||||||
*
|
*
|
||||||
|
|
|
@ -92,12 +92,15 @@ target_link_libraries(daemon
|
||||||
p2p
|
p2p
|
||||||
cryptonote_protocol
|
cryptonote_protocol
|
||||||
daemonizer
|
daemonizer
|
||||||
|
serialization
|
||||||
|
daemon_rpc_server
|
||||||
${Boost_CHRONO_LIBRARY}
|
${Boost_CHRONO_LIBRARY}
|
||||||
${Boost_FILESYSTEM_LIBRARY}
|
${Boost_FILESYSTEM_LIBRARY}
|
||||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||||
${Boost_REGEX_LIBRARY}
|
${Boost_REGEX_LIBRARY}
|
||||||
${Boost_SYSTEM_LIBRARY}
|
${Boost_SYSTEM_LIBRARY}
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
|
${ZMQ_LIB}
|
||||||
${EXTRA_LIBRARIES})
|
${EXTRA_LIBRARIES})
|
||||||
add_dependencies(daemon version)
|
add_dependencies(daemon version)
|
||||||
set_property(TARGET daemon
|
set_property(TARGET daemon
|
||||||
|
|
|
@ -64,6 +64,25 @@ namespace daemon_args
|
||||||
, "Max number of threads to use for a parallel job"
|
, "Max number of threads to use for a parallel job"
|
||||||
, 0
|
, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const command_line::arg_descriptor<std::string> arg_zmq_rpc_bind_ip = {
|
||||||
|
"zmq-rpc-bind-ip"
|
||||||
|
, "IP for ZMQ RPC server to listen on"
|
||||||
|
, "127.0.0.1"
|
||||||
|
};
|
||||||
|
|
||||||
|
const command_line::arg_descriptor<std::string> arg_zmq_rpc_bind_port = {
|
||||||
|
"zmq-rpc-bind-port"
|
||||||
|
, "Port for ZMQ RPC server to listen on"
|
||||||
|
, std::to_string(config::ZMQ_RPC_DEFAULT_PORT)
|
||||||
|
};
|
||||||
|
|
||||||
|
const command_line::arg_descriptor<std::string> arg_zmq_testnet_rpc_bind_port = {
|
||||||
|
"zmq-testnet-rpc-bind-port"
|
||||||
|
, "Port for testnet ZMQ RPC server to listen on"
|
||||||
|
, std::to_string(config::testnet::ZMQ_RPC_DEFAULT_PORT)
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace daemon_args
|
} // namespace daemon_args
|
||||||
|
|
||||||
#endif // DAEMON_COMMAND_LINE_ARGS_H
|
#endif // DAEMON_COMMAND_LINE_ARGS_H
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include "misc_log_ex.h"
|
#include "misc_log_ex.h"
|
||||||
#include "daemon/daemon.h"
|
#include "daemon/daemon.h"
|
||||||
|
#include "rpc/daemon_handler.h"
|
||||||
|
#include "rpc/zmq_server.h"
|
||||||
|
|
||||||
#include "common/password.h"
|
#include "common/password.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
@ -85,7 +87,18 @@ t_daemon::t_daemon(
|
||||||
boost::program_options::variables_map const & vm
|
boost::program_options::variables_map const & vm
|
||||||
)
|
)
|
||||||
: mp_internals{new t_internals{vm}}
|
: mp_internals{new t_internals{vm}}
|
||||||
{}
|
{
|
||||||
|
bool testnet = command_line::get_arg(vm, command_line::arg_testnet_on);
|
||||||
|
if (testnet)
|
||||||
|
{
|
||||||
|
zmq_rpc_bind_port = command_line::get_arg(vm, daemon_args::arg_zmq_testnet_rpc_bind_port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zmq_rpc_bind_port = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_port);
|
||||||
|
}
|
||||||
|
zmq_rpc_bind_address = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_ip);
|
||||||
|
}
|
||||||
|
|
||||||
t_daemon::~t_daemon() = default;
|
t_daemon::~t_daemon() = default;
|
||||||
|
|
||||||
|
@ -133,6 +146,30 @@ bool t_daemon::run(bool interactive)
|
||||||
rpc_commands->start_handling(std::bind(&daemonize::t_daemon::stop_p2p, this));
|
rpc_commands->start_handling(std::bind(&daemonize::t_daemon::stop_p2p, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cryptonote::rpc::DaemonHandler rpc_daemon_handler(mp_internals->core.get(), mp_internals->p2p.get());
|
||||||
|
cryptonote::rpc::ZmqServer zmq_server(rpc_daemon_handler);
|
||||||
|
|
||||||
|
if (!zmq_server.addTCPSocket(zmq_rpc_bind_address, zmq_rpc_bind_port))
|
||||||
|
{
|
||||||
|
LOG_ERROR(std::string("Failed to add TCP Socket (") + zmq_rpc_bind_address
|
||||||
|
+ ":" + zmq_rpc_bind_port + ") to ZMQ RPC Server");
|
||||||
|
|
||||||
|
if (interactive)
|
||||||
|
{
|
||||||
|
rpc_commands->stop_handling();
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_internals->rpc.stop();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MINFO("Starting ZMQ server...");
|
||||||
|
zmq_server.run();
|
||||||
|
|
||||||
|
MINFO(std::string("ZMQ server started at ") + zmq_rpc_bind_address
|
||||||
|
+ ":" + zmq_rpc_bind_port + ".");
|
||||||
|
|
||||||
mp_internals->p2p.run(); // blocks until p2p goes down
|
mp_internals->p2p.run(); // blocks until p2p goes down
|
||||||
|
|
||||||
if (rpc_commands)
|
if (rpc_commands)
|
||||||
|
@ -140,6 +177,8 @@ bool t_daemon::run(bool interactive)
|
||||||
rpc_commands->stop_handling();
|
rpc_commands->stop_handling();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zmq_server.stop();
|
||||||
|
|
||||||
mp_internals->rpc.stop();
|
mp_internals->rpc.stop();
|
||||||
mp_internals->core.get().get_miner().stop();
|
mp_internals->core.get().get_miner().stop();
|
||||||
MGINFO("Node stopped.");
|
MGINFO("Node stopped.");
|
||||||
|
|
|
@ -43,6 +43,8 @@ private:
|
||||||
void stop_p2p();
|
void stop_p2p();
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<t_internals> mp_internals;
|
std::unique_ptr<t_internals> mp_internals;
|
||||||
|
std::string zmq_rpc_bind_address;
|
||||||
|
std::string zmq_rpc_bind_port;
|
||||||
public:
|
public:
|
||||||
t_daemon(
|
t_daemon(
|
||||||
boost::program_options::variables_map const & vm
|
boost::program_options::variables_map const & vm
|
||||||
|
|
|
@ -89,6 +89,9 @@ int main(int argc, char const * argv[])
|
||||||
command_line::add_arg(core_settings, daemon_args::arg_log_file, default_log.string());
|
command_line::add_arg(core_settings, daemon_args::arg_log_file, default_log.string());
|
||||||
command_line::add_arg(core_settings, daemon_args::arg_log_level);
|
command_line::add_arg(core_settings, daemon_args::arg_log_level);
|
||||||
command_line::add_arg(core_settings, daemon_args::arg_max_concurrency);
|
command_line::add_arg(core_settings, daemon_args::arg_max_concurrency);
|
||||||
|
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_ip);
|
||||||
|
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_port);
|
||||||
|
command_line::add_arg(core_settings, daemon_args::arg_zmq_testnet_rpc_bind_port);
|
||||||
|
|
||||||
daemonizer::init_options(hidden_options, visible_options);
|
daemonizer::init_options(hidden_options, visible_options);
|
||||||
daemonize::t_executor::init_options(core_settings);
|
daemonize::t_executor::init_options(core_settings);
|
||||||
|
|
|
@ -30,20 +30,61 @@ set(rpc_sources
|
||||||
core_rpc_server.cpp
|
core_rpc_server.cpp
|
||||||
rpc_args.cpp)
|
rpc_args.cpp)
|
||||||
|
|
||||||
|
set(daemon_messages_sources
|
||||||
|
message.cpp
|
||||||
|
daemon_messages.cpp)
|
||||||
|
|
||||||
|
set(daemon_rpc_server_sources
|
||||||
|
daemon_handler.cpp
|
||||||
|
zmq_server.cpp)
|
||||||
|
|
||||||
|
|
||||||
set(rpc_headers
|
set(rpc_headers
|
||||||
rpc_args.h)
|
rpc_args.h)
|
||||||
|
|
||||||
set(rpc_private_headers
|
set(daemon_rpc_server_headers)
|
||||||
|
|
||||||
|
|
||||||
|
set(rpc_daemon_private_headers
|
||||||
core_rpc_server.h
|
core_rpc_server.h
|
||||||
core_rpc_server_commands_defs.h
|
core_rpc_server_commands_defs.h
|
||||||
core_rpc_server_error_codes.h)
|
core_rpc_server_error_codes.h)
|
||||||
|
|
||||||
|
set(daemon_messages_private_headers
|
||||||
|
message.h
|
||||||
|
daemon_messages.h)
|
||||||
|
|
||||||
|
set(daemon_rpc_server_private_headers
|
||||||
|
message.h
|
||||||
|
daemon_messages.h
|
||||||
|
daemon_handler.h
|
||||||
|
rpc_handler.h
|
||||||
|
zmq_server.h)
|
||||||
|
|
||||||
|
|
||||||
monero_private_headers(rpc
|
monero_private_headers(rpc
|
||||||
${rpc_private_headers})
|
${rpc_private_headers})
|
||||||
|
|
||||||
|
monero_private_headers(daemon_rpc_server
|
||||||
|
${daemon_rpc_server_private_headers})
|
||||||
|
|
||||||
|
|
||||||
monero_add_library(rpc
|
monero_add_library(rpc
|
||||||
${rpc_sources}
|
${rpc_sources}
|
||||||
${rpc_headers}
|
${rpc_headers}
|
||||||
${rpc_private_headers})
|
${rpc_private_headers})
|
||||||
|
|
||||||
|
monero_add_library(daemon_messages
|
||||||
|
${daemon_messages_sources}
|
||||||
|
${daemon_messages_headers}
|
||||||
|
${daemon_messages_private_headers})
|
||||||
|
|
||||||
|
monero_add_library(daemon_rpc_server
|
||||||
|
${daemon_rpc_server_sources}
|
||||||
|
${daemon_rpc_server_headers}
|
||||||
|
${daemon_rpc_server_private_headers})
|
||||||
|
|
||||||
|
|
||||||
target_link_libraries(rpc
|
target_link_libraries(rpc
|
||||||
PUBLIC
|
PUBLIC
|
||||||
common
|
common
|
||||||
|
@ -54,5 +95,32 @@ target_link_libraries(rpc
|
||||||
${Boost_THREAD_LIBRARY}
|
${Boost_THREAD_LIBRARY}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${EXTRA_LIBRARIES})
|
${EXTRA_LIBRARIES})
|
||||||
|
|
||||||
|
target_link_libraries(daemon_messages
|
||||||
|
LINK_PRIVATE
|
||||||
|
cryptonote_core
|
||||||
|
cryptonote_protocol
|
||||||
|
serialization
|
||||||
|
${EXTRA_LIBRARIES})
|
||||||
|
|
||||||
|
target_link_libraries(daemon_rpc_server
|
||||||
|
LINK_PRIVATE
|
||||||
|
cryptonote_core
|
||||||
|
cryptonote_protocol
|
||||||
|
daemon_messages
|
||||||
|
serialization
|
||||||
|
${Boost_CHRONO_LIBRARY}
|
||||||
|
${Boost_REGEX_LIBRARY}
|
||||||
|
${Boost_SYSTEM_LIBRARY}
|
||||||
|
${Boost_THREAD_LIBRARY}
|
||||||
|
${ZMQ_LIB}
|
||||||
|
${EXTRA_LIBRARIES})
|
||||||
|
target_include_directories(daemon_rpc_server PUBLIC ${ZMQ_INCLUDE_PATH})
|
||||||
|
target_include_directories(obj_daemon_rpc_server PUBLIC ${ZMQ_INCLUDE_PATH})
|
||||||
|
|
||||||
|
|
||||||
add_dependencies(rpc
|
add_dependencies(rpc
|
||||||
version)
|
version)
|
||||||
|
|
||||||
|
add_dependencies(daemon_rpc_server
|
||||||
|
version)
|
||||||
|
|
|
@ -137,7 +137,7 @@ namespace cryptonote
|
||||||
res.top_block_hash = string_tools::pod_to_hex(top_hash);
|
res.top_block_hash = string_tools::pod_to_hex(top_hash);
|
||||||
res.target_height = m_core.get_target_blockchain_height();
|
res.target_height = m_core.get_target_blockchain_height();
|
||||||
res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block();
|
res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block();
|
||||||
res.target = m_core.get_blockchain_storage().get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
|
res.target = m_core.get_blockchain_storage().get_difficulty_target();
|
||||||
res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase
|
res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase
|
||||||
res.tx_pool_size = m_core.get_pool_transactions_count();
|
res.tx_pool_size = m_core.get_pool_transactions_count();
|
||||||
res.alt_blocks_count = m_core.get_blockchain_storage().get_alternative_blocks_count();
|
res.alt_blocks_count = m_core.get_blockchain_storage().get_alternative_blocks_count();
|
||||||
|
|
|
@ -0,0 +1,887 @@
|
||||||
|
// Copyright (c) 2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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 "daemon_handler.h"
|
||||||
|
|
||||||
|
// likely included by daemon_handler.h's includes,
|
||||||
|
// but including here for clarity
|
||||||
|
#include "cryptonote_core/cryptonote_core.h"
|
||||||
|
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||||
|
#include "cryptonote_protocol/blobdatatype.h"
|
||||||
|
#include "ringct/rctSigs.h"
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetHeight::Request& req, GetHeight::Response& res)
|
||||||
|
{
|
||||||
|
res.height = m_core.get_current_blockchain_height();
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBlocksFast::Request& req, GetBlocksFast::Response& res)
|
||||||
|
{
|
||||||
|
std::list<std::pair<blobdata, std::list<blobdata> > > blocks;
|
||||||
|
|
||||||
|
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, blocks, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "core::find_blockchain_supplement() returned false";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.blocks.resize(blocks.size());
|
||||||
|
res.output_indices.resize(blocks.size());
|
||||||
|
|
||||||
|
//TODO: really need to switch uses of std::list to std::vector unless
|
||||||
|
// it's a huge performance concern
|
||||||
|
|
||||||
|
auto it = blocks.begin();
|
||||||
|
|
||||||
|
uint64_t block_count = 0;
|
||||||
|
while (it != blocks.end())
|
||||||
|
{
|
||||||
|
cryptonote::rpc::block_with_transactions& bwt = res.blocks[block_count];
|
||||||
|
|
||||||
|
if (!parse_and_validate_block_from_blob(it->first, bwt.block))
|
||||||
|
{
|
||||||
|
res.blocks.clear();
|
||||||
|
res.output_indices.clear();
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "failed retrieving a requested block";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it->second.size() != bwt.block.tx_hashes.size())
|
||||||
|
{
|
||||||
|
res.blocks.clear();
|
||||||
|
res.output_indices.clear();
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "incorrect number of transactions retrieved for block";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::list<transaction> txs;
|
||||||
|
for (const auto& blob : it->second)
|
||||||
|
{
|
||||||
|
txs.resize(txs.size() + 1);
|
||||||
|
if (!parse_and_validate_tx_from_blob(blob, txs.back()))
|
||||||
|
{
|
||||||
|
res.blocks.clear();
|
||||||
|
res.output_indices.clear();
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "failed retrieving a requested transaction";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptonote::rpc::block_output_indices& indices = res.output_indices[block_count];
|
||||||
|
|
||||||
|
// miner tx output indices
|
||||||
|
{
|
||||||
|
cryptonote::rpc::tx_output_indices tx_indices;
|
||||||
|
bool r = m_core.get_tx_outputs_gindexs(get_transaction_hash(bwt.block.miner_tx), tx_indices);
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "core::get_tx_outputs_gindexs() returned false";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
indices.push_back(tx_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume each block returned is returned with all its transactions
|
||||||
|
// in the correct order.
|
||||||
|
auto tx_it = txs.begin();
|
||||||
|
for (const crypto::hash& h : bwt.block.tx_hashes)
|
||||||
|
{
|
||||||
|
bwt.transactions.emplace(h, *tx_it);
|
||||||
|
tx_it++;
|
||||||
|
|
||||||
|
cryptonote::rpc::tx_output_indices tx_indices;
|
||||||
|
bool r = m_core.get_tx_outputs_gindexs(h, tx_indices);
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "core::get_tx_outputs_gindexs() returned false";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
indices.push_back(tx_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
it++;
|
||||||
|
block_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetHashesFast::Request& req, GetHashesFast::Response& res)
|
||||||
|
{
|
||||||
|
res.start_height = req.start_height;
|
||||||
|
|
||||||
|
auto& chain = m_core.get_blockchain_storage();
|
||||||
|
|
||||||
|
if (!chain.find_blockchain_supplement(req.known_hashes, res.hashes, res.start_height, res.current_height))
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "Blockchain::find_blockchain_supplement() returned false";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetTransactions::Request& req, GetTransactions::Response& res)
|
||||||
|
{
|
||||||
|
std::list<cryptonote::transaction> found_txs;
|
||||||
|
std::list<crypto::hash> missed_hashes;
|
||||||
|
|
||||||
|
bool r = m_core.get_transactions(req.tx_hashes, found_txs, missed_hashes);
|
||||||
|
|
||||||
|
// TODO: consider fixing core::get_transactions to not hide exceptions
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "core::get_transactions() returned false (exception caught there)";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t num_found = found_txs.size();
|
||||||
|
|
||||||
|
// std::list is annoying
|
||||||
|
std::vector<cryptonote::transaction> found_txs_vec
|
||||||
|
{
|
||||||
|
std::make_move_iterator(std::begin(found_txs)),
|
||||||
|
std::make_move_iterator(std::end(found_txs))
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<crypto::hash> missed_vec
|
||||||
|
{
|
||||||
|
std::make_move_iterator(std::begin(missed_hashes)),
|
||||||
|
std::make_move_iterator(std::end(missed_hashes))
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<uint64_t> heights(num_found);
|
||||||
|
std::vector<bool> in_pool(num_found, false);
|
||||||
|
std::vector<crypto::hash> found_hashes(num_found);
|
||||||
|
|
||||||
|
for (size_t i=0; i < num_found; i++)
|
||||||
|
{
|
||||||
|
found_hashes[i] = get_transaction_hash(found_txs_vec[i]);
|
||||||
|
heights[i] = m_core.get_blockchain_storage().get_db().get_tx_block_height(found_hashes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if any missing from blockchain, check in tx pool
|
||||||
|
if (!missed_vec.empty())
|
||||||
|
{
|
||||||
|
std::list<cryptonote::transaction> pool_txs;
|
||||||
|
|
||||||
|
m_core.get_pool_transactions(pool_txs);
|
||||||
|
|
||||||
|
for (const auto& tx : pool_txs)
|
||||||
|
{
|
||||||
|
crypto::hash h = get_transaction_hash(tx);
|
||||||
|
|
||||||
|
auto itr = std::find(missed_vec.begin(), missed_vec.end(), h);
|
||||||
|
|
||||||
|
if (itr != missed_vec.end())
|
||||||
|
{
|
||||||
|
found_hashes.push_back(h);
|
||||||
|
found_txs_vec.push_back(tx);
|
||||||
|
heights.push_back(std::numeric_limits<uint64_t>::max());
|
||||||
|
in_pool.push_back(true);
|
||||||
|
missed_vec.erase(itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=0; i < found_hashes.size(); i++)
|
||||||
|
{
|
||||||
|
cryptonote::rpc::transaction_info info;
|
||||||
|
info.height = heights[i];
|
||||||
|
info.in_pool = in_pool[i];
|
||||||
|
info.transaction = std::move(found_txs_vec[i]);
|
||||||
|
|
||||||
|
res.txs.emplace(found_hashes[i], std::move(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
res.missed_hashes = std::move(missed_vec);
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const KeyImagesSpent::Request& req, KeyImagesSpent::Response& res)
|
||||||
|
{
|
||||||
|
res.spent_status.resize(req.key_images.size(), KeyImagesSpent::STATUS::UNSPENT);
|
||||||
|
|
||||||
|
std::vector<bool> chain_spent_status;
|
||||||
|
std::vector<bool> pool_spent_status;
|
||||||
|
|
||||||
|
m_core.are_key_images_spent(req.key_images, chain_spent_status);
|
||||||
|
m_core.are_key_images_spent_in_pool(req.key_images, pool_spent_status);
|
||||||
|
|
||||||
|
if ((chain_spent_status.size() != req.key_images.size()) || (pool_spent_status.size() != req.key_images.size()))
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "tx_pool::have_key_images_as_spent() gave vectors of wrong size(s).";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i=0; i < req.key_images.size(); i++)
|
||||||
|
{
|
||||||
|
if ( chain_spent_status[i] )
|
||||||
|
{
|
||||||
|
res.spent_status[i] = KeyImagesSpent::STATUS::SPENT_IN_BLOCKCHAIN;
|
||||||
|
}
|
||||||
|
else if ( pool_spent_status[i] )
|
||||||
|
{
|
||||||
|
res.spent_status[i] = KeyImagesSpent::STATUS::SPENT_IN_POOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetTxGlobalOutputIndices::Request& req, GetTxGlobalOutputIndices::Response& res)
|
||||||
|
{
|
||||||
|
if (!m_core.get_tx_outputs_gindexs(req.tx_hash, res.output_indices))
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "core::get_tx_outputs_gindexs() returned false";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: handle "restricted" RPC
|
||||||
|
void DaemonHandler::handle(const GetRandomOutputsForAmounts::Request& req, GetRandomOutputsForAmounts::Response& res)
|
||||||
|
{
|
||||||
|
auto& chain = m_core.get_blockchain_storage();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (const uint64_t& amount : req.amounts)
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> indices = chain.get_random_outputs(amount, req.count);
|
||||||
|
|
||||||
|
outputs_for_amount ofa;
|
||||||
|
|
||||||
|
ofa.resize(indices.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < indices.size(); i++)
|
||||||
|
{
|
||||||
|
crypto::public_key key = chain.get_output_key(amount, indices[i]);
|
||||||
|
ofa[i].amount_index = indices[i];
|
||||||
|
ofa[i].key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
amount_with_random_outputs amt;
|
||||||
|
amt.amount = amount;
|
||||||
|
amt.outputs = ofa;
|
||||||
|
|
||||||
|
res.amounts_with_outputs.push_back(amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const SendRawTx::Request& req, SendRawTx::Response& res)
|
||||||
|
{
|
||||||
|
auto tx_blob = cryptonote::tx_to_blob(req.tx);
|
||||||
|
|
||||||
|
cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
|
||||||
|
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||||
|
|
||||||
|
if(!m_core.handle_incoming_tx(tx_blob, tvc, false, false, !req.relay) || tvc.m_verifivation_failed)
|
||||||
|
{
|
||||||
|
if (tvc.m_verifivation_failed)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx");
|
||||||
|
}
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "";
|
||||||
|
|
||||||
|
if (tvc.m_low_mixin)
|
||||||
|
{
|
||||||
|
res.error_details = "mixin too low";
|
||||||
|
}
|
||||||
|
if (tvc.m_double_spend)
|
||||||
|
{
|
||||||
|
if (!res.error_details.empty()) res.error_details += " and ";
|
||||||
|
res.error_details = "double spend";
|
||||||
|
}
|
||||||
|
if (tvc.m_invalid_input)
|
||||||
|
{
|
||||||
|
if (!res.error_details.empty()) res.error_details += " and ";
|
||||||
|
res.error_details = "invalid input";
|
||||||
|
}
|
||||||
|
if (tvc.m_invalid_output)
|
||||||
|
{
|
||||||
|
if (!res.error_details.empty()) res.error_details += " and ";
|
||||||
|
res.error_details = "invalid output";
|
||||||
|
}
|
||||||
|
if (tvc.m_too_big)
|
||||||
|
{
|
||||||
|
if (!res.error_details.empty()) res.error_details += " and ";
|
||||||
|
res.error_details = "too big";
|
||||||
|
}
|
||||||
|
if (tvc.m_overspend)
|
||||||
|
{
|
||||||
|
if (!res.error_details.empty()) res.error_details += " and ";
|
||||||
|
res.error_details = "overspend";
|
||||||
|
}
|
||||||
|
if (tvc.m_fee_too_low)
|
||||||
|
{
|
||||||
|
if (!res.error_details.empty()) res.error_details += " and ";
|
||||||
|
res.error_details = "fee too low";
|
||||||
|
}
|
||||||
|
if (tvc.m_not_rct)
|
||||||
|
{
|
||||||
|
if (!res.error_details.empty()) res.error_details += " and ";
|
||||||
|
res.error_details = "tx is not ringct";
|
||||||
|
}
|
||||||
|
if (res.error_details.empty())
|
||||||
|
{
|
||||||
|
res.error_details = "an unknown issue was found with the transaction";
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!tvc.m_should_be_relayed || !req.relay)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed");
|
||||||
|
res.error_details = "Not relayed";
|
||||||
|
res.relayed = false;
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTIFY_NEW_TRANSACTIONS::request r;
|
||||||
|
r.txs.push_back(tx_blob);
|
||||||
|
m_core.get_protocol()->relay_transactions(r, fake_context);
|
||||||
|
|
||||||
|
//TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
res.relayed = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const StartMining::Request& req, StartMining::Response& res)
|
||||||
|
{
|
||||||
|
account_public_address adr;
|
||||||
|
if(!get_account_address_from_str(adr, m_core.get_testnet(), req.miner_address))
|
||||||
|
{
|
||||||
|
res.error_details = "Failed, wrong address";
|
||||||
|
LOG_PRINT_L0(res.error_details);
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int concurrency_count = boost::thread::hardware_concurrency() * 4;
|
||||||
|
|
||||||
|
// if we couldn't detect threads, set it to a ridiculously high number
|
||||||
|
if(concurrency_count == 0)
|
||||||
|
{
|
||||||
|
concurrency_count = 257;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there are more threads requested than the hardware supports
|
||||||
|
// then we fail and log that.
|
||||||
|
if(req.threads_count > concurrency_count)
|
||||||
|
{
|
||||||
|
res.error_details = "Failed, too many threads relative to CPU cores.";
|
||||||
|
LOG_PRINT_L0(res.error_details);
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::thread::attributes attrs;
|
||||||
|
attrs.set_stack_size(THREAD_STACK_SIZE);
|
||||||
|
|
||||||
|
if(!m_core.get_miner().start(adr, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery))
|
||||||
|
{
|
||||||
|
res.error_details = "Failed, mining not started";
|
||||||
|
LOG_PRINT_L0(res.error_details);
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
res.error_details = "";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetInfo::Request& req, GetInfo::Response& res)
|
||||||
|
{
|
||||||
|
res.info.height = m_core.get_current_blockchain_height();
|
||||||
|
|
||||||
|
res.info.target_height = m_core.get_target_blockchain_height();
|
||||||
|
|
||||||
|
if (res.info.height > res.info.target_height)
|
||||||
|
{
|
||||||
|
res.info.target_height = res.info.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& chain = m_core.get_blockchain_storage();
|
||||||
|
|
||||||
|
res.info.difficulty = chain.get_difficulty_for_next_block();
|
||||||
|
|
||||||
|
res.info.target = chain.get_difficulty_target();
|
||||||
|
|
||||||
|
res.info.tx_count = chain.get_total_transactions() - res.info.height; //without coinbase
|
||||||
|
|
||||||
|
res.info.tx_pool_size = m_core.get_pool_transactions_count();
|
||||||
|
|
||||||
|
res.info.alt_blocks_count = chain.get_alternative_blocks_count();
|
||||||
|
|
||||||
|
uint64_t total_conn = m_p2p.get_connections_count();
|
||||||
|
res.info.outgoing_connections_count = m_p2p.get_outgoing_connections_count();
|
||||||
|
res.info.incoming_connections_count = total_conn - res.info.outgoing_connections_count;
|
||||||
|
|
||||||
|
res.info.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count();
|
||||||
|
|
||||||
|
res.info.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count();
|
||||||
|
|
||||||
|
res.info.testnet = m_core.get_testnet();
|
||||||
|
res.info.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.info.height - 1);
|
||||||
|
res.info.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit();
|
||||||
|
res.info.start_time = (uint64_t)m_core.get_start_time();
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
res.error_details = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const StopMining::Request& req, StopMining::Response& res)
|
||||||
|
{
|
||||||
|
if(!m_core.get_miner().stop())
|
||||||
|
{
|
||||||
|
res.error_details = "Failed, mining not stopped";
|
||||||
|
LOG_PRINT_L0(res.error_details);
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
res.error_details = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const MiningStatus::Request& req, MiningStatus::Response& res)
|
||||||
|
{
|
||||||
|
const cryptonote::miner& lMiner = m_core.get_miner();
|
||||||
|
res.active = lMiner.is_mining();
|
||||||
|
res.is_background_mining_enabled = lMiner.get_is_background_mining_enabled();
|
||||||
|
|
||||||
|
if ( lMiner.is_mining() ) {
|
||||||
|
res.speed = lMiner.get_speed();
|
||||||
|
res.threads_count = lMiner.get_threads_count();
|
||||||
|
const account_public_address& lMiningAdr = lMiner.get_mining_address();
|
||||||
|
res.address = get_account_address_as_str(m_core.get_testnet(), lMiningAdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
res.error_details = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const SaveBC::Request& req, SaveBC::Response& res)
|
||||||
|
{
|
||||||
|
if (!m_core.get_blockchain_storage().store_blockchain())
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "Error storing the blockchain";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBlockHash::Request& req, GetBlockHash::Response& res)
|
||||||
|
{
|
||||||
|
if (m_core.get_current_blockchain_height() <= req.height)
|
||||||
|
{
|
||||||
|
res.hash = cryptonote::null_hash;
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "height given is higher than current chain height";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.hash = m_core.get_block_id_by_height(req.height);
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBlockTemplate::Request& req, GetBlockTemplate::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const SubmitBlock::Request& req, SubmitBlock::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetLastBlockHeader::Request& req, GetLastBlockHeader::Response& res)
|
||||||
|
{
|
||||||
|
const crypto::hash block_hash = m_core.get_tail_id();
|
||||||
|
|
||||||
|
if (!getBlockHeaderByHash(block_hash, res.header))
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "Requested block does not exist";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBlockHeaderByHash::Request& req, GetBlockHeaderByHash::Response& res)
|
||||||
|
{
|
||||||
|
if (!getBlockHeaderByHash(req.hash, res.header))
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "Requested block does not exist";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBlockHeaderByHeight::Request& req, GetBlockHeaderByHeight::Response& res)
|
||||||
|
{
|
||||||
|
const crypto::hash block_hash = m_core.get_block_id_by_height(req.height);
|
||||||
|
|
||||||
|
if (!getBlockHeaderByHash(block_hash, res.header))
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "Requested block does not exist";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBlockHeadersByHeight::Request& req, GetBlockHeadersByHeight::Response& res)
|
||||||
|
{
|
||||||
|
res.headers.resize(req.heights.size());
|
||||||
|
|
||||||
|
for (size_t i=0; i < req.heights.size(); i++)
|
||||||
|
{
|
||||||
|
const crypto::hash block_hash = m_core.get_block_id_by_height(req.heights[i]);
|
||||||
|
|
||||||
|
if (!getBlockHeaderByHash(block_hash, res.headers[i]))
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "A requested block does not exist";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBlock::Request& req, GetBlock::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetPeerList::Request& req, GetPeerList::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const SetLogHashRate::Request& req, SetLogHashRate::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const SetLogLevel::Request& req, SetLogLevel::Response& res)
|
||||||
|
{
|
||||||
|
if (req.level < 0 || req.level > 4)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "Error: log level not valid";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
mlog_set_log_level(req.level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetTransactionPool::Request& req, GetTransactionPool::Response& res)
|
||||||
|
{
|
||||||
|
bool r = m_core.get_pool_for_rpc(res.transactions, res.key_images);
|
||||||
|
|
||||||
|
if (!r) res.status = Message::STATUS_FAILED;
|
||||||
|
else res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetConnections::Request& req, GetConnections::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBlockHeadersRange::Request& req, GetBlockHeadersRange::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const StopDaemon::Request& req, StopDaemon::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const StartSaveGraph::Request& req, StartSaveGraph::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const StopSaveGraph::Request& req, StopSaveGraph::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const HardForkInfo::Request& req, HardForkInfo::Response& res)
|
||||||
|
{
|
||||||
|
const Blockchain &blockchain = m_core.get_blockchain_storage();
|
||||||
|
uint8_t version = req.version > 0 ? req.version : blockchain.get_ideal_hard_fork_version();
|
||||||
|
res.info.version = blockchain.get_current_hard_fork_version();
|
||||||
|
res.info.enabled = blockchain.get_hard_fork_voting_info(version, res.info.window, res.info.votes, res.info.threshold, res.info.earliest_height, res.info.voting);
|
||||||
|
res.info.state = blockchain.get_hard_fork_state();
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetBans::Request& req, GetBans::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const SetBans::Request& req, SetBans::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const FlushTransactionPool::Request& req, FlushTransactionPool::Response& res)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "RPC method not yet implemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetOutputHistogram::Request& req, GetOutputHistogram::Response& res)
|
||||||
|
{
|
||||||
|
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t> > histogram;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts, req.unlocked, req.recent_cutoff);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = e.what();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.histogram.clear();
|
||||||
|
res.histogram.reserve(histogram.size());
|
||||||
|
for (const auto &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.emplace_back(output_amount_count{i.first, std::get<0>(i.second), std::get<1>(i.second), std::get<2>(i.second)});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetOutputKeys::Request& req, GetOutputKeys::Response& res)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (const auto& i : req.outputs)
|
||||||
|
{
|
||||||
|
crypto::public_key key;
|
||||||
|
rct::key mask;
|
||||||
|
bool unlocked;
|
||||||
|
m_core.get_blockchain_storage().get_output_key_mask_unlocked(i.amount, i.index, key, mask, unlocked);
|
||||||
|
res.keys.emplace_back(output_key_mask_unlocked{key, mask, unlocked});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = e.what();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetRPCVersion::Request& req, GetRPCVersion::Response& res)
|
||||||
|
{
|
||||||
|
res.version = DAEMON_RPC_VERSION_ZMQ;
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetPerKBFeeEstimate::Request& req, GetPerKBFeeEstimate::Response& res)
|
||||||
|
{
|
||||||
|
res.estimated_fee_per_kb = m_core.get_blockchain_storage().get_dynamic_per_kb_fee_estimate(req.num_grace_blocks);
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DaemonHandler::getBlockHeaderByHash(const crypto::hash& hash_in, cryptonote::rpc::BlockHeaderResponse& header)
|
||||||
|
{
|
||||||
|
block b;
|
||||||
|
|
||||||
|
if (!m_core.get_block_by_hash(hash_in, b))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.hash = hash_in;
|
||||||
|
header.height = boost::get<txin_gen>(b.miner_tx.vin.front()).height;
|
||||||
|
|
||||||
|
header.major_version = b.major_version;
|
||||||
|
header.minor_version = b.minor_version;
|
||||||
|
header.timestamp = b.timestamp;
|
||||||
|
header.nonce = b.nonce;
|
||||||
|
header.prev_id = b.prev_id;
|
||||||
|
|
||||||
|
header.depth = m_core.get_current_blockchain_height() - header.height - 1;
|
||||||
|
|
||||||
|
header.reward = 0;
|
||||||
|
for (const auto& out : b.miner_tx.vout)
|
||||||
|
{
|
||||||
|
header.reward += out.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.difficulty = m_core.get_blockchain_storage().block_difficulty(header.height);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DaemonHandler::handle(const std::string& request)
|
||||||
|
{
|
||||||
|
MDEBUG("Handling RPC request: " << request);
|
||||||
|
|
||||||
|
Message* resp_message = NULL;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FullMessage req_full(request, true);
|
||||||
|
|
||||||
|
rapidjson::Value& req_json = req_full.getMessage();
|
||||||
|
|
||||||
|
const std::string request_type = req_full.getRequestType();
|
||||||
|
|
||||||
|
// create correct Message subclass and call handle() on it
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetHeight, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetBlocksFast, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetHashesFast, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetTransactions, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, KeyImagesSpent, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetTxGlobalOutputIndices, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetRandomOutputsForAmounts, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, SendRawTx, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetInfo, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, StartMining, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, StopMining, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, MiningStatus, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, SaveBC, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetBlockHash, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetLastBlockHeader, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHash, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHeight, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetBlockHeadersByHeight, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetPeerList, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, SetLogLevel, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetTransactionPool, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, HardForkInfo, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetOutputHistogram, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetOutputKeys, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetRPCVersion, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetPerKBFeeEstimate, req_json, resp_message, handle);
|
||||||
|
|
||||||
|
// if none of the request types matches
|
||||||
|
if (resp_message == NULL)
|
||||||
|
{
|
||||||
|
return BAD_REQUEST(request_type, req_full.getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMessage resp_full = FullMessage::responseMessage(resp_message, req_full.getID());
|
||||||
|
|
||||||
|
const std::string response = resp_full.getJson();
|
||||||
|
delete resp_message;
|
||||||
|
resp_message = NULL;
|
||||||
|
|
||||||
|
MDEBUG("Returning RPC response: " << response);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
if (resp_message)
|
||||||
|
{
|
||||||
|
delete resp_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BAD_JSON(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rpc
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
|
@ -0,0 +1,145 @@
|
||||||
|
// Copyright (c) 2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "daemon_messages.h"
|
||||||
|
#include "daemon_rpc_version.h"
|
||||||
|
#include "rpc_handler.h"
|
||||||
|
#include "cryptonote_core/cryptonote_core.h"
|
||||||
|
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||||
|
#include "p2p/net_node.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
typedef nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > t_p2p;
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
class DaemonHandler : public RpcHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
DaemonHandler(cryptonote::core& c, t_p2p& p2p) : m_core(c), m_p2p(p2p) { }
|
||||||
|
|
||||||
|
~DaemonHandler() { }
|
||||||
|
|
||||||
|
void handle(const GetHeight::Request& req, GetHeight::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBlocksFast::Request& req, GetBlocksFast::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetHashesFast::Request& req, GetHashesFast::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetTransactions::Request& req, GetTransactions::Response& res);
|
||||||
|
|
||||||
|
void handle(const KeyImagesSpent::Request& req, KeyImagesSpent::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetTxGlobalOutputIndices::Request& req, GetTxGlobalOutputIndices::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetRandomOutputsForAmounts::Request& req, GetRandomOutputsForAmounts::Response& res);
|
||||||
|
|
||||||
|
void handle(const SendRawTx::Request& req, SendRawTx::Response& res);
|
||||||
|
|
||||||
|
void handle(const StartMining::Request& req, StartMining::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetInfo::Request& req, GetInfo::Response& res);
|
||||||
|
|
||||||
|
void handle(const StopMining::Request& req, StopMining::Response& res);
|
||||||
|
|
||||||
|
void handle(const MiningStatus::Request& req, MiningStatus::Response& res);
|
||||||
|
|
||||||
|
void handle(const SaveBC::Request& req, SaveBC::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBlockHash::Request& req, GetBlockHash::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBlockTemplate::Request& req, GetBlockTemplate::Response& res);
|
||||||
|
|
||||||
|
void handle(const SubmitBlock::Request& req, SubmitBlock::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetLastBlockHeader::Request& req, GetLastBlockHeader::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBlockHeaderByHash::Request& req, GetBlockHeaderByHash::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBlockHeaderByHeight::Request& req, GetBlockHeaderByHeight::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBlockHeadersByHeight::Request& req, GetBlockHeadersByHeight::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBlock::Request& req, GetBlock::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetPeerList::Request& req, GetPeerList::Response& res);
|
||||||
|
|
||||||
|
void handle(const SetLogHashRate::Request& req, SetLogHashRate::Response& res);
|
||||||
|
|
||||||
|
void handle(const SetLogLevel::Request& req, SetLogLevel::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetTransactionPool::Request& req, GetTransactionPool::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetConnections::Request& req, GetConnections::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBlockHeadersRange::Request& req, GetBlockHeadersRange::Response& res);
|
||||||
|
|
||||||
|
void handle(const StopDaemon::Request& req, StopDaemon::Response& res);
|
||||||
|
|
||||||
|
void handle(const StartSaveGraph::Request& req, StartSaveGraph::Response& res);
|
||||||
|
|
||||||
|
void handle(const StopSaveGraph::Request& req, StopSaveGraph::Response& res);
|
||||||
|
|
||||||
|
void handle(const HardForkInfo::Request& req, HardForkInfo::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetBans::Request& req, GetBans::Response& res);
|
||||||
|
|
||||||
|
void handle(const SetBans::Request& req, SetBans::Response& res);
|
||||||
|
|
||||||
|
void handle(const FlushTransactionPool::Request& req, FlushTransactionPool::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetOutputHistogram::Request& req, GetOutputHistogram::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetOutputKeys::Request& req, GetOutputKeys::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetRPCVersion::Request& req, GetRPCVersion::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetPerKBFeeEstimate::Request& req, GetPerKBFeeEstimate::Response& res);
|
||||||
|
|
||||||
|
std::string handle(const std::string& request);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool getBlockHeaderByHash(const crypto::hash& hash_in, cryptonote::rpc::BlockHeaderResponse& response);
|
||||||
|
|
||||||
|
cryptonote::core& m_core;
|
||||||
|
t_p2p& m_p2p;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rpc
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
|
@ -0,0 +1,900 @@
|
||||||
|
// Copyright (c) 2016-2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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 "daemon_messages.h"
|
||||||
|
#include "serialization/json_object.h"
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
const char* const GetHeight::name = "get_height";
|
||||||
|
const char* const GetBlocksFast::name = "get_blocks_fast";
|
||||||
|
const char* const GetHashesFast::name = "get_hashes_fast";
|
||||||
|
const char* const GetTransactions::name = "get_transactions";
|
||||||
|
const char* const KeyImagesSpent::name = "key_images_spent";
|
||||||
|
const char* const GetTxGlobalOutputIndices::name = "get_tx_global_output_indices";
|
||||||
|
const char* const GetRandomOutputsForAmounts::name = "get_random_outputs_for_amounts";
|
||||||
|
const char* const SendRawTx::name = "send_raw_tx";
|
||||||
|
const char* const StartMining::name = "start_mining";
|
||||||
|
const char* const StopMining::name = "stop_mining";
|
||||||
|
const char* const MiningStatus::name = "mining_status";
|
||||||
|
const char* const GetInfo::name = "get_info";
|
||||||
|
const char* const SaveBC::name = "save_bc";
|
||||||
|
const char* const GetBlockHash::name = "get_block_hash";
|
||||||
|
const char* const GetLastBlockHeader::name = "get_last_block_header";
|
||||||
|
const char* const GetBlockHeaderByHash::name = "get_block_header_by_hash";
|
||||||
|
const char* const GetBlockHeaderByHeight::name = "get_block_header_by_height";
|
||||||
|
const char* const GetBlockHeadersByHeight::name = "get_block_headers_by_height";
|
||||||
|
const char* const GetPeerList::name = "get_peer_list";
|
||||||
|
const char* const SetLogLevel::name = "set_log_level";
|
||||||
|
const char* const GetTransactionPool::name = "get_transaction_pool";
|
||||||
|
const char* const HardForkInfo::name = "hard_fork_info";
|
||||||
|
const char* const GetOutputHistogram::name = "get_output_histogram";
|
||||||
|
const char* const GetOutputKeys::name = "get_output_keys";
|
||||||
|
const char* const GetRPCVersion::name = "get_rpc_version";
|
||||||
|
const char* const GetPerKBFeeEstimate::name = "get_dynamic_per_kb_fee_estimate";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetHeight::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetHeight::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetHeight::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
val.AddMember("height", height, al);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetHeight::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, height, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetBlocksFast::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, block_ids, block_ids);
|
||||||
|
val.AddMember("start_height", start_height, al);
|
||||||
|
val.AddMember("prune", prune, al);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlocksFast::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, block_ids, block_ids);
|
||||||
|
GET_FROM_JSON_OBJECT(val, start_height, start_height);
|
||||||
|
GET_FROM_JSON_OBJECT(val, prune, prune);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetBlocksFast::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, blocks, blocks);
|
||||||
|
val.AddMember("start_height", start_height, al);
|
||||||
|
val.AddMember("current_height", current_height, al);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, output_indices, output_indices);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlocksFast::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, blocks, blocks);
|
||||||
|
GET_FROM_JSON_OBJECT(val, start_height, start_height);
|
||||||
|
GET_FROM_JSON_OBJECT(val, current_height, current_height);
|
||||||
|
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetHashesFast::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, known_hashes, known_hashes);
|
||||||
|
val.AddMember("start_height", start_height, al);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetHashesFast::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, known_hashes, known_hashes);
|
||||||
|
GET_FROM_JSON_OBJECT(val, start_height, start_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetHashesFast::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, hashes, hashes);
|
||||||
|
val.AddMember("start_height", start_height, al);
|
||||||
|
val.AddMember("current_height", current_height, al);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetHashesFast::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, hashes, hashes);
|
||||||
|
GET_FROM_JSON_OBJECT(val, start_height, start_height);
|
||||||
|
GET_FROM_JSON_OBJECT(val, current_height, current_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetTransactions::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, tx_hashes, tx_hashes);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetTransactions::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, tx_hashes, tx_hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetTransactions::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
rapidjson::Value val(rapidjson::kObjectType);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, txs, txs);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, missed_hashes, missed_hashes);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetTransactions::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, txs, txs);
|
||||||
|
GET_FROM_JSON_OBJECT(val, missed_hashes, missed_hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value KeyImagesSpent::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, key_images, key_images);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyImagesSpent::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, key_images, key_images);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value KeyImagesSpent::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, spent_status, spent_status);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyImagesSpent::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, spent_status, spent_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetTxGlobalOutputIndices::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, tx_hash, tx_hash);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetTxGlobalOutputIndices::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, tx_hash, tx_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetTxGlobalOutputIndices::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, output_indices, output_indices);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetTxGlobalOutputIndices::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetRandomOutputsForAmounts::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, amounts, amounts);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, count, count);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetRandomOutputsForAmounts::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, amounts, amounts);
|
||||||
|
GET_FROM_JSON_OBJECT(val, count, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetRandomOutputsForAmounts::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, amounts_with_outputs, amounts_with_outputs);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetRandomOutputsForAmounts::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, amounts_with_outputs, amounts_with_outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value SendRawTx::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, tx, tx);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, relay, relay);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendRawTx::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, tx, tx);
|
||||||
|
GET_FROM_JSON_OBJECT(val, relay, relay);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value SendRawTx::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, relayed, relayed);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SendRawTx::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, relayed, relayed);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value StartMining::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, miner_address, miner_address);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, threads_count, threads_count);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, do_background_mining, do_background_mining);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, ignore_battery, ignore_battery);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartMining::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, miner_address, miner_address);
|
||||||
|
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
|
||||||
|
GET_FROM_JSON_OBJECT(val, do_background_mining, do_background_mining);
|
||||||
|
GET_FROM_JSON_OBJECT(val, ignore_battery, ignore_battery);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value StartMining::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartMining::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value StopMining::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopMining::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value StopMining::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopMining::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value MiningStatus::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiningStatus::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value MiningStatus::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, active, active);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, speed, speed);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, threads_count, threads_count);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, address, address);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, is_background_mining_enabled, is_background_mining_enabled);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiningStatus::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, active, active);
|
||||||
|
GET_FROM_JSON_OBJECT(val, speed, speed);
|
||||||
|
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
|
||||||
|
GET_FROM_JSON_OBJECT(val, address, address);
|
||||||
|
GET_FROM_JSON_OBJECT(val, is_background_mining_enabled, is_background_mining_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetInfo::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetInfo::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetInfo::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, info, info);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetInfo::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, info, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value SaveBC::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveBC::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value SaveBC::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveBC::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetBlockHash::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, height, height);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlockHash::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, height, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetBlockHash::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, hash, hash);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlockHash::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, hash, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetLastBlockHeader::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetLastBlockHeader::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetLastBlockHeader::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, header, header);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetLastBlockHeader::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, header, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetBlockHeaderByHash::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, hash, hash);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlockHeaderByHash::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, hash, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetBlockHeaderByHash::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, header, header);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlockHeaderByHash::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, header, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetBlockHeaderByHeight::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, height, height);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlockHeaderByHeight::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, height, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetBlockHeaderByHeight::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, header, header);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlockHeaderByHeight::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, header, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetBlockHeadersByHeight::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, heights, heights);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlockHeadersByHeight::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, heights, heights);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetBlockHeadersByHeight::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, headers, headers);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBlockHeadersByHeight::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, headers, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetPeerList::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetPeerList::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetPeerList::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, white_list, white_list);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, gray_list, gray_list);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetPeerList::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, white_list, white_list);
|
||||||
|
GET_FROM_JSON_OBJECT(val, gray_list, gray_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value SetLogLevel::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
val.AddMember("level", level, al);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLogLevel::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, level, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value SetLogLevel::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLogLevel::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetTransactionPool::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetTransactionPool::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetTransactionPool::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, transactions, transactions);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, key_images, key_images);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetTransactionPool::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, transactions, transactions);
|
||||||
|
GET_FROM_JSON_OBJECT(val, key_images, key_images);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value HardForkInfo::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, version, version);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HardForkInfo::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, version, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value HardForkInfo::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, info, info);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HardForkInfo::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, info, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetOutputHistogram::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, amounts, amounts);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, min_count, min_count);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, max_count, max_count);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, unlocked, unlocked);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, recent_cutoff, recent_cutoff);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetOutputHistogram::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, amounts, amounts);
|
||||||
|
GET_FROM_JSON_OBJECT(val, min_count, min_count);
|
||||||
|
GET_FROM_JSON_OBJECT(val, max_count, max_count);
|
||||||
|
GET_FROM_JSON_OBJECT(val, unlocked, unlocked);
|
||||||
|
GET_FROM_JSON_OBJECT(val, recent_cutoff, recent_cutoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetOutputHistogram::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, histogram, histogram);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetOutputHistogram::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, histogram, histogram);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetOutputKeys::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, outputs, outputs);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetOutputKeys::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, outputs, outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetOutputKeys::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, keys, keys);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetOutputKeys::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, keys, keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rapidjson::Value GetRPCVersion::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
return Message::toJson(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetRPCVersion::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetRPCVersion::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, version, version);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetRPCVersion::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, version, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetPerKBFeeEstimate::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, num_grace_blocks, num_grace_blocks);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetPerKBFeeEstimate::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetPerKBFeeEstimate::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, estimated_fee_per_kb, estimated_fee_per_kb);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetPerKBFeeEstimate::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, estimated_fee_per_kb, estimated_fee_per_kb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace rpc
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
|
@ -0,0 +1,421 @@
|
||||||
|
// Copyright (c) 2016-2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "message.h"
|
||||||
|
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||||
|
#include "rpc/message_data_structs.h"
|
||||||
|
#include "rpc/daemon_rpc_version.h"
|
||||||
|
#include "cryptonote_basic/cryptonote_basic.h"
|
||||||
|
|
||||||
|
#define BEGIN_RPC_MESSAGE_CLASS(classname) \
|
||||||
|
class classname \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
static const char* const name;
|
||||||
|
|
||||||
|
#define BEGIN_RPC_MESSAGE_REQUEST \
|
||||||
|
class Request : public Message \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
Request() { } \
|
||||||
|
~Request() { } \
|
||||||
|
rapidjson::Value toJson(rapidjson::Document& doc) const; \
|
||||||
|
void fromJson(rapidjson::Value& val);
|
||||||
|
|
||||||
|
#define BEGIN_RPC_MESSAGE_RESPONSE \
|
||||||
|
class Response : public Message \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
Response() { } \
|
||||||
|
~Response() { } \
|
||||||
|
rapidjson::Value toJson(rapidjson::Document& doc) const; \
|
||||||
|
void fromJson(rapidjson::Value& val);
|
||||||
|
|
||||||
|
#define END_RPC_MESSAGE_REQUEST };
|
||||||
|
#define END_RPC_MESSAGE_RESPONSE };
|
||||||
|
#define END_RPC_MESSAGE_CLASS };
|
||||||
|
|
||||||
|
#define COMMA() ,
|
||||||
|
|
||||||
|
// NOTE: when using a type with multiple template parameters,
|
||||||
|
// replace any comma in the template specifier with the macro
|
||||||
|
// above, or the preprocessor will eat the comma in a bad way.
|
||||||
|
#define RPC_MESSAGE_MEMBER(type, name) type name;
|
||||||
|
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetHeight);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, height);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBlocksFast);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::list<crypto::hash>, block_ids);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, start_height);
|
||||||
|
RPC_MESSAGE_MEMBER(bool, prune);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<cryptonote::rpc::block_with_transactions>, blocks);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, start_height);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, current_height);
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<cryptonote::rpc::block_output_indices>, output_indices);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetHashesFast);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::list<crypto::hash>, known_hashes);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, start_height);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::list<crypto::hash>, hashes);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, start_height);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, current_height);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetTransactions);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<crypto::hash>, tx_hashes);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::unordered_map<crypto::hash COMMA() cryptonote::rpc::transaction_info>, txs);
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<crypto::hash>, missed_hashes);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(KeyImagesSpent);
|
||||||
|
enum STATUS {
|
||||||
|
UNSPENT = 0,
|
||||||
|
SPENT_IN_BLOCKCHAIN = 1,
|
||||||
|
SPENT_IN_POOL = 2,
|
||||||
|
};
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<crypto::key_image>, key_images);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<uint64_t>, spent_status);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetTxGlobalOutputIndices);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(crypto::hash, tx_hash);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<uint64_t>, output_indices);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetRandomOutputsForAmounts);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<uint64_t>, amounts);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, count);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<amount_with_random_outputs>, amounts_with_outputs);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(SendRawTx);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(cryptonote::transaction, tx);
|
||||||
|
RPC_MESSAGE_MEMBER(bool, relay);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(bool, relayed);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(StartMining);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::string, miner_address);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, threads_count);
|
||||||
|
RPC_MESSAGE_MEMBER(bool, do_background_mining);
|
||||||
|
RPC_MESSAGE_MEMBER(bool, ignore_battery);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetInfo);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(DaemonInfo, info);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(StopMining);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(MiningStatus);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(bool, active);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, speed);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, threads_count);
|
||||||
|
RPC_MESSAGE_MEMBER(std::string, address);
|
||||||
|
RPC_MESSAGE_MEMBER(bool, is_background_mining_enabled);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(SaveBC);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBlockHash);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, height);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(crypto::hash, hash);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBlockTemplate);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(SubmitBlock);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetLastBlockHeader);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(cryptonote::rpc::BlockHeaderResponse, header);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBlockHeaderByHash);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(crypto::hash, hash);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(cryptonote::rpc::BlockHeaderResponse, header);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBlockHeaderByHeight);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, height);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(cryptonote::rpc::BlockHeaderResponse, header);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBlockHeadersByHeight);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<uint64_t>, heights);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<cryptonote::rpc::BlockHeaderResponse>, headers);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBlock);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetPeerList);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<peer>, white_list);
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<peer>, gray_list);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(SetLogHashRate);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(SetLogLevel);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(int8_t, level);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetTransactionPool);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<cryptonote::rpc::tx_in_pool>, transactions);
|
||||||
|
RPC_MESSAGE_MEMBER(key_images_with_tx_hashes, key_images);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetConnections);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBlockHeadersRange);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(StopDaemon);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(StartSaveGraph);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(StopSaveGraph);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(HardForkInfo);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(uint8_t, version);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(hard_fork_info, info);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetBans);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(SetBans);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(FlushTransactionPool);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetOutputHistogram);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<uint64_t>, amounts);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, min_count);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, max_count);
|
||||||
|
RPC_MESSAGE_MEMBER(bool, unlocked);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, recent_cutoff);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<output_amount_count>, histogram);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetOutputKeys);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<output_amount_and_index>, outputs);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<output_key_mask_unlocked>, keys);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetRPCVersion);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(uint32_t, version);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetPerKBFeeEstimate);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, num_grace_blocks);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, estimated_fee_per_kb);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
} // namespace rpc
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright (c) 2016-2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
static const uint32_t DAEMON_RPC_VERSION_ZMQ_MINOR = 0;
|
||||||
|
static const uint32_t DAEMON_RPC_VERSION_ZMQ_MAJOR = 1;
|
||||||
|
|
||||||
|
static const uint32_t DAEMON_RPC_VERSION_ZMQ = DAEMON_RPC_VERSION_ZMQ_MINOR + (DAEMON_RPC_VERSION_ZMQ_MAJOR << 16);
|
||||||
|
|
||||||
|
} // namespace rpc
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
|
@ -0,0 +1,286 @@
|
||||||
|
// Copyright (c) 2016-2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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 "message.h"
|
||||||
|
#include "daemon_rpc_version.h"
|
||||||
|
#include "serialization/json_object.h"
|
||||||
|
|
||||||
|
#include "rapidjson/writer.h"
|
||||||
|
#include "rapidjson/stringbuffer.h"
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
const char* Message::STATUS_OK = "OK";
|
||||||
|
const char* Message::STATUS_RETRY = "Retry";
|
||||||
|
const char* Message::STATUS_FAILED = "Failed";
|
||||||
|
const char* Message::STATUS_BAD_REQUEST = "Invalid request type";
|
||||||
|
const char* Message::STATUS_BAD_JSON = "Malformed json";
|
||||||
|
|
||||||
|
rapidjson::Value Message::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
rapidjson::Value val(rapidjson::kObjectType);
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
val.AddMember("status", rapidjson::StringRef(status.c_str()), al);
|
||||||
|
val.AddMember("error_details", rapidjson::StringRef(error_details.c_str()), al);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, rpc_version, DAEMON_RPC_VERSION_ZMQ);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Message::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, status, status);
|
||||||
|
GET_FROM_JSON_OBJECT(val, error_details, error_details);
|
||||||
|
GET_FROM_JSON_OBJECT(val, rpc_version, rpc_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FullMessage::FullMessage(const std::string& request, Message* message)
|
||||||
|
{
|
||||||
|
doc.SetObject();
|
||||||
|
|
||||||
|
doc.AddMember("method", rapidjson::StringRef(request.c_str()), doc.GetAllocator());
|
||||||
|
doc.AddMember("params", message->toJson(doc), doc.GetAllocator());
|
||||||
|
|
||||||
|
// required by JSON-RPC 2.0 spec
|
||||||
|
doc.AddMember("jsonrpc", rapidjson::Value("2.0"), doc.GetAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMessage::FullMessage(Message* message)
|
||||||
|
{
|
||||||
|
doc.SetObject();
|
||||||
|
|
||||||
|
// required by JSON-RPC 2.0 spec
|
||||||
|
doc.AddMember("jsonrpc", "2.0", doc.GetAllocator());
|
||||||
|
|
||||||
|
if (message->status == Message::STATUS_OK)
|
||||||
|
{
|
||||||
|
doc.AddMember("response", message->toJson(doc), doc.GetAllocator());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cryptonote::rpc::error err;
|
||||||
|
|
||||||
|
err.error_str = message->status;
|
||||||
|
err.message = message->error_details;
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(doc, doc, error, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMessage::FullMessage(const std::string& json_string, bool request)
|
||||||
|
{
|
||||||
|
doc.Parse(json_string.c_str());
|
||||||
|
if (doc.HasParseError())
|
||||||
|
{
|
||||||
|
throw cryptonote::json::PARSE_FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBJECT_HAS_MEMBER_OR_THROW(doc, "jsonrpc")
|
||||||
|
|
||||||
|
if (request)
|
||||||
|
{
|
||||||
|
OBJECT_HAS_MEMBER_OR_THROW(doc, "method")
|
||||||
|
OBJECT_HAS_MEMBER_OR_THROW(doc, "params")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!doc.HasMember("response") && !doc.HasMember("error"))
|
||||||
|
{
|
||||||
|
throw cryptonote::json::MISSING_KEY("error/response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FullMessage::getJson()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!doc.HasMember("id"))
|
||||||
|
{
|
||||||
|
doc.AddMember("id", rapidjson::Value("unused"), doc.GetAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::StringBuffer buf;
|
||||||
|
|
||||||
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
|
||||||
|
|
||||||
|
doc.Accept(writer);
|
||||||
|
|
||||||
|
return std::string(buf.GetString(), buf.GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FullMessage::getRequestType() const
|
||||||
|
{
|
||||||
|
OBJECT_HAS_MEMBER_OR_THROW(doc, "method")
|
||||||
|
return doc["method"].GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value& FullMessage::getMessage()
|
||||||
|
{
|
||||||
|
if (doc.HasMember("params"))
|
||||||
|
{
|
||||||
|
return doc["params"];
|
||||||
|
}
|
||||||
|
else if (doc.HasMember("response"))
|
||||||
|
{
|
||||||
|
return doc["response"];
|
||||||
|
}
|
||||||
|
|
||||||
|
//else
|
||||||
|
OBJECT_HAS_MEMBER_OR_THROW(doc, "error")
|
||||||
|
return doc["error"];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value FullMessage::getMessageCopy()
|
||||||
|
{
|
||||||
|
rapidjson::Value& val = getMessage();
|
||||||
|
|
||||||
|
return rapidjson::Value(val, doc.GetAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value& FullMessage::getID()
|
||||||
|
{
|
||||||
|
OBJECT_HAS_MEMBER_OR_THROW(doc, "id")
|
||||||
|
return doc["id"];
|
||||||
|
}
|
||||||
|
|
||||||
|
void FullMessage::setID(rapidjson::Value& id)
|
||||||
|
{
|
||||||
|
auto itr = doc.FindMember("id");
|
||||||
|
if (itr != doc.MemberEnd())
|
||||||
|
{
|
||||||
|
itr->value = id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doc.AddMember("id", id, doc.GetAllocator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptonote::rpc::error FullMessage::getError()
|
||||||
|
{
|
||||||
|
cryptonote::rpc::error err;
|
||||||
|
err.use = false;
|
||||||
|
if (doc.HasMember("error"))
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(doc, err, error);
|
||||||
|
err.use = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMessage FullMessage::requestMessage(const std::string& request, Message* message)
|
||||||
|
{
|
||||||
|
return FullMessage(request, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMessage FullMessage::requestMessage(const std::string& request, Message* message, rapidjson::Value& id)
|
||||||
|
{
|
||||||
|
auto mes = requestMessage(request, message);
|
||||||
|
mes.setID(id);
|
||||||
|
return mes;
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMessage FullMessage::responseMessage(Message* message)
|
||||||
|
{
|
||||||
|
return FullMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMessage FullMessage::responseMessage(Message* message, rapidjson::Value& id)
|
||||||
|
{
|
||||||
|
auto mes = responseMessage(message);
|
||||||
|
mes.setID(id);
|
||||||
|
return mes;
|
||||||
|
}
|
||||||
|
|
||||||
|
FullMessage* FullMessage::timeoutMessage()
|
||||||
|
{
|
||||||
|
auto *full_message = new FullMessage();
|
||||||
|
|
||||||
|
auto& doc = full_message->doc;
|
||||||
|
auto& al = full_message->doc.GetAllocator();
|
||||||
|
|
||||||
|
doc.SetObject();
|
||||||
|
|
||||||
|
// required by JSON-RPC 2.0 spec
|
||||||
|
doc.AddMember("jsonrpc", "2.0", al);
|
||||||
|
|
||||||
|
cryptonote::rpc::error err;
|
||||||
|
|
||||||
|
err.error_str = "RPC request timed out.";
|
||||||
|
INSERT_INTO_JSON_OBJECT(doc, doc, err, err);
|
||||||
|
|
||||||
|
return full_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convenience functions for bad input
|
||||||
|
std::string BAD_REQUEST(const std::string& request)
|
||||||
|
{
|
||||||
|
Message fail;
|
||||||
|
fail.status = Message::STATUS_BAD_REQUEST;
|
||||||
|
fail.error_details = std::string("\"") + request + "\" is not a valid request.";
|
||||||
|
|
||||||
|
FullMessage fail_response = FullMessage::responseMessage(&fail);
|
||||||
|
|
||||||
|
return fail_response.getJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BAD_REQUEST(const std::string& request, rapidjson::Value& id)
|
||||||
|
{
|
||||||
|
Message fail;
|
||||||
|
fail.status = Message::STATUS_BAD_REQUEST;
|
||||||
|
fail.error_details = std::string("\"") + request + "\" is not a valid request.";
|
||||||
|
|
||||||
|
FullMessage fail_response = FullMessage::responseMessage(&fail, id);
|
||||||
|
|
||||||
|
return fail_response.getJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BAD_JSON(const std::string& error_details)
|
||||||
|
{
|
||||||
|
Message fail;
|
||||||
|
fail.status = Message::STATUS_BAD_JSON;
|
||||||
|
fail.error_details = error_details;
|
||||||
|
|
||||||
|
FullMessage fail_response = FullMessage::responseMessage(&fail);
|
||||||
|
|
||||||
|
return fail_response.getJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace rpc
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
|
@ -0,0 +1,131 @@
|
||||||
|
// Copyright (c) 2016-2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "rpc/message_data_structs.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/* I normally hate using macros, but in this case it would be untenably
|
||||||
|
* verbose to not use a macro. This macro saves the trouble of explicitly
|
||||||
|
* writing the below if block for every single RPC call.
|
||||||
|
*/
|
||||||
|
#define REQ_RESP_TYPES_MACRO( runtime_str, type, reqjson, resp_message_ptr, handler) \
|
||||||
|
\
|
||||||
|
if (runtime_str == type::name) \
|
||||||
|
{ \
|
||||||
|
type::Request reqvar; \
|
||||||
|
type::Response *respvar = new type::Response(); \
|
||||||
|
\
|
||||||
|
reqvar.fromJson(reqjson); \
|
||||||
|
\
|
||||||
|
handler(reqvar, *respvar); \
|
||||||
|
\
|
||||||
|
resp_message_ptr = respvar; \
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
class Message
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const char* STATUS_OK;
|
||||||
|
static const char* STATUS_RETRY;
|
||||||
|
static const char* STATUS_FAILED;
|
||||||
|
static const char* STATUS_BAD_REQUEST;
|
||||||
|
static const char* STATUS_BAD_JSON;
|
||||||
|
|
||||||
|
Message() : status(STATUS_OK) { }
|
||||||
|
|
||||||
|
virtual ~Message() { }
|
||||||
|
|
||||||
|
virtual rapidjson::Value toJson(rapidjson::Document& doc) const;
|
||||||
|
|
||||||
|
virtual void fromJson(rapidjson::Value& val);
|
||||||
|
|
||||||
|
std::string status;
|
||||||
|
std::string error_details;
|
||||||
|
uint32_t rpc_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FullMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~FullMessage() { }
|
||||||
|
|
||||||
|
FullMessage(FullMessage&& rhs) noexcept : doc(std::move(rhs.doc)) { }
|
||||||
|
|
||||||
|
FullMessage(const std::string& json_string, bool request=false);
|
||||||
|
|
||||||
|
std::string getJson();
|
||||||
|
|
||||||
|
std::string getRequestType() const;
|
||||||
|
|
||||||
|
rapidjson::Value& getMessage();
|
||||||
|
|
||||||
|
rapidjson::Value getMessageCopy();
|
||||||
|
|
||||||
|
rapidjson::Value& getID();
|
||||||
|
|
||||||
|
void setID(rapidjson::Value& id);
|
||||||
|
|
||||||
|
cryptonote::rpc::error getError();
|
||||||
|
|
||||||
|
static FullMessage requestMessage(const std::string& request, Message* message);
|
||||||
|
static FullMessage requestMessage(const std::string& request, Message* message, rapidjson::Value& id);
|
||||||
|
|
||||||
|
static FullMessage responseMessage(Message* message);
|
||||||
|
static FullMessage responseMessage(Message* message, rapidjson::Value& id);
|
||||||
|
|
||||||
|
static FullMessage* timeoutMessage();
|
||||||
|
private:
|
||||||
|
|
||||||
|
FullMessage() = default;
|
||||||
|
|
||||||
|
FullMessage(const std::string& request, Message* message);
|
||||||
|
FullMessage(Message* message);
|
||||||
|
|
||||||
|
rapidjson::Document doc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// convenience functions for bad input
|
||||||
|
std::string BAD_REQUEST(const std::string& request);
|
||||||
|
std::string BAD_REQUEST(const std::string& request, rapidjson::Value& id);
|
||||||
|
|
||||||
|
std::string BAD_JSON(const std::string& error_details);
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace rpc
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
|
@ -0,0 +1,189 @@
|
||||||
|
// Copyright (c) 2016-2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "crypto/hash.h"
|
||||||
|
#include "cryptonote_basic/cryptonote_basic.h"
|
||||||
|
#include "ringct/rctSigs.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
struct block_with_transactions
|
||||||
|
{
|
||||||
|
cryptonote::block block;
|
||||||
|
std::unordered_map<crypto::hash, cryptonote::transaction> transactions;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<uint64_t> tx_output_indices;
|
||||||
|
|
||||||
|
typedef std::vector<tx_output_indices> block_output_indices;
|
||||||
|
|
||||||
|
struct transaction_info
|
||||||
|
{
|
||||||
|
cryptonote::transaction transaction;
|
||||||
|
bool in_pool;
|
||||||
|
uint64_t height;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct output_key_and_amount_index
|
||||||
|
{
|
||||||
|
uint64_t amount_index;
|
||||||
|
crypto::public_key key;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<output_key_and_amount_index> outputs_for_amount;
|
||||||
|
|
||||||
|
struct amount_with_random_outputs
|
||||||
|
{
|
||||||
|
uint64_t amount;
|
||||||
|
outputs_for_amount outputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct peer
|
||||||
|
{
|
||||||
|
uint64_t id;
|
||||||
|
uint32_t ip;
|
||||||
|
uint16_t port;
|
||||||
|
uint64_t last_seen;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tx_in_pool
|
||||||
|
{
|
||||||
|
cryptonote::transaction tx;
|
||||||
|
crypto::hash tx_hash;
|
||||||
|
uint64_t blob_size;
|
||||||
|
uint64_t fee;
|
||||||
|
crypto::hash max_used_block_hash;
|
||||||
|
uint64_t max_used_block_height;
|
||||||
|
bool kept_by_block;
|
||||||
|
crypto::hash last_failed_block_hash;
|
||||||
|
uint64_t last_failed_block_height;
|
||||||
|
uint64_t receive_time;
|
||||||
|
uint64_t last_relayed_time;
|
||||||
|
bool relayed;
|
||||||
|
bool do_not_relay;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::unordered_map<crypto::key_image, std::vector<crypto::hash> > key_images_with_tx_hashes;
|
||||||
|
|
||||||
|
struct output_amount_count
|
||||||
|
{
|
||||||
|
uint64_t amount;
|
||||||
|
uint64_t total_count;
|
||||||
|
uint64_t unlocked_count;
|
||||||
|
uint64_t recent_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct output_amount_and_index
|
||||||
|
{
|
||||||
|
uint64_t amount;
|
||||||
|
uint64_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct output_key_mask_unlocked
|
||||||
|
{
|
||||||
|
crypto::public_key key;
|
||||||
|
rct::key mask;
|
||||||
|
bool unlocked;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hard_fork_info
|
||||||
|
{
|
||||||
|
uint8_t version;
|
||||||
|
bool enabled;
|
||||||
|
uint32_t window;
|
||||||
|
uint32_t votes;
|
||||||
|
uint32_t threshold;
|
||||||
|
uint8_t voting;
|
||||||
|
uint32_t state;
|
||||||
|
uint64_t earliest_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
//required by JSON-RPC 2.0 spec
|
||||||
|
struct error
|
||||||
|
{
|
||||||
|
// not really using code, maybe later.
|
||||||
|
error() : use(false), code(1) { }
|
||||||
|
|
||||||
|
bool use; // do not serialize
|
||||||
|
|
||||||
|
int32_t code;
|
||||||
|
|
||||||
|
// not required by spec, but int error codes aren't perfect
|
||||||
|
std::string error_str;
|
||||||
|
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
//TODO: data member? not required, may want later.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BlockHeaderResponse
|
||||||
|
{
|
||||||
|
uint64_t major_version;
|
||||||
|
uint64_t minor_version;
|
||||||
|
uint64_t timestamp;
|
||||||
|
crypto::hash prev_id;
|
||||||
|
uint32_t nonce;
|
||||||
|
uint64_t height;
|
||||||
|
uint64_t depth;
|
||||||
|
crypto::hash hash;
|
||||||
|
uint64_t difficulty;
|
||||||
|
uint64_t reward;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DaemonInfo
|
||||||
|
{
|
||||||
|
uint64_t height;
|
||||||
|
uint64_t target_height;
|
||||||
|
uint64_t difficulty;
|
||||||
|
uint64_t target;
|
||||||
|
uint64_t tx_count;
|
||||||
|
uint64_t tx_pool_size;
|
||||||
|
uint64_t alt_blocks_count;
|
||||||
|
uint64_t outgoing_connections_count;
|
||||||
|
uint64_t incoming_connections_count;
|
||||||
|
uint64_t white_peerlist_size;
|
||||||
|
uint64_t grey_peerlist_size;
|
||||||
|
bool testnet;
|
||||||
|
crypto::hash top_block_hash;
|
||||||
|
uint64_t cumulative_difficulty;
|
||||||
|
uint64_t block_size_limit;
|
||||||
|
uint64_t start_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rpc
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright (c) 2016, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
class RpcHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual std::string handle(const std::string& request) = 0;
|
||||||
|
|
||||||
|
RpcHandler() { }
|
||||||
|
|
||||||
|
virtual ~RpcHandler() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // rpc
|
||||||
|
|
||||||
|
} // cryptonote
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright (c) 2016, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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 "zmq_server.h"
|
||||||
|
#include <boost/chrono/chrono.hpp>
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
ZmqServer::ZmqServer(RpcHandler& h) :
|
||||||
|
handler(h),
|
||||||
|
stop_signal(false),
|
||||||
|
running(false),
|
||||||
|
context(DEFAULT_NUM_ZMQ_THREADS) // TODO: make this configurable
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ZmqServer::~ZmqServer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZmqServer::serve()
|
||||||
|
{
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
zmq::message_t message;
|
||||||
|
|
||||||
|
if (!rep_socket)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("ZMQ RPC server reply socket is null");
|
||||||
|
}
|
||||||
|
while (rep_socket->recv(&message))
|
||||||
|
{
|
||||||
|
std::string message_string(reinterpret_cast<const char *>(message.data()), message.size());
|
||||||
|
|
||||||
|
MDEBUG(std::string("Received RPC request: \"") + message_string + "\"");
|
||||||
|
|
||||||
|
std::string response = handler.handle(message_string);
|
||||||
|
|
||||||
|
zmq::message_t reply(response.size());
|
||||||
|
memcpy((void *) reply.data(), response.c_str(), response.size());
|
||||||
|
|
||||||
|
rep_socket->send(reply);
|
||||||
|
MDEBUG(std::string("Sent RPC reply: \"") + response + "\"");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const boost::thread_interrupted& e)
|
||||||
|
{
|
||||||
|
MDEBUG("ZMQ Server thread interrupted.");
|
||||||
|
}
|
||||||
|
catch (const zmq::error_t& e)
|
||||||
|
{
|
||||||
|
MERROR(std::string("ZMQ error: ") + e.what());
|
||||||
|
}
|
||||||
|
boost::this_thread::interruption_point();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZmqServer::addIPCSocket(std::string address, std::string port)
|
||||||
|
{
|
||||||
|
MERROR("ZmqServer::addIPCSocket not yet implemented!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZmqServer::addTCPSocket(std::string address, std::string port)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::string addr_prefix("tcp://");
|
||||||
|
|
||||||
|
rep_socket.reset(new zmq::socket_t(context, ZMQ_REP));
|
||||||
|
|
||||||
|
rep_socket->setsockopt(ZMQ_RCVTIMEO, DEFAULT_RPC_RECV_TIMEOUT_MS);
|
||||||
|
|
||||||
|
std::string bind_address = addr_prefix + address + std::string(":") + port;
|
||||||
|
rep_socket->bind(bind_address.c_str());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
MERROR(std::string("Error creating ZMQ Socket: ") + e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZmqServer::run()
|
||||||
|
{
|
||||||
|
running = true;
|
||||||
|
run_thread = boost::thread(boost::bind(&ZmqServer::serve, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZmqServer::stop()
|
||||||
|
{
|
||||||
|
if (!running) return;
|
||||||
|
|
||||||
|
stop_signal = true;
|
||||||
|
|
||||||
|
run_thread.interrupt();
|
||||||
|
run_thread.join();
|
||||||
|
|
||||||
|
running = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
||||||
|
|
||||||
|
} // namespace rpc
|
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright (c) 2016, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/thread/thread.hpp>
|
||||||
|
#include <zmq.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "common/command_line.h"
|
||||||
|
|
||||||
|
#include "rpc_handler.h"
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
|
||||||
|
static constexpr int DEFAULT_NUM_ZMQ_THREADS = 1;
|
||||||
|
static constexpr int DEFAULT_RPC_RECV_TIMEOUT_MS = 1000;
|
||||||
|
|
||||||
|
class ZmqServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ZmqServer(RpcHandler& h);
|
||||||
|
|
||||||
|
~ZmqServer();
|
||||||
|
|
||||||
|
static void init_options(boost::program_options::options_description& desc);
|
||||||
|
|
||||||
|
void serve();
|
||||||
|
|
||||||
|
bool addIPCSocket(std::string address, std::string port);
|
||||||
|
bool addTCPSocket(std::string address, std::string port);
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
RpcHandler& handler;
|
||||||
|
|
||||||
|
volatile bool stop_signal;
|
||||||
|
volatile bool running;
|
||||||
|
|
||||||
|
zmq::context_t context;
|
||||||
|
|
||||||
|
boost::thread run_thread;
|
||||||
|
|
||||||
|
std::unique_ptr<zmq::socket_t> rep_socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
||||||
|
|
||||||
|
} // namespace rpc
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Copyright (c) 2016, The Monero Project
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
# used to endorse or promote products derived from this software without specific
|
||||||
|
# prior written permission.
|
||||||
|
#
|
||||||
|
# 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 HOLDER 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.
|
||||||
|
|
||||||
|
set(serialization_sources
|
||||||
|
json_object.cpp)
|
||||||
|
|
||||||
|
set(serialization_headers)
|
||||||
|
|
||||||
|
set(serialization_private_headers
|
||||||
|
json_object.h)
|
||||||
|
|
||||||
|
monero_private_headers(serialization
|
||||||
|
${serialization_private_headers})
|
||||||
|
monero_add_library(serialization
|
||||||
|
${serialization_sources}
|
||||||
|
${serialization_headers}
|
||||||
|
${serialization_private_headers})
|
||||||
|
target_link_libraries(serialization
|
||||||
|
LINK_PRIVATE
|
||||||
|
cryptonote_core
|
||||||
|
cryptonote_protocol
|
||||||
|
${Boost_CHRONO_LIBRARY}
|
||||||
|
${Boost_REGEX_LIBRARY}
|
||||||
|
${Boost_SYSTEM_LIBRARY}
|
||||||
|
${Boost_THREAD_LIBRARY}
|
||||||
|
${EXTRA_LIBRARIES})
|
||||||
|
add_dependencies(serialization
|
||||||
|
version)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,371 @@
|
||||||
|
// Copyright (c) 2016-2017, The Monero Project
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// 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 HOLDER 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "cryptonote_basic/cryptonote_basic.h"
|
||||||
|
#include "rpc/message_data_structs.h"
|
||||||
|
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||||
|
#include "common/sfinae_helpers.h"
|
||||||
|
|
||||||
|
#define OBJECT_HAS_MEMBER_OR_THROW(val, key) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (!val.HasMember(key)) \
|
||||||
|
{ \
|
||||||
|
throw cryptonote::json::MISSING_KEY(key); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define INSERT_INTO_JSON_OBJECT(jsonVal, doc, key, source) \
|
||||||
|
rapidjson::Value key##Val; \
|
||||||
|
cryptonote::json::toJsonValue(doc, source, key##Val); \
|
||||||
|
jsonVal.AddMember(#key, key##Val, doc.GetAllocator());
|
||||||
|
|
||||||
|
#define GET_FROM_JSON_OBJECT(source, dst, key) \
|
||||||
|
OBJECT_HAS_MEMBER_OR_THROW(source, #key) \
|
||||||
|
decltype(dst) dstVal##key; \
|
||||||
|
cryptonote::json::fromJsonValue(source[#key], dstVal##key); \
|
||||||
|
dst = dstVal##key;
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace json
|
||||||
|
{
|
||||||
|
|
||||||
|
struct JSON_ERROR : public std::exception
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
JSON_ERROR() { }
|
||||||
|
std::string m;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~JSON_ERROR() { }
|
||||||
|
|
||||||
|
const char* what() const throw()
|
||||||
|
{
|
||||||
|
return m.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MISSING_KEY : public JSON_ERROR
|
||||||
|
{
|
||||||
|
MISSING_KEY(const char* key)
|
||||||
|
{
|
||||||
|
m = std::string("Key \"") + key + "\" missing from object.";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WRONG_TYPE : public JSON_ERROR
|
||||||
|
{
|
||||||
|
WRONG_TYPE(const char* type)
|
||||||
|
{
|
||||||
|
m = std::string("Json value has incorrect type, expected: ") + type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BAD_INPUT : public JSON_ERROR
|
||||||
|
{
|
||||||
|
BAD_INPUT()
|
||||||
|
{
|
||||||
|
m = "An item failed to convert from json object to native object";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PARSE_FAIL : public JSON_ERROR
|
||||||
|
{
|
||||||
|
PARSE_FAIL()
|
||||||
|
{
|
||||||
|
m = "Failed to parse the json request";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
inline constexpr bool is_to_hex()
|
||||||
|
{
|
||||||
|
return std::is_pod<Type>() && !std::is_integral<Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// POD to json value
|
||||||
|
template <class Type>
|
||||||
|
typename std::enable_if<is_to_hex<Type>()>::type toJsonValue(rapidjson::Document& doc, const Type& pod, rapidjson::Value& value)
|
||||||
|
{
|
||||||
|
value = rapidjson::Value(epee::string_tools::pod_to_hex(pod).c_str(), doc.GetAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Type>
|
||||||
|
typename std::enable_if<is_to_hex<Type>()>::type fromJsonValue(const rapidjson::Value& val, Type& t)
|
||||||
|
{
|
||||||
|
if (!val.IsString())
|
||||||
|
{
|
||||||
|
throw WRONG_TYPE("string");
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: handle failure to convert hex string to POD type
|
||||||
|
bool success = epee::string_tools::hex_to_pod(val.GetString(), t);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
throw BAD_INPUT();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const std::string& i, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, std::string& str);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, bool i, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, bool& b);
|
||||||
|
|
||||||
|
// integers overloads for toJsonValue are not needed for standard promotions
|
||||||
|
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, unsigned char& i);
|
||||||
|
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, signed char& i);
|
||||||
|
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, char& i);
|
||||||
|
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, unsigned short& i);
|
||||||
|
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, short& i);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const unsigned i, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, unsigned& i);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const int, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, int& i);
|
||||||
|
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const unsigned long long i, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, unsigned long long& i);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const long long i, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, long long& i);
|
||||||
|
|
||||||
|
inline void toJsonValue(rapidjson::Document& doc, const unsigned long i, rapidjson::Value& val) {
|
||||||
|
toJsonValue(doc, static_cast<unsigned long long>(i), val);
|
||||||
|
}
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, unsigned long& i);
|
||||||
|
|
||||||
|
inline void toJsonValue(rapidjson::Document& doc, const long i, rapidjson::Value& val) {
|
||||||
|
toJsonValue(doc, static_cast<long long>(i), val);
|
||||||
|
}
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, long& i);
|
||||||
|
|
||||||
|
// end integers
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::transaction& tx, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::block& b, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::block& b);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_v& txin, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_v& txin);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_gen& txin, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_gen& txin);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_script& txin, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_script& txin);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_scripthash& txin, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash& txin);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_key& txin, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_key& txin);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_target_v& txout, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_target_v& txout);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_script& txout, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_script& txout);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_scripthash& txout, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_scripthash& txout);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_key& txout, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_key& txout);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::tx_out& txout, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_out& txout);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::connection_info& info, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::connection_info& info);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::block_complete_entry& blk, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::block_complete_entry& blk);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::block_with_transactions& blk, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::block_with_transactions& blk);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::transaction_info& tx_info, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::transaction_info& tx_info);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_key_and_amount_index& out, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_and_amount_index& out);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::amount_with_random_outputs& out, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::amount_with_random_outputs& out);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::peer& peer, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::peer& peer);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::tx_in_pool& tx, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::hard_fork_info& info, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::hard_fork_info& info);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_amount_count& out, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_count& out);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_amount_and_index& out, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_and_index& out);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_key_mask_unlocked& out, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_mask_unlocked& out);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::error& err, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::BlockHeaderResponse& response, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResponse& response);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const rct::rctSig& i, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& i, rct::rctSig& sig);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const rct::ctkey& key, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, rct::ctkey& key);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const rct::ecdhTuple& tuple, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, rct::ecdhTuple& tuple);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const rct::rctSigPrunable& sig, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, rct::rctSigPrunable& sig);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const rct::rangeSig& sig, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const rct::boroSig& sig, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const rct::mgSig& sig, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::DaemonInfo& info, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info);
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Document& doc, const Map& map, rapidjson::Value& val);
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type fromJsonValue(const rapidjson::Value& val, Map& map);
|
||||||
|
|
||||||
|
template <typename Vec>
|
||||||
|
typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Document& doc, const Vec &vec, rapidjson::Value& val);
|
||||||
|
|
||||||
|
template <typename Vec>
|
||||||
|
typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type fromJsonValue(const rapidjson::Value& val, Vec& vec);
|
||||||
|
|
||||||
|
|
||||||
|
// ideally would like to have the below functions in the .cpp file, but
|
||||||
|
// unfortunately because of how templates work they have to be here.
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Document& doc, const Map& map, rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
val.SetObject();
|
||||||
|
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
for (const auto& i : map)
|
||||||
|
{
|
||||||
|
rapidjson::Value k;
|
||||||
|
rapidjson::Value m;
|
||||||
|
toJsonValue(doc, i.first, k);
|
||||||
|
toJsonValue(doc, i.second, m);
|
||||||
|
val.AddMember(k, m, al);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type fromJsonValue(const rapidjson::Value& val, Map& map)
|
||||||
|
{
|
||||||
|
if (!val.IsObject())
|
||||||
|
{
|
||||||
|
throw WRONG_TYPE("json object");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto itr = val.MemberBegin();
|
||||||
|
|
||||||
|
while (itr != val.MemberEnd())
|
||||||
|
{
|
||||||
|
typename Map::key_type k;
|
||||||
|
typename Map::mapped_type m;
|
||||||
|
fromJsonValue(itr->name, k);
|
||||||
|
fromJsonValue(itr->value, m);
|
||||||
|
map.emplace(k, m);
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Vec>
|
||||||
|
typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type toJsonValue(rapidjson::Document& doc, const Vec &vec, rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
val.SetArray();
|
||||||
|
|
||||||
|
for (const auto& t : vec)
|
||||||
|
{
|
||||||
|
rapidjson::Value v;
|
||||||
|
toJsonValue(doc, t, v);
|
||||||
|
val.PushBack(v, doc.GetAllocator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Vec>
|
||||||
|
typename std::enable_if<sfinae::is_vector_like<Vec>::value, void>::type fromJsonValue(const rapidjson::Value& val, Vec& vec)
|
||||||
|
{
|
||||||
|
if (!val.IsArray())
|
||||||
|
{
|
||||||
|
throw WRONG_TYPE("json array");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (rapidjson::SizeType i=0; i < val.Size(); i++)
|
||||||
|
{
|
||||||
|
typename Vec::value_type v;
|
||||||
|
fromJsonValue(val[i], v);
|
||||||
|
vec.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace json
|
||||||
|
|
||||||
|
} // namespace cryptonote
|
Loading…
Reference in New Issue