aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--README.md4
-rw-r--r--contrib/epee/include/net/http_protocol_handler.inl4
-rw-r--r--contrib/epee/include/net/http_server_handlers_map2.h4
-rw-r--r--contrib/epee/include/net/levin_protocol_handler_async.h24
-rw-r--r--contrib/epee/include/storages/parserse_base_utils.h59
-rw-r--r--contrib/epee/include/string_tools.h24
-rw-r--r--contrib/gitian/README.md116
-rw-r--r--src/cryptonote_config.h2
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp2
-rw-r--r--src/daemon/rpc_command_executor.cpp57
-rw-r--r--src/p2p/net_node.inl5
-rw-r--r--src/p2p/net_peerlist.h3
-rw-r--r--src/rpc/CMakeLists.txt2
-rw-r--r--src/rpc/core_rpc_server.cpp21
-rw-r--r--src/rpc/core_rpc_server.h3
-rw-r--r--src/simplewallet/simplewallet.cpp2
-rw-r--r--src/wallet/api/wallet.cpp25
-rw-r--r--src/wallet/wallet2.cpp15
-rwxr-xr-xtests/functional_tests/blockchain.py12
-rwxr-xr-xtests/functional_tests/functional_tests_rpc.py2
-rwxr-xr-xtests/functional_tests/wallet_address.py5
-rw-r--r--tests/unit_tests/epee_utils.cpp17
-rw-r--r--tests/unit_tests/output_selection.cpp4
-rw-r--r--utils/python-rpc/framework/daemon.py11
25 files changed, 322 insertions, 104 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b150a8998..59384d180 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1003,6 +1003,7 @@ endif()
add_subdirectory(contrib)
add_subdirectory(src)
+find_package(PythonInterp)
if(BUILD_TESTS)
message(STATUS "Building tests")
add_subdirectory(tests)
@@ -1047,5 +1048,3 @@ option(INSTALL_VENDORED_LIBUNBOUND "Install libunbound binary built from source
CHECK_C_COMPILER_FLAG(-std=c11 HAVE_C11)
-
-find_package(PythonInterp)
diff --git a/README.md b/README.md
index 10c0daa28..24975ed4f 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers.
- [Research](#research)
- [Announcements](#announcements)
- [Translations](#translations)
- - [Build](#build)
+ - [Build Status](#build-status)
- [IMPORTANT](#important)
- [Coverage](#coverage)
- [Introduction](#introduction)
@@ -55,7 +55,7 @@ The CLI wallet is available in different languages. If you want to help translat
If you need help/support/info about translations, contact the localization workgroup. You can find the complete list of contacts on the repository of the workgroup: [monero-translations](https://github.com/monero-ecosystem/monero-translations#contacts).
-## Build
+## Build Status
### IMPORTANT
diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl
index ae8e43477..790d0f3b1 100644
--- a/contrib/epee/include/net/http_protocol_handler.inl
+++ b/contrib/epee/include/net/http_protocol_handler.inl
@@ -577,6 +577,10 @@ namespace net_utils
if (query_info.m_http_method != http::http_method_options)
{
res = handle_request(query_info, response);
+ if (response.m_response_code == 500)
+ {
+ m_want_close = true; // close on all "Internal server error"s
+ }
}
else
{
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
index 4b2053091..07ed8157b 100644
--- a/contrib/epee/include/net/http_server_handlers_map2.h
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
@@ -71,7 +71,7 @@
MINFO(m_conn_context << "calling " << s_pattern); \
if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), &m_conn_context)) \
{ \
- LOG_ERROR("Failed to " << #callback_f << "()"); \
+ MERROR(m_conn_context << "Failed to " << #callback_f << "()"); \
response_info.m_response_code = 500; \
response_info.m_response_comment = "Internal Server Error"; \
return true; \
@@ -99,7 +99,7 @@
MINFO(m_conn_context << "calling " << s_pattern); \
if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), &m_conn_context)) \
{ \
- LOG_ERROR("Failed to " << #callback_f << "()"); \
+ MERROR(m_conn_context << "Failed to " << #callback_f << "()"); \
response_info.m_response_code = 500; \
response_info.m_response_comment = "Internal Server Error"; \
return true; \
diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h
index 116b3ace1..8d7ffb2c2 100644
--- a/contrib/epee/include/net/levin_protocol_handler_async.h
+++ b/contrib/epee/include/net/levin_protocol_handler_async.h
@@ -99,6 +99,8 @@ public:
template<class callback_t>
bool for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb);
size_t get_connections_count();
+ size_t get_out_connections_count();
+ size_t get_in_connections_count();
void set_handler(levin_commands_handler<t_connection_context>* handler, void (*destroy)(levin_commands_handler<t_connection_context>*) = NULL);
async_protocol_handler_config():m_pcommands_handler(NULL), m_pcommands_handler_destroy(NULL), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE), m_invoke_timeout(LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
@@ -882,6 +884,28 @@ size_t async_protocol_handler_config<t_connection_context>::get_connections_coun
}
//------------------------------------------------------------------------------------------
template<class t_connection_context>
+size_t async_protocol_handler_config<t_connection_context>::get_out_connections_count()
+{
+ CRITICAL_REGION_LOCAL(m_connects_lock);
+ size_t count = 0;
+ for (const auto &c: m_connects)
+ if (!c.second->m_connection_context.m_is_income)
+ ++count;
+ return count;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+size_t async_protocol_handler_config<t_connection_context>::get_in_connections_count()
+{
+ CRITICAL_REGION_LOCAL(m_connects_lock);
+ size_t count = 0;
+ for (const auto &c: m_connects)
+ if (c.second->m_connection_context.m_is_income)
+ ++count;
+ return count;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
void async_protocol_handler_config<t_connection_context>::set_handler(levin_commands_handler<t_connection_context>* handler, void (*destroy)(levin_commands_handler<t_connection_context>*))
{
if (m_pcommands_handler && m_pcommands_handler_destroy)
diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h
index b5c4138c5..fe53628a5 100644
--- a/contrib/epee/include/storages/parserse_base_utils.h
+++ b/contrib/epee/include/storages/parserse_base_utils.h
@@ -31,6 +31,9 @@
#include <algorithm>
#include <boost/utility/string_ref.hpp>
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "serialization"
+
namespace epee
{
namespace misc_utils
@@ -62,6 +65,26 @@ namespace misc_utils
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
+ static const constexpr unsigned char isx[256] =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+
inline bool isspace(char c)
{
return lut[(uint8_t)c] & 8;
@@ -162,6 +185,42 @@ namespace misc_utils
val.push_back('\\');break;
case '/': //Slash character
val.push_back('/');break;
+ case 'u': //Unicode code point
+ if (buf_end - it < 4)
+ {
+ ASSERT_MES_AND_THROW("Invalid Unicode escape sequence");
+ }
+ else
+ {
+ uint32_t dst = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ const unsigned char tmp = isx[(int)*++it];
+ CHECK_AND_ASSERT_THROW_MES(tmp != 0xff, "Bad Unicode encoding");
+ dst = dst << 4 | tmp;
+ }
+ // encode as UTF-8
+ if (dst <= 0x7f)
+ {
+ val.push_back(dst);
+ }
+ else if (dst <= 0x7ff)
+ {
+ val.push_back(0xc0 | (dst >> 6));
+ val.push_back(0x80 | (dst & 0x3f));
+ }
+ else if (dst <= 0xffff)
+ {
+ val.push_back(0xe0 | (dst >> 12));
+ val.push_back(0x80 | ((dst >> 6) & 0x3f));
+ val.push_back(0x80 | (dst & 0x3f));
+ }
+ else
+ {
+ ASSERT_MES_AND_THROW("Unicode code point is out or range");
+ }
+ }
+ break;
default:
val.push_back(*it);
LOG_PRINT_L0("Unknown escape sequence :\"\\" << *it << "\"");
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
index da47b7d55..1be5eb5e1 100644
--- a/contrib/epee/include/string_tools.h
+++ b/contrib/epee/include/string_tools.h
@@ -59,26 +59,6 @@
#pragma comment (lib, "Rpcrt4.lib")
#endif
-static const constexpr unsigned char isx[256] =
-{
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
-
namespace epee
{
namespace string_tools
@@ -99,10 +79,10 @@ namespace string_tools
for(size_t i = 0; i < s.size(); i += 2)
{
int tmp = *src++;
- tmp = isx[tmp];
+ tmp = epee::misc_utils::parse::isx[tmp];
if (tmp == 0xff) return false;
int t2 = *src++;
- t2 = isx[t2];
+ t2 = epee::misc_utils::parse::isx[t2];
if (t2 == 0xff) return false;
*dst++ = (tmp << 4) | t2;
}
diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md
index 3fc26354c..32aee5f56 100644
--- a/contrib/gitian/README.md
+++ b/contrib/gitian/README.md
@@ -26,12 +26,16 @@ Preparing the Gitian builder host
The first step is to prepare the host environment that will be used to perform the Gitian builds.
This guide explains how to set up the environment, and how to start the builds.
-Gitian offers to build with either `kvm`, `docker` or `lxc`. The default build
-path chosen is `lxc`, but its setup is more complicated. You need to be logged in as the `gitianuser`.
-If this user does not exist yet on your system, create it. Gitian can use
-either kvm, lxc or docker as a host environment. This documentation will show
-how to build with lxc and docker. While the docker setup is easy, the lxc setup
-is more involved.
+
+* Gitian host OS should be Ubuntu 18.04 "Bionic Beaver". If you are on a mac or windows for example, you can run it in a VM but will be slower.
+
+* Gitian gives you the option of using any of 3 different virtualization tools: `kvm`, `docker` or `lxc`. This documentation will only show how to build with `lxc` and `docker` (documentation for `kvm` is welcome). Building with `lxc` is the default, but is more complicated, so we recommend docker your first time.
+
+
+## Create the gitianuser account
+
+You need to create a new user called `gitianuser` and be logged in as that user. The user needs `sudo` access.
+
LXC
---
@@ -76,10 +80,17 @@ This setup is required to enable networking in the container.
Docker
------
-Building in docker does not require much setup. Install docker on your host, then type the following:
+Prepare for building with docker:
```bash
-sudo apt-get install git make curl
+sudo apt-get install git make curl docker.io
+```
+
+Consider adding `gitianuser` to the `docker` group after reading about [the security implications](https://docs.docker.com/v17.09/engine/installation/linux/linux-postinstall/):
+
+```bash
+sudo groupadd docker
+sudo usermod -aG docker gitianuser
```
Optionally add yourself to the docker group. Note that this will give docker root access to your system.
@@ -88,7 +99,7 @@ Optionally add yourself to the docker group. Note that this will give docker roo
sudo usermod -aG docker gitianuser
```
-Manual and Building
+Manual Building
-------------------
The instructions below use the automated script [gitian-build.py](gitian-build.py) which only works in Ubuntu.
@@ -109,66 +120,95 @@ The `gitian-build.py` script will checkout different release tags, so it's best
cp monero/contrib/gitian/gitian-build.py .
```
-Setup the required environment, you only need to do this once:
+### Setup the required environment
+
+Setup for LXC:
```bash
-./gitian-build.py --setup fluffypony v0.14.0
+GH_USER=fluffypony
+VERSION=v0.14.1.0
+
+./gitian-build.py --setup $GH_USER $VERSION
```
-Where `fluffypony` is your Github name and `v0.14.0` is the version tag you want to build.
-If you are using docker, run it with:
+Where `GH_USER` is your Github user name and `VERSION` is the version tag you want to build.
+
+Setup for docker:
```bash
-./gitian-build.py --setup --docker fluffypony v0.14.0
+./gitian-build.py --setup --docker $GH_USER $VERSION
```
-While gitian and this build script does provide a way for you to sign the build directly, it is recommended to sign in a seperate step.
-This script is only there for convenience. Seperate steps for building can still be taken.
+While gitian and this build script does provide a way for you to sign the build directly, it is recommended to sign in a separate step. This script is only there for convenience. Separate steps for building can still be taken.
In order to sign gitian builds on your host machine, which has your PGP key,
-fork the gitian.sigs repository and clone it on your host machine,
+fork the [gitian.sigs repository](https://github.com/monero-project/gitian.sigs) and clone it on your host machine,
or pass the signed assert file back to your build machine.
```bash
git clone git@github.com:monero-project/gitian.sigs.git
-git remote add fluffypony git@github.com:fluffypony/gitian.sigs.git
+git remote add $GH_USER git@github.com:$GH_USER/gitian.sigs.git
```
-Build Binaries
------------------------------
-To build the most recent tag (pass in `--docker` after setting up with docker):
+Build the binaries
+------------------
+
+**Note:** if you intend to build MacOS binaries, please follow [these instructions](https://github.com/bitcoin-core/docs/blob/master/gitian-building/gitian-building-mac-os-sdk.md) to get the required SDK.
+
+To build the most recent tag (pass in `--docker` if using docker):
```bash
-./gitian-build.py --detach-sign --no-commit -b fluffypony v0.14.0
+./gitian-build.py --detach-sign --no-commit --build $GH_USER $VERSION
```
-To speed up the build, use `-j 5 -m 5000` as the first arguments, where `5` is the number of CPU's you allocated to the VM plus one, and 5000 is a little bit less than then the MB's of RAM you allocated. If there is memory corruption on your machine, try to tweak these values.
+To speed up the build, use `-j 5 --memory 5000` as the first arguments, where `5` is the number of CPU's you allocated to the VM plus one, and 5000 is a little bit less than then the MB's of RAM you allocated. If there is memory corruption on your machine, try to tweak these values.
-If all went well, this produces a number of (uncommited) `.assert` files in the gitian.sigs repository.
+If all went well, this produces a number of (uncommitted) `.assert` files in the gitian.sigs directory.
-If you do detached, offline signing, you need to copy these uncommited changes to your host machine, where you can sign them. For example:
+Checking your work
+------------------
+
+Take a look in the assert files and note the SHA256 checksums listed there. eg for `v0.14.1.0` you should get this checksum:
+
+```
+2b95118f53d98d542a85f8732b84ba13b3cd20517ccb40332b0edd0ddf4f8c62 monero-x86_64-linux-gnu.tar.gz
+```
+
+You should verify that this is really the checksum you get on that file you built. You can also look in the gitian.sigs repo and / or [getmonero.org release checksums](https://web.getmonero.org/downloads/hashes.txt) to see if others got the same checksum for the same version tag. If there is ever a mismatch -- **STOP! Something is wrong**. Contact others on IRC / github to figure out what is going on.
+
+
+Signing assert files
+--------------------
+
+If you chose to do detached signing using `--detach-sign` above (recommended), you need to copy these uncommitted changes to your host machine, then sign them using your gpg key like so:
```bash
-export NAME=fluffypony
-export VERSION=v0.14.0
-gpg --output $VERSION-linux/$NAME/monero-linux-$VERSION-build.assert.sig --detach-sign $VERSION-linux/$NAME/monero-linux-$VERSION-build.assert
-gpg --output $VERSION-osx-unsigned/$NAME/monero-osx-$VERSION-build.assert.sig --detach-sign $VERSION-osx-unsigned/$NAME/monero-osx-$VERSION-build.assert
-gpg --output $VERSION-win-unsigned/$NAME/monero-win-$VERSION-build.assert.sig --detach-sign $VERSION-win-unsigned/$NAME/monero-win-$VERSION-build.assert
+GH_USER=fluffypony
+VERSION=v0.14.1.0
+
+gpg --detach-sign ${VERSION}-linux/${GH_USER}/monero-linux-*-build.assert
+gpg --detach-sign ${VERSION}-win/${GH_USER}/monero-win-*-build.assert
+gpg --detach-sign ${VERSION}-osx/${GH_USER}/monero-osx-*-build.assert
```
+<!-- TODO: Replace * above with ${VERSION} once gitian builds correct file name -->
+
+This will create a `.sig` file for each `.assert` file above (2 files for each platform).
+
+
+Submitting your signed assert files
+-----------------------------------
Make a pull request (both the `.assert` and `.assert.sig` files) to the
[monero-project/gitian.sigs](https://github.com/monero-project/gitian.sigs/) repository:
```bash
-git checkout -b v0.14.0
-git commit -S -a -m "Add $NAME v0.14.0"
-git push --set-upstream $NAME v0.14.0
+git checkout -b $VERSION
+# add your assert and sig files...
+git commit -S -a -m "Add $GH_USER $VERSION"
+git push --set-upstream $GH_USER $VERSION
```
-```bash
-gpg --detach-sign ${VERSION}-linux/${SIGNER}/monero-linux-*-build.assert
-gpg --detach-sign ${VERSION}-win-unsigned/${SIGNER}/monero-win-*-build.assert
-gpg --detach-sign ${VERSION}-osx-unsigned/${SIGNER}/monero-osx-*-build.assert
-```
+**Note:** Please ensure your gpg public key is available to check signatures by adding it to the [gitian.sigs/gitian-pubkeys/](https://github.com/monero-project/gitian.sigs/tree/master/gitian-pubkeys) directory in a pull request.
+
More Build Options
------------------
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index fc718c4f7..b68bb41e1 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -128,6 +128,8 @@
#define P2P_SUPPORT_FLAG_FLUFFY_BLOCKS 0x01
#define P2P_SUPPORT_FLAGS P2P_SUPPORT_FLAG_FLUFFY_BLOCKS
+#define RPC_IP_FAILS_BEFORE_BLOCK 3
+
#define ALLOW_DEBUG_COMMANDS
#define CRYPTONOTE_NAME "bitmonero"
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 2ebd99904..a3a92ab60 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1844,7 +1844,7 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::check_block_rate()
{
- if (m_offline || m_nettype == FAKECHAIN || m_target_blockchain_height > get_current_blockchain_height())
+ if (m_offline || m_nettype == FAKECHAIN || m_target_blockchain_height > get_current_blockchain_height() || m_target_blockchain_height == 0)
{
MDEBUG("Not checking block rate, offline or syncing");
return true;
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 309e5c8dd..dbf0409e5 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -35,6 +35,7 @@
#include "daemon/rpc_command_executor.h"
#include "rpc/core_rpc_server_commands_defs.h"
#include "cryptonote_core/cryptonote_core.h"
+#include "cryptonote_basic/difficulty.h"
#include "cryptonote_basic/hardfork.h"
#include <boost/format.hpp>
#include <ctime>
@@ -89,7 +90,7 @@ namespace {
<< "height: " << boost::lexical_cast<std::string>(header.height) << std::endl
<< "depth: " << boost::lexical_cast<std::string>(header.depth) << std::endl
<< "hash: " << header.hash << std::endl
- << "difficulty: " << boost::lexical_cast<std::string>(header.difficulty) << std::endl
+ << "difficulty: " << header.wide_difficulty << std::endl
<< "POW hash: " << header.pow_hash << std::endl
<< "block size: " << header.block_size << std::endl
<< "block weight: " << header.block_weight << std::endl
@@ -350,19 +351,41 @@ bool t_rpc_command_executor::show_difficulty() {
tools::success_msg_writer() << "BH: " << res.height
<< ", TH: " << res.top_block_hash
- << ", DIFF: " << res.difficulty
- << ", CUM_DIFF: " << res.cumulative_difficulty
- << ", HR: " << res.difficulty / res.target << " H/s";
+ << ", DIFF: " << res.wide_difficulty
+ << ", CUM_DIFF: " << res.wide_cumulative_difficulty
+ << ", HR: " << cryptonote::difficulty_type(res.wide_difficulty) / res.target << " H/s";
return true;
}
-static std::string get_mining_speed(uint64_t hr)
+static void get_metric_prefix(cryptonote::difficulty_type hr, double& hr_d, char& prefix)
{
- if (hr>1e9) return (boost::format("%.2f GH/s") % (hr/1e9)).str();
- if (hr>1e6) return (boost::format("%.2f MH/s") % (hr/1e6)).str();
- if (hr>1e3) return (boost::format("%.2f kH/s") % (hr/1e3)).str();
- return (boost::format("%.0f H/s") % hr).str();
+ if (hr < 1000)
+ {
+ prefix = 0;
+ return;
+ }
+ static const char metric_prefixes[4] = { 'k', 'M', 'G', 'T' };
+ for (size_t i = 0; i < sizeof(metric_prefixes); ++i)
+ {
+ if (hr < 1000000)
+ {
+ hr_d = hr.convert_to<double>() / 1000;
+ prefix = metric_prefixes[i];
+ return;
+ }
+ hr /= 1000;
+ }
+ prefix = 0;
+}
+
+static std::string get_mining_speed(cryptonote::difficulty_type hr)
+{
+ double hr_d;
+ char prefix;
+ get_metric_prefix(hr, hr_d, prefix);
+ if (prefix == 0) return (boost::format("%.0f H/s") % hr).str();
+ return (boost::format("%.2f %cH/s") % hr_d % prefix).str();
}
static std::string get_fork_extra_info(uint64_t t, uint64_t now, uint64_t block_time)
@@ -479,7 +502,7 @@ bool t_rpc_command_executor::show_status() {
% (ires.testnet ? "testnet" : ires.stagenet ? "stagenet" : "mainnet")
% bootstrap_msg
% (!has_mining_info ? "mining info unavailable" : mining_busy ? "syncing" : mres.active ? ( ( mres.is_background_mining_enabled ? "smart " : "" ) + std::string("mining at ") + get_mining_speed(mres.speed)) : "not mining")
- % get_mining_speed(ires.difficulty / ires.target)
+ % get_mining_speed(cryptonote::difficulty_type(ires.wide_difficulty) / ires.target)
% (unsigned)hfres.version
% get_fork_extra_info(hfres.earliest_height, net_height, ires.target)
% (hfres.state == cryptonote::HardFork::Ready ? "up to date" : hfres.state == cryptonote::HardFork::UpdateNeeded ? "update needed" : "out of date, likely forked")
@@ -742,7 +765,7 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u
<< ", size: " << header.block_size << ", weight: " << header.block_weight << " (long term " << header.long_term_weight << "), transactions: " << header.num_txes << std::endl
<< "major version: " << (unsigned)header.major_version << ", minor version: " << (unsigned)header.minor_version << std::endl
<< "block id: " << header.hash << ", previous block id: " << header.prev_hash << std::endl
- << "difficulty: " << header.difficulty << ", nonce " << header.nonce << ", reward " << cryptonote::print_money(header.reward) << std::endl;
+ << "difficulty: " << header.wide_difficulty << ", nonce " << header.nonce << ", reward " << cryptonote::print_money(header.reward) << std::endl;
first = false;
}
@@ -1874,7 +1897,7 @@ bool t_rpc_command_executor::alt_chain_info(const std::string &tip, size_t above
const auto &chain = chains[idx];
const uint64_t start_height = (chain.height - chain.length + 1);
tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
- << " deep), diff " << chain.difficulty << ": " << chain.block_hash;
+ << " deep), diff " << chain.wide_difficulty << ": " << chain.block_hash;
}
}
else
@@ -1887,7 +1910,7 @@ bool t_rpc_command_executor::alt_chain_info(const std::string &tip, size_t above
tools::success_msg_writer() << "Found alternate chain with tip " << tip;
uint64_t start_height = (chain.height - chain.length + 1);
tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
- << " deep), diff " << chain.difficulty << ":";
+ << " deep), diff " << chain.wide_difficulty << ":";
for (const std::string &block_id: chain.block_hashes)
tools::msg_writer() << " " << block_id;
tools::msg_writer() << "Chain parent on main chain: " << chain.main_chain_parent_block;
@@ -1991,7 +2014,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks)
}
}
- tools::msg_writer() << "Height: " << ires.height << ", diff " << ires.difficulty << ", cum. diff " << ires.cumulative_difficulty
+ tools::msg_writer() << "Height: " << ires.height << ", diff " << ires.wide_difficulty << ", cum. diff " << ires.wide_cumulative_difficulty
<< ", target " << ires.target << " sec" << ", dyn fee " << cryptonote::print_money(feres.fee) << "/" << (hfres.enabled ? "byte" : "kB");
if (nblocks > 0)
@@ -2018,7 +2041,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks)
}
}
- double avgdiff = 0;
+ cryptonote::difficulty_type avgdiff = 0;
double avgnumtxes = 0;
double avgreward = 0;
std::vector<uint64_t> weights;
@@ -2027,7 +2050,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks)
std::vector<unsigned> major_versions(256, 0), minor_versions(256, 0);
for (const auto &bhr: bhres.headers)
{
- avgdiff += bhr.difficulty;
+ avgdiff += cryptonote::difficulty_type(bhr.wide_difficulty);
avgnumtxes += bhr.num_txes;
avgreward += bhr.reward;
weights.push_back(bhr.block_weight);
@@ -2042,7 +2065,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks)
avgnumtxes /= nblocks;
avgreward /= nblocks;
uint64_t median_block_weight = epee::misc_utils::median(weights);
- tools::msg_writer() << "Last " << nblocks << ": avg. diff " << (uint64_t)avgdiff << ", " << (latest - earliest) / nblocks << " avg sec/block, avg num txes " << avgnumtxes
+ tools::msg_writer() << "Last " << nblocks << ": avg. diff " << avgdiff << ", " << (latest - earliest) / nblocks << " avg sec/block, avg num txes " << avgnumtxes
<< ", avg. reward " << cryptonote::print_money(avgreward) << ", median block weight " << median_block_weight;
unsigned int max_major = 256, max_minor = 256;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 426767365..00467132a 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -2432,10 +2432,11 @@ namespace nodetool
auto public_zone = m_network_zones.find(epee::net_utils::zone::public_);
if (public_zone != m_network_zones.end())
{
- const auto current = public_zone->second.m_config.m_net_config.max_out_connection_count;
+ const auto current = public_zone->second.m_net_server.get_config_object().get_out_connections_count();
public_zone->second.m_config.m_net_config.max_out_connection_count = count;
if(current > count)
public_zone->second.m_net_server.get_config_object().del_out_connections(current - count);
+ m_payload_handler.set_max_out_peers(count);
}
}
@@ -2454,7 +2455,7 @@ namespace nodetool
auto public_zone = m_network_zones.find(epee::net_utils::zone::public_);
if (public_zone != m_network_zones.end())
{
- const auto current = public_zone->second.m_config.m_net_config.max_in_connection_count;
+ const auto current = public_zone->second.m_net_server.get_config_object().get_in_connections_count();
public_zone->second.m_config.m_net_config.max_in_connection_count = count;
if(current > count)
public_zone->second.m_net_server.get_config_object().del_in_connections(current - count);
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index 883997fd6..68627375a 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -278,6 +278,9 @@ namespace nodetool
// was moved to the gray list (if it's not accessibe, which the attacker can check if
// the address accepts incoming connections) or it was the oldest to still fit in the 250 items,
// so its last_seen is old.
+ //
+ // See Cao, Tong et al. "Exploring the Monero Peer-to-Peer Network". https://eprint.iacr.org/2019/411
+ //
const uint32_t pick_depth = anonymize ? depth + depth / 5 : depth;
bs_head.reserve(pick_depth);
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index))
diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt
index cffe8e1eb..06577d37e 100644
--- a/src/rpc/CMakeLists.txt
+++ b/src/rpc/CMakeLists.txt
@@ -47,7 +47,7 @@ set(rpc_base_headers
rpc_args.h)
set(rpc_headers
- rpc_handler.cpp)
+ rpc_handler.h)
set(daemon_rpc_server_headers)
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index c81cfa59c..9aaaa026d 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -142,6 +142,7 @@ namespace cryptonote
{
m_restricted = restricted;
m_net_server.set_threads_prefix("RPC");
+ m_net_server.set_connection_filter(&m_p2p);
auto rpc_config = cryptonote::rpc_args::process(vm, true);
if (!rpc_config)
@@ -175,6 +176,24 @@ namespace cryptonote
}
return true;
}
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::add_host_fail(const connection_context *ctx)
+ {
+ if(!ctx || !ctx->m_remote_address.is_blockable())
+ return false;
+
+ CRITICAL_REGION_LOCAL(m_host_fails_score_lock);
+ uint64_t fails = ++m_host_fails_score[ctx->m_remote_address.host_str()];
+ MDEBUG("Host " << ctx->m_remote_address.host_str() << " fail score=" << fails);
+ if(fails > RPC_IP_FAILS_BEFORE_BLOCK)
+ {
+ auto it = m_host_fails_score.find(ctx->m_remote_address.host_str());
+ CHECK_AND_ASSERT_MES(it != m_host_fails_score.end(), false, "internal error");
+ it->second = RPC_IP_FAILS_BEFORE_BLOCK/2;
+ m_p2p.block_host(ctx->m_remote_address);
+ }
+ return true;
+ }
#define CHECK_CORE_READY() do { if(!check_core_ready()){res.status = CORE_RPC_STATUS_BUSY;return true;} } while(0)
//------------------------------------------------------------------------------------------------------------------------------
@@ -302,6 +321,7 @@ namespace cryptonote
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, req.prune, !req.no_miner_tx, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
{
res.status = "Failed";
+ add_host_fail(ctx);
return false;
}
@@ -425,6 +445,7 @@ namespace cryptonote
if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, res.m_block_ids, res.start_height, res.current_height, false))
{
res.status = "Failed";
+ add_host_fail(ctx);
return false;
}
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index f697df485..e91d4c953 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -238,6 +238,7 @@ namespace cryptonote
private:
bool check_core_busy();
bool check_core_ready();
+ bool add_host_fail(const connection_context *ctx);
//utils
uint64_t get_block_reward(const block& blk);
@@ -258,6 +259,8 @@ private:
bool m_was_bootstrap_ever_used;
network_type m_nettype;
bool m_restricted;
+ epee::critical_section m_host_fails_score_lock;
+ std::map<std::string, uint64_t> m_host_fails_score;
};
}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index fca14c8f8..10901bb51 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -3972,7 +3972,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (m_restoring && m_generate_from_json.empty() && m_generate_from_device.empty())
{
- m_wallet->explicit_refresh_from_block_height(!(command_line::is_arg_defaulted(vm, arg_restore_height) ||
+ m_wallet->explicit_refresh_from_block_height(!(command_line::is_arg_defaulted(vm, arg_restore_height) &&
command_line::is_arg_defaulted(vm, arg_restore_date)));
if (command_line::is_arg_defaulted(vm, arg_restore_height) && !command_line::is_arg_defaulted(vm, arg_restore_date))
{
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 9d2129d08..e632b8d23 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1748,18 +1748,27 @@ std::string WalletImpl::getTxKey(const std::string &txid_str) const
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
- if (m_wallet->get_tx_key(txid, tx_key, additional_tx_keys))
+ try
{
clearStatus();
- std::ostringstream oss;
- oss << epee::string_tools::pod_to_hex(tx_key);
- for (size_t i = 0; i < additional_tx_keys.size(); ++i)
- oss << epee::string_tools::pod_to_hex(additional_tx_keys[i]);
- return oss.str();
+ if (m_wallet->get_tx_key(txid, tx_key, additional_tx_keys))
+ {
+ clearStatus();
+ std::ostringstream oss;
+ oss << epee::string_tools::pod_to_hex(tx_key);
+ for (size_t i = 0; i < additional_tx_keys.size(); ++i)
+ oss << epee::string_tools::pod_to_hex(additional_tx_keys[i]);
+ return oss.str();
+ }
+ else
+ {
+ setStatusError(tr("no tx keys found for this txid"));
+ return "";
+ }
}
- else
+ catch (const std::exception &e)
{
- setStatusError(tr("no tx keys found for this txid"));
+ setStatusError(e.what());
return "";
}
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index e44fea7d7..23c375924 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -6125,7 +6125,7 @@ void wallet2::commit_tx(pending_tx& ptx)
amount_in += m_transfers[idx].amount();
}
add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
- if (store_tx_info())
+ if (store_tx_info() && ptx.tx_key != crypto::null_skey)
{
m_tx_keys.insert(std::make_pair(txid, ptx.tx_key));
m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys));
@@ -6314,7 +6314,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
// normally, the tx keys are saved in commit_tx, when the tx is actually sent to the daemon.
// we can't do that here since the tx will be sent from the compromised wallet, which we don't want
// to see that info, so we save it here
- if (store_tx_info())
+ if (store_tx_info() && ptx.tx_key != crypto::null_skey)
{
const crypto::hash txid = get_transaction_hash(ptx.tx);
m_tx_keys.insert(std::make_pair(txid, tx_key));
@@ -8167,6 +8167,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
if (needed_money < found_money)
{
change_dts.addr = get_subaddress({subaddr_account, 0});
+ change_dts.is_subaddress = subaddr_account != 0;
change_dts.amount = found_money - needed_money;
}
@@ -10310,6 +10311,8 @@ bool wallet2::get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx
if (i == m_tx_keys.end())
return false;
tx_key = i->second;
+ if (tx_key == crypto::null_skey)
+ return false;
const auto j = m_additional_tx_keys.find(txid);
if (j != m_additional_tx_keys.end())
additional_tx_keys = j->second;
@@ -10321,6 +10324,7 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, s
bool r = get_tx_key_cached(txid, tx_key, additional_tx_keys);
if (r)
{
+ MDEBUG("tx key cached for txid: " << txid);
return true;
}
@@ -10382,13 +10386,18 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, s
dev_cold->get_tx_key(tx_keys, tx_key_data, m_account.get_keys().m_view_secret_key);
if (tx_keys.empty())
{
+ MDEBUG("Empty tx keys for txid: " << txid);
+ return false;
+ }
+
+ if (tx_keys[0] == crypto::null_skey)
+ {
return false;
}
tx_key = tx_keys[0];
tx_keys.erase(tx_keys.begin());
additional_tx_keys = tx_keys;
-
return true;
}
//----------------------------------------------------------------------------------------------------
diff --git a/tests/functional_tests/blockchain.py b/tests/functional_tests/blockchain.py
index 2bd7672c0..2c3f34c35 100755
--- a/tests/functional_tests/blockchain.py
+++ b/tests/functional_tests/blockchain.py
@@ -78,6 +78,12 @@ class BlockchainTest():
except: ok = True
assert ok
+ res = daemon.get_fee_estimate()
+ assert res.fee == 234562
+ assert res.quantization_mask == 10000
+ res = daemon.get_fee_estimate(10)
+ assert res.fee <= 234562
+
# generate blocks
res_generateblocks = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', blocks)
@@ -229,6 +235,12 @@ class BlockchainTest():
assert res.histogram[i].unlocked_instances == 0
assert res.histogram[i].recent_instances == 0
+ res = daemon.get_fee_estimate()
+ assert res.fee == 234560
+ assert res.quantization_mask == 10000
+ res = daemon.get_fee_estimate(10)
+ assert res.fee <= 234560
+
def _test_alt_chains(self):
print('Testing alt chains')
daemon = Daemon()
diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py
index 25ab641ab..77d0e4c4d 100755
--- a/tests/functional_tests/functional_tests_rpc.py
+++ b/tests/functional_tests/functional_tests_rpc.py
@@ -65,7 +65,7 @@ try:
for i in range(len(command_lines)):
#print('Running: ' + str(command_lines[i]))
processes.append(subprocess.Popen(command_lines[i], stdout = outputs[i]))
-except Exception, e:
+except Exception as e:
print('Error: ' + str(e))
sys.exit(1)
diff --git a/tests/functional_tests/wallet_address.py b/tests/functional_tests/wallet_address.py
index 4ff059a6f..eda52b432 100755
--- a/tests/functional_tests/wallet_address.py
+++ b/tests/functional_tests/wallet_address.py
@@ -198,8 +198,9 @@ class WalletAddressTest():
try: wallet.close_wallet()
except: pass
languages = res.languages
- for language in languages:
- print('Creating ' + str(language) + ' wallet')
+ languages_local = res.languages_local
+ for language in languages + languages_local:
+ print('Creating ' + language.encode('utf8') + ' wallet')
wallet.create_wallet(filename = '', language = language)
res = wallet.query_key('mnemonic')
wallet.close_wallet()
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index 946731826..c5f9a42d0 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -946,3 +946,20 @@ TEST(parsing, number)
epee::misc_utils::parse::match_number(i, s.end(), val);
ASSERT_EQ(val, "+9.34e+03");
}
+
+TEST(parsing, unicode)
+{
+ std::string bs;
+ std::string s;
+ std::string::const_iterator si;
+
+ s = "\"\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, "");
+ s = "\"\\u0000\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, std::string(1, '\0'));
+ s = "\"\\u0020\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, " ");
+ s = "\"\\u1\""; si = s.begin(); ASSERT_FALSE(epee::misc_utils::parse::match_string(si, s.end(), bs));
+ s = "\"\\u12\""; si = s.begin(); ASSERT_FALSE(epee::misc_utils::parse::match_string(si, s.end(), bs));
+ s = "\"\\u123\""; si = s.begin(); ASSERT_FALSE(epee::misc_utils::parse::match_string(si, s.end(), bs));
+ s = "\"\\u1234\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, "ሴ");
+ s = "\"foo\\u1234bar\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, "fooሴbar");
+ s = "\"\\u3042\\u307e\\u3084\\u304b\\u3059\""; si = s.begin(); ASSERT_TRUE(epee::misc_utils::parse::match_string(si, s.end(), bs)); ASSERT_EQ(bs, "あまやかす");
+}
diff --git a/tests/unit_tests/output_selection.cpp b/tests/unit_tests/output_selection.cpp
index c98696fbd..0724cd3e0 100644
--- a/tests/unit_tests/output_selection.cpp
+++ b/tests/unit_tests/output_selection.cpp
@@ -211,10 +211,10 @@ TEST(select_outputs, same_distribution)
{
const double diff = (double)output_norm[i] - (double)chain_norm[i];
double dev = fabs(2.0 * diff / (output_norm[i] + chain_norm[i]));
- ASSERT_LT(dev, 0.1);
+ ASSERT_LT(dev, 0.15);
avg_dev += dev;
}
avg_dev /= 100;
MDEBUG("avg_dev: " << avg_dev);
- ASSERT_LT(avg_dev, 0.015);
+ ASSERT_LT(avg_dev, 0.02);
}
diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py
index 20967030a..23d5ec0f0 100644
--- a/utils/python-rpc/framework/daemon.py
+++ b/utils/python-rpc/framework/daemon.py
@@ -333,3 +333,14 @@ class Daemon(object):
'id': '0'
}
return self.rpc.send_json_rpc_request(get_alternate_chains)
+
+ def get_fee_estimate(self, grace_blocks = 0):
+ get_fee_estimate = {
+ 'method': 'get_fee_estimate',
+ 'params': {
+ 'grace_blocks': grace_blocks,
+ },
+ 'jsonrpc': '2.0',
+ 'id': '0'
+ }
+ return self.rpc.send_json_rpc_request(get_fee_estimate)