mirror of
https://github.com/monero-project/monero.git
synced 2024-12-23 12:09:54 +00:00
Merge pull request #4092
3a1ad042
docker: update to new versions of dependencies (HomDx)fc8726f1
fix sha256sum check, which requires two spaces. added set -ex to catch this, and other, errors in the future. (cornfeedhobo)8c331a6d
wallet2: fix double counting outs if the tx pubkey is duplicated (moneromooo-monero)2daf54de
abstract_tcp_server2: fix use after free (moneromooo-monero)41662ebc
device_ledger: fix buffer underflow on bad data from device (moneromooo-monero)e389101c
device: misc cleanup (moneromooo-monero)076b7e10
device_ledger: fix potential buffer overflow from bad size calc (moneromooo-monero)0429cabe
simplewallet: init trusted daemon flag to false when autodetecting (moneromooo-monero)b323d90f
wallet2: fix read buffer overflow in import_key_images (moneromooo-monero)47b42f8b
wallet-rpc.getaddress: throw if index is out of bound (stoffu)223429f0
zmq_server: fix bind call when address and/or port are empty (moneromooo-monero)280e1a64
Fix RPC crashes that didn't check for an open wallet (Howard Chu)43a12497
wallet2: fix out of sync account tag cache (moneromooo-monero)e5ac16b0
abstract_tcp_server2: restart async accept on error (moneromooo-monero)bea06d1a
epee.string_tools: add conversion between UTF-8 and UTF-16 (stoffu)e93058b4
wallet_api: fixups to build on the branch (moneromooo-monero)8fb50b73
Wallet API: add support for wallet creation from hardware device (stoffu)9e9cd108
Move parse_subaddress_lookahead() from simplewallet.cpp to util.cpp (stoffu)fbdc3096
wallet2: lower default for subaddress lookahead when restoring with hardware (stoffu)ed366efb
add disclaimer about 3rd party packages (Jethro Grassie)afa66965
wallet: allow unspendable unmixable outputs to be discarded (stoffu)e70d80e8
wallet2: use decoded amount when reporting repeated output key (stoffu)5e180c73
wallet2: use correct fee for split txes (stoffu)d099dba9
epee: adaptive connection timeout system (moneromooo-monero)04abe99f
simplewallet: don't confirm missing payment ID when sending to only subaddresses (stoffu)9c2f09df
epee: fallback to a counter if gmtime fails when rotating logs (moneromooo-monero)505fde2e
Update readme to include pcslite dependency (Gingeropolous)009feaca
wallet2: fix get_approximate_blockchain_height for stagenet (stoffu)7ce841cc
wallet: do not log by default if we're not asked to log to console (moneromooo-monero)4e2b279a
tx_pool: initialize bitflags padding since it gets written to storage (moneromooo-monero)b85169a5
README: mention --untrusted-daemon (moneromooo-monero)082e0a1b
util: consider Tor/I2P addresses to be non local (moneromooo-monero)85d2ae4a
simplewallet: add optional trusted/untrusted argument to set_daemon (moneromooo-monero)233a1ead
blockchain: pop forked blocks only when DB is not read-only (stoffu)1380b70e
Fixes #3645: error on freebsd lambda return values forced to std::string (rockhouse@users.noreply.github.com)8e64b616
blockchain: return error when requesting non existent output (moneromooo-monero)1d3874da
epee: fix detection of 172.16.0.0/172.31.255.255 local IP range (moneromooo-monero)74008527
daemon: fix readline interfering with std::cerr usage (moneromooo-monero)81e39263
disable file size sanity check when loading the wallet cache (moneromooo-monero)e04ae088
fix build with GCC 8.1.0 (moneromooo-monero)f6896d99
core: lock incoming tx lock when checking the txpool and chain (moneromooo-monero)f6dbb967
simplewallet: add --untrusted-daemon option (moneromooo-monero)
This commit is contained in:
commit
1ce04b7574
38 changed files with 595 additions and 213 deletions
73
Dockerfile
73
Dockerfile
|
@ -3,7 +3,8 @@
|
||||||
# builder stage
|
# builder stage
|
||||||
FROM ubuntu:16.04 as builder
|
FROM ubuntu:16.04 as builder
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN set -ex && \
|
||||||
|
apt-get update && \
|
||||||
apt-get --no-install-recommends --yes install \
|
apt-get --no-install-recommends --yes install \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
cmake \
|
cmake \
|
||||||
|
@ -16,16 +17,31 @@ RUN apt-get update && \
|
||||||
curl \
|
curl \
|
||||||
libtool-bin \
|
libtool-bin \
|
||||||
autoconf \
|
autoconf \
|
||||||
automake
|
automake \
|
||||||
|
bzip2
|
||||||
|
|
||||||
WORKDIR /usr/local
|
WORKDIR /usr/local
|
||||||
|
|
||||||
|
#Cmake
|
||||||
|
ARG CMAKE_VERSION=3.11.4
|
||||||
|
ARG CMAKE_VERSION_DOT=v3.11
|
||||||
|
ARG CMAKE_HASH=8f864e9f78917de3e1483e256270daabc4a321741592c5b36af028e72bff87f5
|
||||||
|
RUN set -ex \
|
||||||
|
&& curl -s -O https://cmake.org/files/${CMAKE_VERSION_DOT}/cmake-${CMAKE_VERSION}.tar.gz \
|
||||||
|
&& echo "${CMAKE_HASH} cmake-${CMAKE_VERSION}.tar.gz" | sha256sum -c \
|
||||||
|
&& tar -xzf cmake-${CMAKE_VERSION}.tar.gz \
|
||||||
|
&& cd cmake-${CMAKE_VERSION} \
|
||||||
|
&& ./configure \
|
||||||
|
&& make \
|
||||||
|
&& make install
|
||||||
|
|
||||||
## Boost
|
## Boost
|
||||||
ARG BOOST_VERSION=1_66_0
|
ARG BOOST_VERSION=1_67_0
|
||||||
ARG BOOST_VERSION_DOT=1.66.0
|
ARG BOOST_VERSION_DOT=1.67.0
|
||||||
ARG BOOST_HASH=5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9
|
ARG BOOST_HASH=2684c972994ee57fc5632e03bf044746f6eb45d4920c343937a465fd67a5adba
|
||||||
RUN curl -s -L -o boost_${BOOST_VERSION}.tar.bz2 https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \
|
RUN set -ex \
|
||||||
&& echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \
|
&& curl -s -L -o boost_${BOOST_VERSION}.tar.bz2 https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \
|
||||||
|
&& echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \
|
||||||
&& tar -xvf boost_${BOOST_VERSION}.tar.bz2 \
|
&& tar -xvf boost_${BOOST_VERSION}.tar.bz2 \
|
||||||
&& cd boost_${BOOST_VERSION} \
|
&& cd boost_${BOOST_VERSION} \
|
||||||
&& ./bootstrap.sh \
|
&& ./bootstrap.sh \
|
||||||
|
@ -33,21 +49,24 @@ RUN curl -s -L -o boost_${BOOST_VERSION}.tar.bz2 https://dl.bintray.com/boostor
|
||||||
ENV BOOST_ROOT /usr/local/boost_${BOOST_VERSION}
|
ENV BOOST_ROOT /usr/local/boost_${BOOST_VERSION}
|
||||||
|
|
||||||
# OpenSSL
|
# OpenSSL
|
||||||
ARG OPENSSL_VERSION=1.0.2n
|
ARG OPENSSL_VERSION=1.1.0h
|
||||||
ARG OPENSSL_HASH=370babb75f278c39e0c50e8c4e7493bc0f18db6867478341a832a982fd15a8fe
|
ARG OPENSSL_HASH=5835626cde9e99656585fc7aaa2302a73a7e1340bf8c14fd635a62c66802a517
|
||||||
RUN curl -s -O https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
|
RUN set -ex \
|
||||||
&& echo "${OPENSSL_HASH} openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c \
|
&& curl -s -O https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
|
||||||
|
&& echo "${OPENSSL_HASH} openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c \
|
||||||
&& tar -xzf openssl-${OPENSSL_VERSION}.tar.gz \
|
&& tar -xzf openssl-${OPENSSL_VERSION}.tar.gz \
|
||||||
&& cd openssl-${OPENSSL_VERSION} \
|
&& cd openssl-${OPENSSL_VERSION} \
|
||||||
&& ./Configure linux-x86_64 no-shared --static -fPIC \
|
&& ./Configure linux-x86_64 no-shared --static -fPIC \
|
||||||
&& make build_crypto build_ssl \
|
&& make build_generated \
|
||||||
|
&& make libcrypto.a \
|
||||||
&& make install
|
&& make install
|
||||||
ENV OPENSSL_ROOT_DIR=/usr/local/openssl-${OPENSSL_VERSION}
|
ENV OPENSSL_ROOT_DIR=/usr/local/openssl-${OPENSSL_VERSION}
|
||||||
|
|
||||||
# ZMQ
|
# ZMQ
|
||||||
ARG ZMQ_VERSION=v4.2.3
|
ARG ZMQ_VERSION=v4.2.5
|
||||||
ARG ZMQ_HASH=3226b8ebddd9c6c738ba42986822c26418a49afb
|
ARG ZMQ_HASH=d062edd8c142384792955796329baf1e5a3377cd
|
||||||
RUN git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} \
|
RUN set -ex \
|
||||||
|
&& git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} \
|
||||||
&& cd libzmq \
|
&& cd libzmq \
|
||||||
&& test `git rev-parse HEAD` = ${ZMQ_HASH} || exit 1 \
|
&& test `git rev-parse HEAD` = ${ZMQ_HASH} || exit 1 \
|
||||||
&& ./autogen.sh \
|
&& ./autogen.sh \
|
||||||
|
@ -57,8 +76,10 @@ RUN git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} \
|
||||||
&& ldconfig
|
&& ldconfig
|
||||||
|
|
||||||
# zmq.hpp
|
# zmq.hpp
|
||||||
|
ARG CPPZMQ_VERSION=v4.2.3
|
||||||
ARG CPPZMQ_HASH=6aa3ab686e916cb0e62df7fa7d12e0b13ae9fae6
|
ARG CPPZMQ_HASH=6aa3ab686e916cb0e62df7fa7d12e0b13ae9fae6
|
||||||
RUN git clone https://github.com/zeromq/cppzmq.git -b ${ZMQ_VERSION} \
|
RUN set -ex \
|
||||||
|
&& git clone https://github.com/zeromq/cppzmq.git -b ${CPPZMQ_VERSION} \
|
||||||
&& cd cppzmq \
|
&& cd cppzmq \
|
||||||
&& test `git rev-parse HEAD` = ${CPPZMQ_HASH} || exit 1 \
|
&& test `git rev-parse HEAD` = ${CPPZMQ_HASH} || exit 1 \
|
||||||
&& mv *.hpp /usr/local/include
|
&& mv *.hpp /usr/local/include
|
||||||
|
@ -66,8 +87,9 @@ RUN git clone https://github.com/zeromq/cppzmq.git -b ${ZMQ_VERSION} \
|
||||||
# Readline
|
# Readline
|
||||||
ARG READLINE_VERSION=7.0
|
ARG READLINE_VERSION=7.0
|
||||||
ARG READLINE_HASH=750d437185286f40a369e1e4f4764eda932b9459b5ec9a731628393dd3d32334
|
ARG READLINE_HASH=750d437185286f40a369e1e4f4764eda932b9459b5ec9a731628393dd3d32334
|
||||||
RUN curl -s -O https://ftp.gnu.org/gnu/readline/readline-${READLINE_VERSION}.tar.gz \
|
RUN set -ex \
|
||||||
&& echo "${READLINE_HASH} readline-${READLINE_VERSION}.tar.gz" | sha256sum -c \
|
&& curl -s -O https://ftp.gnu.org/gnu/readline/readline-${READLINE_VERSION}.tar.gz \
|
||||||
|
&& echo "${READLINE_HASH} readline-${READLINE_VERSION}.tar.gz" | sha256sum -c \
|
||||||
&& tar -xzf readline-${READLINE_VERSION}.tar.gz \
|
&& tar -xzf readline-${READLINE_VERSION}.tar.gz \
|
||||||
&& cd readline-${READLINE_VERSION} \
|
&& cd readline-${READLINE_VERSION} \
|
||||||
&& CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure \
|
&& CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure \
|
||||||
|
@ -77,7 +99,8 @@ RUN curl -s -O https://ftp.gnu.org/gnu/readline/readline-${READLINE_VERSION}.tar
|
||||||
# Sodium
|
# Sodium
|
||||||
ARG SODIUM_VERSION=1.0.16
|
ARG SODIUM_VERSION=1.0.16
|
||||||
ARG SODIUM_HASH=675149b9b8b66ff44152553fb3ebf9858128363d
|
ARG SODIUM_HASH=675149b9b8b66ff44152553fb3ebf9858128363d
|
||||||
RUN git clone https://github.com/jedisct1/libsodium.git -b ${SODIUM_VERSION} \
|
RUN set -ex \
|
||||||
|
&& git clone https://github.com/jedisct1/libsodium.git -b ${SODIUM_VERSION} \
|
||||||
&& cd libsodium \
|
&& cd libsodium \
|
||||||
&& test `git rev-parse HEAD` = ${SODIUM_HASH} || exit 1 \
|
&& test `git rev-parse HEAD` = ${SODIUM_HASH} || exit 1 \
|
||||||
&& ./autogen.sh \
|
&& ./autogen.sh \
|
||||||
|
@ -90,13 +113,18 @@ WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ARG NPROC
|
ARG NPROC
|
||||||
RUN rm -rf build && \
|
RUN set -ex && \
|
||||||
if [ -z "$NPROC" ];then make -j$(nproc) release-static;else make -j$NPROC release-static;fi
|
rm -rf build && \
|
||||||
|
if [ -z "$NPROC" ] ; \
|
||||||
|
then make -j$(nproc) release-static ; \
|
||||||
|
else make -j$NPROC release-static ; \
|
||||||
|
fi
|
||||||
|
|
||||||
# runtime stage
|
# runtime stage
|
||||||
FROM ubuntu:16.04
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN set -ex && \
|
||||||
|
apt-get update && \
|
||||||
apt-get --no-install-recommends --yes install ca-certificates && \
|
apt-get --no-install-recommends --yes install ca-certificates && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt
|
rm -rf /var/lib/apt
|
||||||
|
@ -115,3 +143,4 @@ EXPOSE 18080
|
||||||
EXPOSE 18081
|
EXPOSE 18081
|
||||||
|
|
||||||
ENTRYPOINT ["monerod", "--p2p-bind-ip=0.0.0.0", "--p2p-bind-port=18080", "--rpc-bind-ip=0.0.0.0", "--rpc-bind-port=18081", "--non-interactive", "--confirm-external-bind"]
|
ENTRYPOINT ["monerod", "--p2p-bind-ip=0.0.0.0", "--p2p-bind-port=18080", "--rpc-bind-ip=0.0.0.0", "--rpc-bind-port=18081", "--non-interactive", "--confirm-external-bind"]
|
||||||
|
|
||||||
|
|
89
README.md
89
README.md
|
@ -113,49 +113,6 @@ X's indicate that these details have not been determined as of commit date.
|
||||||
|
|
||||||
Approximately three months prior to a scheduled software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
|
Approximately three months prior to a scheduled software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
|
||||||
|
|
||||||
## Installing Monero from a package
|
|
||||||
|
|
||||||
Packages are available for
|
|
||||||
|
|
||||||
* Ubuntu and [snap supported](https://snapcraft.io/docs/core/install) systems, via a community contributed build.
|
|
||||||
|
|
||||||
snap install monero --beta
|
|
||||||
|
|
||||||
Installing a snap is very quick. Snaps are secure. They are isolated with all of their dependencies. Snaps also auto update when a new version is released.
|
|
||||||
|
|
||||||
* Arch Linux (via [AUR](https://aur.archlinux.org/)):
|
|
||||||
- Stable release: [`monero`](https://aur.archlinux.org/packages/monero)
|
|
||||||
- Bleeding edge: [`monero-git`](https://aur.archlinux.org/packages/monero-git)
|
|
||||||
|
|
||||||
* Void Linux:
|
|
||||||
|
|
||||||
xbps-install -S monero
|
|
||||||
|
|
||||||
* GuixSD
|
|
||||||
|
|
||||||
guix package -i monero
|
|
||||||
|
|
||||||
* OS X via [Homebrew](http://brew.sh)
|
|
||||||
|
|
||||||
brew tap sammy007/cryptonight
|
|
||||||
brew install monero --build-from-source
|
|
||||||
|
|
||||||
* Docker
|
|
||||||
|
|
||||||
# Build using all available cores
|
|
||||||
docker build -t monero .
|
|
||||||
|
|
||||||
# or build using a specific number of cores (reduce RAM requirement)
|
|
||||||
docker build --build-arg NPROC=1 -t monero .
|
|
||||||
|
|
||||||
# either run in foreground
|
|
||||||
docker run -it -v /monero/chain:/root/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
|
|
||||||
|
|
||||||
# or in background
|
|
||||||
docker run -it -d -v /monero/chain:/root/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
|
|
||||||
|
|
||||||
Packaging for your favorite distribution would be a welcome contribution!
|
|
||||||
|
|
||||||
## Compiling Monero from source
|
## Compiling Monero from source
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
@ -188,6 +145,7 @@ library archives (`.a`).
|
||||||
| GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | `gtest-devel` | YES | Test suite |
|
| GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | `gtest-devel` | YES | Test suite |
|
||||||
| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | YES | Documentation |
|
| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | YES | Documentation |
|
||||||
| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | YES | Documentation |
|
| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | YES | Documentation |
|
||||||
|
| pcsclite | ? | NO | `libpcsclite-dev` | ? | `pcsc-lite pcsc-lite-devel` | NO | Ledger |
|
||||||
|
|
||||||
|
|
||||||
[^] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
|
[^] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
|
||||||
|
@ -494,6 +452,49 @@ By default, in either dynamically or statically linked builds, binaries target t
|
||||||
* ```make release-static-win64``` builds binaries on 64-bit Windows portable across 64-bit Windows systems
|
* ```make release-static-win64``` builds binaries on 64-bit Windows portable across 64-bit Windows systems
|
||||||
* ```make release-static-win32``` builds binaries on 64-bit or 32-bit Windows portable across 32-bit Windows systems
|
* ```make release-static-win32``` builds binaries on 64-bit or 32-bit Windows portable across 32-bit Windows systems
|
||||||
|
|
||||||
|
## Installing Monero from a package
|
||||||
|
|
||||||
|
**DISCLAIMER: These packages are not part of this repository or maintained by this project's contributors, and as such, do not go through the same review process to ensure their trustworthiness and security.**
|
||||||
|
|
||||||
|
Packages are available for
|
||||||
|
|
||||||
|
* Ubuntu and [snap supported](https://snapcraft.io/docs/core/install) systems, via a community contributed build.
|
||||||
|
|
||||||
|
snap install monero --beta
|
||||||
|
|
||||||
|
Installing a snap is very quick. Snaps are secure. They are isolated with all of their dependencies. Snaps also auto update when a new version is released.
|
||||||
|
|
||||||
|
* Arch Linux (via [AUR](https://aur.archlinux.org/)):
|
||||||
|
- Stable release: [`monero`](https://aur.archlinux.org/packages/monero)
|
||||||
|
- Bleeding edge: [`monero-git`](https://aur.archlinux.org/packages/monero-git)
|
||||||
|
|
||||||
|
* Void Linux:
|
||||||
|
|
||||||
|
xbps-install -S monero
|
||||||
|
|
||||||
|
* GuixSD
|
||||||
|
|
||||||
|
guix package -i monero
|
||||||
|
|
||||||
|
* Docker
|
||||||
|
|
||||||
|
# Build using all available cores
|
||||||
|
docker build -t monero .
|
||||||
|
|
||||||
|
# or build using a specific number of cores (reduce RAM requirement)
|
||||||
|
docker build --build-arg NPROC=1 -t monero .
|
||||||
|
|
||||||
|
# either run in foreground
|
||||||
|
docker run -it -v /monero/chain:/root/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
|
||||||
|
|
||||||
|
# or in background
|
||||||
|
docker run -it -d -v /monero/chain:/root/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
|
||||||
|
|
||||||
|
* The build needs 3 GB space.
|
||||||
|
* Wait one hour or more
|
||||||
|
|
||||||
|
Packaging for your favorite distribution would be a welcome contribution!
|
||||||
|
|
||||||
## Running monerod
|
## Running monerod
|
||||||
|
|
||||||
The build places the binary in `bin/` sub-directory within the build directory
|
The build places the binary in `bin/` sub-directory within the build directory
|
||||||
|
@ -547,6 +548,8 @@ setting the following configuration parameters and environment variables:
|
||||||
as well.
|
as well.
|
||||||
* Do NOT pass `--detach` when running through torsocks with systemd, (see
|
* Do NOT pass `--detach` when running through torsocks with systemd, (see
|
||||||
[utils/systemd/monerod.service](utils/systemd/monerod.service) for details).
|
[utils/systemd/monerod.service](utils/systemd/monerod.service) for details).
|
||||||
|
* If you use the wallet with a Tor daemon via the loopback IP (eg, 127.0.0.1:9050),
|
||||||
|
then use `--untrusted-daemon` unless it is your own hidden service.
|
||||||
|
|
||||||
Example command line to start monerod through Tor:
|
Example command line to start monerod through Tor:
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include "string_tools.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// On Windows there is a problem with non-ASCII characters in path and file names
|
// On Windows there is a problem with non-ASCII characters in path and file names
|
||||||
|
@ -72,11 +73,9 @@ namespace file_io_utils
|
||||||
bool save_string_to_file(const std::string& path_to_file, const std::string& str)
|
bool save_string_to_file(const std::string& path_to_file, const std::string& str)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
WCHAR wide_path[1000];
|
std::wstring wide_path;
|
||||||
int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000);
|
try { wide_path = string_tools::utf8_to_utf16(path_to_file); } catch (...) { return false; }
|
||||||
if (chars == 0)
|
HANDLE file_handle = CreateFileW(wide_path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
return false;
|
|
||||||
HANDLE file_handle = CreateFileW(wide_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
||||||
if (file_handle == INVALID_HANDLE_VALUE)
|
if (file_handle == INVALID_HANDLE_VALUE)
|
||||||
return false;
|
return false;
|
||||||
DWORD bytes_written;
|
DWORD bytes_written;
|
||||||
|
@ -128,18 +127,16 @@ namespace file_io_utils
|
||||||
|
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool load_file_to_string(const std::string& path_to_file, std::string& target_str)
|
bool load_file_to_string(const std::string& path_to_file, std::string& target_str, size_t max_size = 1000000000)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
WCHAR wide_path[1000];
|
std::wstring wide_path;
|
||||||
int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000);
|
try { wide_path = string_tools::utf8_to_utf16(path_to_file); } catch (...) { return false; }
|
||||||
if (chars == 0)
|
HANDLE file_handle = CreateFileW(wide_path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
return false;
|
|
||||||
HANDLE file_handle = CreateFileW(wide_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
||||||
if (file_handle == INVALID_HANDLE_VALUE)
|
if (file_handle == INVALID_HANDLE_VALUE)
|
||||||
return false;
|
return false;
|
||||||
DWORD file_size = GetFileSize(file_handle, NULL);
|
DWORD file_size = GetFileSize(file_handle, NULL);
|
||||||
if ((file_size == INVALID_FILE_SIZE) || (file_size > 1000000000)) {
|
if ((file_size == INVALID_FILE_SIZE) || (uint64_t)file_size > (uint64_t)max_size) {
|
||||||
CloseHandle(file_handle);
|
CloseHandle(file_handle);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +156,7 @@ namespace file_io_utils
|
||||||
|
|
||||||
std::ifstream::pos_type file_size = fstream.tellg();
|
std::ifstream::pos_type file_size = fstream.tellg();
|
||||||
|
|
||||||
if(file_size > 1000000000)
|
if((uint64_t)file_size > (uint64_t)max_size) // ensure a large domain for comparison, and negative -> too large
|
||||||
return false;//don't go crazy
|
return false;//don't go crazy
|
||||||
size_t file_size_t = static_cast<size_t>(file_size);
|
size_t file_size_t = static_cast<size_t>(file_size);
|
||||||
|
|
||||||
|
@ -202,11 +199,9 @@ namespace file_io_utils
|
||||||
bool get_file_size(const std::string& path_to_file, uint64_t &size)
|
bool get_file_size(const std::string& path_to_file, uint64_t &size)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
WCHAR wide_path[1000];
|
std::wstring wide_path;
|
||||||
int chars = MultiByteToWideChar(CP_UTF8, 0, path_to_file.c_str(), path_to_file.size() + 1, wide_path, 1000);
|
try { wide_path = string_tools::utf8_to_utf16(path_to_file); } catch (...) { return false; }
|
||||||
if (chars == 0)
|
HANDLE file_handle = CreateFileW(wide_path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
return false;
|
|
||||||
HANDLE file_handle = CreateFileW(wide_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
||||||
if (file_handle == INVALID_HANDLE_VALUE)
|
if (file_handle == INVALID_HANDLE_VALUE)
|
||||||
return false;
|
return false;
|
||||||
LARGE_INTEGER file_size;
|
LARGE_INTEGER file_size;
|
||||||
|
|
|
@ -119,6 +119,7 @@ namespace net_utils
|
||||||
//----------------- i_service_endpoint ---------------------
|
//----------------- i_service_endpoint ---------------------
|
||||||
virtual bool do_send(const void* ptr, size_t cb); ///< (see do_send from i_service_endpoint)
|
virtual bool do_send(const void* ptr, size_t cb); ///< (see do_send from i_service_endpoint)
|
||||||
virtual bool do_send_chunk(const void* ptr, size_t cb); ///< will send (or queue) a part of data
|
virtual bool do_send_chunk(const void* ptr, size_t cb); ///< will send (or queue) a part of data
|
||||||
|
virtual bool send_done();
|
||||||
virtual bool close();
|
virtual bool close();
|
||||||
virtual bool call_run_once_service_io();
|
virtual bool call_run_once_service_io();
|
||||||
virtual bool request_callback();
|
virtual bool request_callback();
|
||||||
|
@ -137,8 +138,11 @@ namespace net_utils
|
||||||
|
|
||||||
/// reset connection timeout timer and callback
|
/// reset connection timeout timer and callback
|
||||||
void reset_timer(boost::posix_time::milliseconds ms, bool add);
|
void reset_timer(boost::posix_time::milliseconds ms, bool add);
|
||||||
boost::posix_time::milliseconds get_default_time() const;
|
boost::posix_time::milliseconds get_default_timeout();
|
||||||
boost::posix_time::milliseconds get_timeout_from_bytes_read(size_t bytes) const;
|
boost::posix_time::milliseconds get_timeout_from_bytes_read(size_t bytes);
|
||||||
|
|
||||||
|
/// host connection count tracking
|
||||||
|
unsigned int host_count(const std::string &host, int delta = 0);
|
||||||
|
|
||||||
/// Buffer for incoming data.
|
/// Buffer for incoming data.
|
||||||
boost::array<char, 8192> buffer_;
|
boost::array<char, 8192> buffer_;
|
||||||
|
@ -165,6 +169,8 @@ namespace net_utils
|
||||||
|
|
||||||
boost::asio::deadline_timer m_timer;
|
boost::asio::deadline_timer m_timer;
|
||||||
bool m_local;
|
bool m_local;
|
||||||
|
bool m_ready_to_close;
|
||||||
|
std::string m_host;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setRpcStation();
|
void setRpcStation();
|
||||||
|
|
|
@ -56,8 +56,8 @@
|
||||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||||
|
|
||||||
#define DEFAULT_TIMEOUT_MS_LOCAL boost::posix_time::milliseconds(120000) // 2 minutes
|
#define DEFAULT_TIMEOUT_MS_LOCAL 1800000 // 30 minutes
|
||||||
#define DEFAULT_TIMEOUT_MS_REMOTE boost::posix_time::milliseconds(10000) // 10 seconds
|
#define DEFAULT_TIMEOUT_MS_REMOTE 300000 // 5 minutes
|
||||||
#define TIMEOUT_EXTRA_MS_PER_BYTE 0.2
|
#define TIMEOUT_EXTRA_MS_PER_BYTE 0.2
|
||||||
|
|
||||||
PRAGMA_WARNING_PUSH
|
PRAGMA_WARNING_PUSH
|
||||||
|
@ -86,7 +86,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
m_throttle_speed_in("speed_in", "throttle_speed_in"),
|
m_throttle_speed_in("speed_in", "throttle_speed_in"),
|
||||||
m_throttle_speed_out("speed_out", "throttle_speed_out"),
|
m_throttle_speed_out("speed_out", "throttle_speed_out"),
|
||||||
m_timer(io_service),
|
m_timer(io_service),
|
||||||
m_local(false)
|
m_local(false),
|
||||||
|
m_ready_to_close(false)
|
||||||
{
|
{
|
||||||
MDEBUG("test, connection constructor set m_connection_type="<<m_connection_type);
|
MDEBUG("test, connection constructor set m_connection_type="<<m_connection_type);
|
||||||
}
|
}
|
||||||
|
@ -146,7 +147,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
|
|
||||||
context = boost::value_initialized<t_connection_context>();
|
context = boost::value_initialized<t_connection_context>();
|
||||||
const unsigned long ip_{boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong())};
|
const unsigned long ip_{boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong())};
|
||||||
m_local = epee::net_utils::is_ip_loopback(ip_);
|
m_local = epee::net_utils::is_ip_loopback(ip_) || epee::net_utils::is_ip_local(ip_);
|
||||||
|
|
||||||
// create a random uuid
|
// create a random uuid
|
||||||
boost::uuids::uuid random_uuid;
|
boost::uuids::uuid random_uuid;
|
||||||
|
@ -165,9 +166,12 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_host = context.m_remote_address.host_str();
|
||||||
|
try { host_count(m_host, 1); } catch(...) { /* ignore */ }
|
||||||
|
|
||||||
m_protocol_handler.after_init_connection();
|
m_protocol_handler.after_init_connection();
|
||||||
|
|
||||||
reset_timer(get_default_time(), false);
|
reset_timer(get_default_timeout(), false);
|
||||||
|
|
||||||
socket_.async_read_some(boost::asio::buffer(buffer_),
|
socket_.async_read_some(boost::asio::buffer(buffer_),
|
||||||
strand_.wrap(
|
strand_.wrap(
|
||||||
|
@ -324,6 +328,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
logger_handle_net_read(bytes_transferred);
|
logger_handle_net_read(bytes_transferred);
|
||||||
context.m_last_recv = time(NULL);
|
context.m_last_recv = time(NULL);
|
||||||
context.m_recv_cnt += bytes_transferred;
|
context.m_recv_cnt += bytes_transferred;
|
||||||
|
m_ready_to_close = false;
|
||||||
bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred);
|
bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred);
|
||||||
if(!recv_res)
|
if(!recv_res)
|
||||||
{
|
{
|
||||||
|
@ -356,6 +361,13 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
_dbg3("[sock " << socket_.native_handle() << "] Some problems at read: " << e.message() << ':' << e.value());
|
_dbg3("[sock " << socket_.native_handle() << "] Some problems at read: " << e.message() << ':' << e.value());
|
||||||
shutdown();
|
shutdown();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dbg3("[sock " << socket_.native_handle() << "] peer closed connection");
|
||||||
|
if (m_ready_to_close)
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
m_ready_to_close = true;
|
||||||
}
|
}
|
||||||
// If an error occurs then no new asynchronous operations are started. This
|
// If an error occurs then no new asynchronous operations are started. This
|
||||||
// means that all shared_ptr references to the connection object will
|
// means that all shared_ptr references to the connection object will
|
||||||
|
@ -531,7 +543,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
if(m_send_que.size() > 1)
|
if(m_send_que.size() > 1)
|
||||||
{ // active operation should be in progress, nothing to do, just wait last operation callback
|
{ // active operation should be in progress, nothing to do, just wait last operation callback
|
||||||
auto size_now = cb;
|
auto size_now = cb;
|
||||||
MDEBUG("do_send() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size());
|
MDEBUG("do_send_chunk() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size());
|
||||||
//do_send_handler_delayed( ptr , size_now ); // (((H))) // empty function
|
//do_send_handler_delayed( ptr , size_now ); // (((H))) // empty function
|
||||||
|
|
||||||
LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
|
LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
|
||||||
|
@ -546,12 +558,12 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size_now = m_send_que.front().size();
|
auto size_now = m_send_que.front().size();
|
||||||
MDEBUG("do_send() NOW SENSD: packet="<<size_now<<" B");
|
MDEBUG("do_send_chunk() NOW SENSD: packet="<<size_now<<" B");
|
||||||
if (speed_limit_is_enabled())
|
if (speed_limit_is_enabled())
|
||||||
do_send_handler_write( ptr , size_now ); // (((H)))
|
do_send_handler_write( ptr , size_now ); // (((H)))
|
||||||
|
|
||||||
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), false, "Unexpected queue size");
|
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), false, "Unexpected queue size");
|
||||||
reset_timer(get_default_time(), false);
|
reset_timer(get_default_timeout(), false);
|
||||||
boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now ) ,
|
boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now ) ,
|
||||||
//strand_.wrap(
|
//strand_.wrap(
|
||||||
boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
|
boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
|
||||||
|
@ -566,29 +578,51 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
CATCH_ENTRY_L0("connection<t_protocol_handler>::do_send", false);
|
CATCH_ENTRY_L0("connection<t_protocol_handler>::do_send_chunk", false);
|
||||||
} // do_send_chunk
|
} // do_send_chunk
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
template<class t_protocol_handler>
|
template<class t_protocol_handler>
|
||||||
boost::posix_time::milliseconds connection<t_protocol_handler>::get_default_time() const
|
boost::posix_time::milliseconds connection<t_protocol_handler>::get_default_timeout()
|
||||||
{
|
{
|
||||||
|
unsigned count;
|
||||||
|
try { count = host_count(m_host); } catch (...) { count = 0; }
|
||||||
|
const unsigned shift = std::min(std::max(count, 1u) - 1, 8u);
|
||||||
|
boost::posix_time::milliseconds timeout(0);
|
||||||
if (m_local)
|
if (m_local)
|
||||||
return DEFAULT_TIMEOUT_MS_LOCAL;
|
timeout = boost::posix_time::milliseconds(DEFAULT_TIMEOUT_MS_LOCAL >> shift);
|
||||||
else
|
else
|
||||||
return DEFAULT_TIMEOUT_MS_REMOTE;
|
timeout = boost::posix_time::milliseconds(DEFAULT_TIMEOUT_MS_REMOTE >> shift);
|
||||||
|
return timeout;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
template<class t_protocol_handler>
|
template<class t_protocol_handler>
|
||||||
boost::posix_time::milliseconds connection<t_protocol_handler>::get_timeout_from_bytes_read(size_t bytes) const
|
boost::posix_time::milliseconds connection<t_protocol_handler>::get_timeout_from_bytes_read(size_t bytes)
|
||||||
{
|
{
|
||||||
boost::posix_time::milliseconds ms = (boost::posix_time::milliseconds)(unsigned)(bytes * TIMEOUT_EXTRA_MS_PER_BYTE);
|
boost::posix_time::milliseconds ms = (boost::posix_time::milliseconds)(unsigned)(bytes * TIMEOUT_EXTRA_MS_PER_BYTE);
|
||||||
ms += m_timer.expires_from_now();
|
ms += m_timer.expires_from_now();
|
||||||
if (ms > get_default_time())
|
if (ms > get_default_timeout())
|
||||||
ms = get_default_time();
|
ms = get_default_timeout();
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
template<class t_protocol_handler>
|
template<class t_protocol_handler>
|
||||||
|
unsigned int connection<t_protocol_handler>::host_count(const std::string &host, int delta)
|
||||||
|
{
|
||||||
|
static boost::mutex hosts_mutex;
|
||||||
|
CRITICAL_REGION_LOCAL(hosts_mutex);
|
||||||
|
static std::map<std::string, unsigned int> hosts;
|
||||||
|
unsigned int &val = hosts[host];
|
||||||
|
if (delta > 0)
|
||||||
|
MTRACE("New connection from host " << host << ": " << val);
|
||||||
|
else if (delta < 0)
|
||||||
|
MTRACE("Closed connection from host " << host << ": " << val);
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(delta >= 0 || val >= (unsigned)-delta, "Count would go negative");
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(delta <= 0 || val <= std::numeric_limits<unsigned int>::max() - (unsigned)delta, "Count would wrap");
|
||||||
|
val += delta;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
template<class t_protocol_handler>
|
||||||
void connection<t_protocol_handler>::reset_timer(boost::posix_time::milliseconds ms, bool add)
|
void connection<t_protocol_handler>::reset_timer(boost::posix_time::milliseconds ms, bool add)
|
||||||
{
|
{
|
||||||
if (m_connection_type != e_connection_type_RPC)
|
if (m_connection_type != e_connection_type_RPC)
|
||||||
|
@ -619,6 +653,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
m_timer.cancel();
|
m_timer.cancel();
|
||||||
boost::system::error_code ignored_ec;
|
boost::system::error_code ignored_ec;
|
||||||
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||||
|
if (!m_host.empty())
|
||||||
|
{
|
||||||
|
try { host_count(m_host, -1); } catch (...) { /* ignore */ }
|
||||||
|
m_host = "";
|
||||||
|
}
|
||||||
m_was_shutdown = true;
|
m_was_shutdown = true;
|
||||||
m_protocol_handler.release_protocol();
|
m_protocol_handler.release_protocol();
|
||||||
return true;
|
return true;
|
||||||
|
@ -645,6 +684,15 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
template<class t_protocol_handler>
|
template<class t_protocol_handler>
|
||||||
|
bool connection<t_protocol_handler>::send_done()
|
||||||
|
{
|
||||||
|
if (m_ready_to_close)
|
||||||
|
return close();
|
||||||
|
m_ready_to_close = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
template<class t_protocol_handler>
|
||||||
bool connection<t_protocol_handler>::cancel()
|
bool connection<t_protocol_handler>::cancel()
|
||||||
{
|
{
|
||||||
return close();
|
return close();
|
||||||
|
@ -687,7 +735,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
//have more data to send
|
//have more data to send
|
||||||
reset_timer(get_default_time(), false);
|
reset_timer(get_default_timeout(), false);
|
||||||
auto size_now = m_send_que.front().size();
|
auto size_now = m_send_que.front().size();
|
||||||
MDEBUG("handle_write() NOW SENDS: packet="<<size_now<<" B" <<", from queue size="<<m_send_que.size());
|
MDEBUG("handle_write() NOW SENDS: packet="<<size_now<<" B" <<", from queue size="<<m_send_que.size());
|
||||||
if (speed_limit_is_enabled())
|
if (speed_limit_is_enabled())
|
||||||
|
@ -982,7 +1030,8 @@ POP_WARNINGS
|
||||||
void boosted_tcp_server<t_protocol_handler>::handle_accept(const boost::system::error_code& e)
|
void boosted_tcp_server<t_protocol_handler>::handle_accept(const boost::system::error_code& e)
|
||||||
{
|
{
|
||||||
MDEBUG("handle_accept");
|
MDEBUG("handle_accept");
|
||||||
TRY_ENTRY();
|
try
|
||||||
|
{
|
||||||
if (!e)
|
if (!e)
|
||||||
{
|
{
|
||||||
if (m_connection_type == e_connection_type_RPC) {
|
if (m_connection_type == e_connection_type_RPC) {
|
||||||
|
@ -1000,11 +1049,25 @@ POP_WARNINGS
|
||||||
|
|
||||||
conn->start(true, 1 < m_threads_count);
|
conn->start(true, 1 < m_threads_count);
|
||||||
conn->save_dbg_log();
|
conn->save_dbg_log();
|
||||||
}else
|
return;
|
||||||
{
|
|
||||||
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_sock_count);
|
|
||||||
}
|
}
|
||||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::handle_accept", void());
|
else
|
||||||
|
{
|
||||||
|
MERROR("Error in boosted_tcp_server<t_protocol_handler>::handle_accept: " << e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
MERROR("Exception in boosted_tcp_server<t_protocol_handler>::handle_accept: " << e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
// error path, if e or exception
|
||||||
|
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_sock_count);
|
||||||
|
misc_utils::sleep_no_w(100);
|
||||||
|
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type));
|
||||||
|
acceptor_.async_accept(new_connection_->socket(),
|
||||||
|
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||||
|
boost::asio::placeholders::error));
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
template<class t_protocol_handler>
|
template<class t_protocol_handler>
|
||||||
|
|
|
@ -399,7 +399,7 @@ namespace net_utils
|
||||||
template<class t_connection_context>
|
template<class t_connection_context>
|
||||||
bool simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(size_t pos)
|
bool simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(size_t pos)
|
||||||
{
|
{
|
||||||
//LOG_PRINT_L4("HTTP HEAD:\r\n" << m_cache.substr(0, pos));
|
LOG_PRINT_L3("HTTP HEAD:\r\n" << m_cache.substr(0, pos));
|
||||||
|
|
||||||
m_query_info.m_full_request_buf_size = pos;
|
m_query_info.m_full_request_buf_size = pos;
|
||||||
m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos);
|
m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos);
|
||||||
|
@ -582,6 +582,7 @@ namespace net_utils
|
||||||
m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size());
|
m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size());
|
||||||
if ((response.m_body.size() && (query_info.m_http_method != http::http_method_head)) || (query_info.m_http_method == http::http_method_options))
|
if ((response.m_body.size() && (query_info.m_http_method != http::http_method_head)) || (query_info.m_http_method == http::http_method_options))
|
||||||
m_psnd_hndlr->do_send((void*)response.m_body.data(), response.m_body.size());
|
m_psnd_hndlr->do_send((void*)response.m_body.data(), response.m_body.size());
|
||||||
|
m_psnd_hndlr->send_done();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
|
@ -48,7 +48,7 @@ namespace epee
|
||||||
|
|
||||||
if( (ip | 0xffffff00) == 0xffffffac)
|
if( (ip | 0xffffff00) == 0xffffffac)
|
||||||
{
|
{
|
||||||
uint32_t second_num = (ip << 8) & 0xff000000;
|
uint32_t second_num = (ip >> 8) & 0xff;
|
||||||
if(second_num >= 16 && second_num <= 31 )
|
if(second_num >= 16 && second_num <= 31 )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,6 +281,7 @@ namespace net_utils
|
||||||
{
|
{
|
||||||
virtual bool do_send(const void* ptr, size_t cb)=0;
|
virtual bool do_send(const void* ptr, size_t cb)=0;
|
||||||
virtual bool close()=0;
|
virtual bool close()=0;
|
||||||
|
virtual bool send_done()=0;
|
||||||
virtual bool call_run_once_service_io()=0;
|
virtual bool call_run_once_service_io()=0;
|
||||||
virtual bool request_callback()=0;
|
virtual bool request_callback()=0;
|
||||||
virtual boost::asio::io_service& get_io_service()=0;
|
virtual boost::asio::io_service& get_io_service()=0;
|
||||||
|
|
|
@ -381,6 +381,41 @@ POP_WARNINGS
|
||||||
res = str.substr(0, pos);
|
res = str.substr(0, pos);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
#ifdef _WIN32
|
||||||
|
inline std::wstring utf8_to_utf16(const std::string& str)
|
||||||
|
{
|
||||||
|
if (str.empty())
|
||||||
|
return {};
|
||||||
|
int wstr_size = MultiByteToWideChar(CP_UTF8, 0, &str[0], str.size(), NULL, 0);
|
||||||
|
if (wstr_size == 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::error_code(GetLastError(), std::system_category()).message());
|
||||||
|
}
|
||||||
|
std::wstring wstr(wstr_size, wchar_t{});
|
||||||
|
if (!MultiByteToWideChar(CP_UTF8, 0, &str[0], str.size(), &wstr[0], wstr_size))
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::error_code(GetLastError(), std::system_category()).message());
|
||||||
|
}
|
||||||
|
return wstr;
|
||||||
|
}
|
||||||
|
inline std::string utf16_to_utf8(const std::wstring& wstr)
|
||||||
|
{
|
||||||
|
if (wstr.empty())
|
||||||
|
return {};
|
||||||
|
int str_size = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], wstr.size(), NULL, 0, NULL, NULL);
|
||||||
|
if (str_size == 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::error_code(GetLastError(), std::system_category()).message());
|
||||||
|
}
|
||||||
|
std::string str(str_size, char{});
|
||||||
|
if (!WideCharToMultiByte(CP_UTF8, 0, &wstr[0], wstr.size(), &str[0], str_size, NULL, NULL))
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::error_code(GetLastError(), std::system_category()).message());
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //_STRING_TOOLS_H_
|
#endif //_STRING_TOOLS_H_
|
||||||
|
|
|
@ -47,6 +47,7 @@ using namespace epee;
|
||||||
static std::string generate_log_filename(const char *base)
|
static std::string generate_log_filename(const char *base)
|
||||||
{
|
{
|
||||||
std::string filename(base);
|
std::string filename(base);
|
||||||
|
static unsigned int fallback_counter = 0;
|
||||||
char tmp[200];
|
char tmp[200];
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
@ -56,7 +57,7 @@ static std::string generate_log_filename(const char *base)
|
||||||
#else
|
#else
|
||||||
(!gmtime_r(&now, &tm))
|
(!gmtime_r(&now, &tm))
|
||||||
#endif
|
#endif
|
||||||
strcpy(tmp, "unknown");
|
snprintf(tmp, sizeof(tmp), "part-%u", ++fallback_counter);
|
||||||
else
|
else
|
||||||
strftime(tmp, sizeof(tmp), "%Y-%m-%d-%H-%M-%S", &tm);
|
strftime(tmp, sizeof(tmp), "%Y-%m-%d-%H-%M-%S", &tm);
|
||||||
tmp[sizeof(tmp) - 1] = 0;
|
tmp[sizeof(tmp) - 1] = 0;
|
||||||
|
|
|
@ -148,6 +148,7 @@ struct txpool_tx_meta_t
|
||||||
uint8_t relayed;
|
uint8_t relayed;
|
||||||
uint8_t do_not_relay;
|
uint8_t do_not_relay;
|
||||||
uint8_t double_spend_seen: 1;
|
uint8_t double_spend_seen: 1;
|
||||||
|
uint8_t bf_padding: 7;
|
||||||
|
|
||||||
uint8_t padding[76]; // till 192 bytes
|
uint8_t padding[76]; // till 192 bytes
|
||||||
};
|
};
|
||||||
|
|
|
@ -165,7 +165,7 @@ int main(int argc, char* argv[])
|
||||||
"blackball-db-dir", "Specify blackball database directory",
|
"blackball-db-dir", "Specify blackball database directory",
|
||||||
get_default_db_path(),
|
get_default_db_path(),
|
||||||
{{ &arg_testnet_on, &arg_stagenet_on }},
|
{{ &arg_testnet_on, &arg_stagenet_on }},
|
||||||
[](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) {
|
[](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string {
|
||||||
if (testnet_stagenet[0])
|
if (testnet_stagenet[0])
|
||||||
return (boost::filesystem::path(val) / "testnet").string();
|
return (boost::filesystem::path(val) / "testnet").string();
|
||||||
else if (testnet_stagenet[1])
|
else if (testnet_stagenet[1])
|
||||||
|
|
|
@ -440,10 +440,15 @@ std::string get_nix_version_display_string()
|
||||||
|
|
||||||
if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate))
|
if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate))
|
||||||
{
|
{
|
||||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, psz_path, wcslen(psz_path), NULL, 0, NULL, NULL);
|
try
|
||||||
std::string folder_name(size_needed, 0);
|
{
|
||||||
WideCharToMultiByte(CP_UTF8, 0, psz_path, wcslen(psz_path), &folder_name[0], size_needed, NULL, NULL);
|
return string_tools::utf16_to_utf8(psz_path);
|
||||||
return folder_name;
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
MERROR("utf16_to_utf8 failed: " << e.what());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR("SHGetSpecialFolderPathW() failed, could not obtain requested path.");
|
LOG_ERROR("SHGetSpecialFolderPathW() failed, could not obtain requested path.");
|
||||||
|
@ -504,18 +509,20 @@ std::string get_nix_version_display_string()
|
||||||
int code;
|
int code;
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
// Maximizing chances for success
|
// Maximizing chances for success
|
||||||
WCHAR wide_replacement_name[1000];
|
std::wstring wide_replacement_name;
|
||||||
MultiByteToWideChar(CP_UTF8, 0, replacement_name.c_str(), replacement_name.size() + 1, wide_replacement_name, 1000);
|
try { wide_replacement_name = string_tools::utf8_to_utf16(replacement_name); }
|
||||||
WCHAR wide_replaced_name[1000];
|
catch (...) { return std::error_code(GetLastError(), std::system_category()); }
|
||||||
MultiByteToWideChar(CP_UTF8, 0, replaced_name.c_str(), replaced_name.size() + 1, wide_replaced_name, 1000);
|
std::wstring wide_replaced_name;
|
||||||
|
try { wide_replaced_name = string_tools::utf8_to_utf16(replaced_name); }
|
||||||
|
catch (...) { return std::error_code(GetLastError(), std::system_category()); }
|
||||||
|
|
||||||
DWORD attributes = ::GetFileAttributesW(wide_replaced_name);
|
DWORD attributes = ::GetFileAttributesW(wide_replaced_name.c_str());
|
||||||
if (INVALID_FILE_ATTRIBUTES != attributes)
|
if (INVALID_FILE_ATTRIBUTES != attributes)
|
||||||
{
|
{
|
||||||
::SetFileAttributesW(wide_replaced_name, attributes & (~FILE_ATTRIBUTE_READONLY));
|
::SetFileAttributesW(wide_replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = 0 != ::MoveFileExW(wide_replacement_name, wide_replaced_name, MOVEFILE_REPLACE_EXISTING);
|
bool ok = 0 != ::MoveFileExW(wide_replacement_name.c_str(), wide_replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING);
|
||||||
code = ok ? 0 : static_cast<int>(::GetLastError());
|
code = ok ? 0 : static_cast<int>(::GetLastError());
|
||||||
#else
|
#else
|
||||||
bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str());
|
bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str());
|
||||||
|
@ -657,6 +664,13 @@ std::string get_nix_version_display_string()
|
||||||
|
|
||||||
bool is_local_address(const std::string &address)
|
bool is_local_address(const std::string &address)
|
||||||
{
|
{
|
||||||
|
// always assume Tor/I2P addresses to be untrusted by default
|
||||||
|
if (boost::ends_with(address, ".onion") || boost::ends_with(address, ".i2p"))
|
||||||
|
{
|
||||||
|
MDEBUG("Address '" << address << "' is Tor/I2P, non local");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// extract host
|
// extract host
|
||||||
epee::net_utils::http::url_content u_c;
|
epee::net_utils::http::url_content u_c;
|
||||||
if (!epee::net_utils::parse_url(address, u_c))
|
if (!epee::net_utils::parse_url(address, u_c))
|
||||||
|
@ -750,4 +764,22 @@ std::string get_nix_version_display_string()
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str)
|
||||||
|
{
|
||||||
|
auto pos = str.find(":");
|
||||||
|
bool r = pos != std::string::npos;
|
||||||
|
uint32_t major;
|
||||||
|
r = r && epee::string_tools::get_xtype_from_string(major, str.substr(0, pos));
|
||||||
|
uint32_t minor;
|
||||||
|
r = r && epee::string_tools::get_xtype_from_string(minor, str.substr(pos + 1));
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
return std::make_pair(major, minor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include <boost/thread/locks.hpp>
|
#include <boost/thread/locks.hpp>
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -212,4 +213,6 @@ namespace tools
|
||||||
|
|
||||||
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash);
|
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash);
|
||||||
bool sha256sum(const std::string &filename, crypto::hash &hash);
|
bool sha256sum(const std::string &filename, crypto::hash &hash);
|
||||||
|
|
||||||
|
boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,7 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||||
void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
|
void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
|
||||||
{
|
{
|
||||||
crypto::secret_key fake;
|
crypto::secret_key fake;
|
||||||
memset(&fake, 0, sizeof(fake));
|
memset(&unwrap(fake), 0, sizeof(fake));
|
||||||
create_from_keys(address, fake, viewkey);
|
create_from_keys(address, fake, viewkey);
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
|
|
|
@ -442,7 +442,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
|
||||||
m_db->block_txn_stop();
|
m_db->block_txn_stop();
|
||||||
|
|
||||||
uint64_t num_popped_blocks = 0;
|
uint64_t num_popped_blocks = 0;
|
||||||
while (true)
|
while (!m_db->is_read_only())
|
||||||
{
|
{
|
||||||
const uint64_t top_height = m_db->height() - 1;
|
const uint64_t top_height = m_db->height() - 1;
|
||||||
const crypto::hash top_id = m_db->top_block_hash();
|
const crypto::hash top_id = m_db->top_block_hash();
|
||||||
|
@ -1941,14 +1941,21 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA
|
||||||
|
|
||||||
res.outs.clear();
|
res.outs.clear();
|
||||||
res.outs.reserve(req.outputs.size());
|
res.outs.reserve(req.outputs.size());
|
||||||
for (const auto &i: req.outputs)
|
try
|
||||||
{
|
{
|
||||||
// get tx_hash, tx_out_index from DB
|
for (const auto &i: req.outputs)
|
||||||
const output_data_t od = m_db->get_output_key(i.amount, i.index);
|
{
|
||||||
tx_out_index toi = m_db->get_output_tx_and_index(i.amount, i.index);
|
// get tx_hash, tx_out_index from DB
|
||||||
bool unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
|
const output_data_t od = m_db->get_output_key(i.amount, i.index);
|
||||||
|
tx_out_index toi = m_db->get_output_tx_and_index(i.amount, i.index);
|
||||||
|
bool unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
|
||||||
|
|
||||||
res.outs.push_back({od.pubkey, od.commitment, unlocked, od.height, toi.first});
|
res.outs.push_back({od.pubkey, od.commitment, unlocked, od.height, toi.first});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -676,6 +676,7 @@ namespace cryptonote
|
||||||
bool core::handle_incoming_txs(const std::list<blobdata>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
|
bool core::handle_incoming_txs(const std::list<blobdata>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
|
||||||
{
|
{
|
||||||
TRY_ENTRY();
|
TRY_ENTRY();
|
||||||
|
CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
|
||||||
|
|
||||||
struct result { bool res; cryptonote::transaction tx; crypto::hash hash; crypto::hash prefix_hash; bool in_txpool; bool in_blockchain; };
|
struct result { bool res; cryptonote::transaction tx; crypto::hash hash; crypto::hash prefix_hash; bool in_txpool; bool in_blockchain; };
|
||||||
std::vector<result> results(tx_blobs.size());
|
std::vector<result> results(tx_blobs.size());
|
||||||
|
|
|
@ -239,6 +239,7 @@ namespace cryptonote
|
||||||
meta.relayed = relayed;
|
meta.relayed = relayed;
|
||||||
meta.do_not_relay = do_not_relay;
|
meta.do_not_relay = do_not_relay;
|
||||||
meta.double_spend_seen = have_tx_keyimges_as_spent(tx);
|
meta.double_spend_seen = have_tx_keyimges_as_spent(tx);
|
||||||
|
meta.bf_padding = 0;
|
||||||
memset(meta.padding, 0, sizeof(meta.padding));
|
memset(meta.padding, 0, sizeof(meta.padding));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -278,6 +279,7 @@ namespace cryptonote
|
||||||
meta.relayed = relayed;
|
meta.relayed = relayed;
|
||||||
meta.do_not_relay = do_not_relay;
|
meta.do_not_relay = do_not_relay;
|
||||||
meta.double_spend_seen = false;
|
meta.double_spend_seen = false;
|
||||||
|
meta.bf_padding = 0;
|
||||||
memset(meta.padding, 0, sizeof(meta.padding));
|
memset(meta.padding, 0, sizeof(meta.padding));
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
|
@ -262,6 +262,9 @@ int main(int argc, char const * argv[])
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
rdln::suspend_readline pause_readline;
|
||||||
|
#endif
|
||||||
std::cerr << "Unknown command: " << command.front() << std::endl;
|
std::cerr << "Unknown command: " << command.front() << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -973,7 +973,7 @@ bool t_rpc_command_executor::print_transaction_pool_stats() {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memset(&res.pool_stats, 0, sizeof(res.pool_stats));
|
res.pool_stats = {};
|
||||||
if (!m_rpc_server->on_get_transaction_pool_stats(req, res, false) || res.status != CORE_RPC_STATUS_OK)
|
if (!m_rpc_server->on_get_transaction_pool_stats(req, res, false) || res.status != CORE_RPC_STATUS_OK)
|
||||||
{
|
{
|
||||||
tools::fail_msg_writer() << make_error(fail_message, res.status);
|
tools::fail_msg_writer() << make_error(fail_message, res.status);
|
||||||
|
|
|
@ -187,14 +187,15 @@ namespace hw {
|
||||||
void device_ledger::logCMD() {
|
void device_ledger::logCMD() {
|
||||||
if (apdu_verbose) {
|
if (apdu_verbose) {
|
||||||
char strbuffer[1024];
|
char strbuffer[1024];
|
||||||
sprintf(strbuffer, "%.02x %.02x %.02x %.02x %.02x ",
|
snprintf(strbuffer, sizeof(strbuffer), "%.02x %.02x %.02x %.02x %.02x ",
|
||||||
this->buffer_send[0],
|
this->buffer_send[0],
|
||||||
this->buffer_send[1],
|
this->buffer_send[1],
|
||||||
this->buffer_send[2],
|
this->buffer_send[2],
|
||||||
this->buffer_send[3],
|
this->buffer_send[3],
|
||||||
this->buffer_send[4]
|
this->buffer_send[4]
|
||||||
);
|
);
|
||||||
buffer_to_str(strbuffer+strlen(strbuffer), sizeof(strbuffer), (char*)(this->buffer_send+5), this->length_send-5);
|
const size_t len = strlen(strbuffer);
|
||||||
|
buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_send+5), this->length_send-5);
|
||||||
MDEBUG( "CMD :" << strbuffer);
|
MDEBUG( "CMD :" << strbuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,11 +203,12 @@ namespace hw {
|
||||||
void device_ledger::logRESP() {
|
void device_ledger::logRESP() {
|
||||||
if (apdu_verbose) {
|
if (apdu_verbose) {
|
||||||
char strbuffer[1024];
|
char strbuffer[1024];
|
||||||
sprintf(strbuffer, "%.02x%.02x ",
|
snprintf(strbuffer, sizeof(strbuffer), "%.02x%.02x ",
|
||||||
this->buffer_recv[this->length_recv-2],
|
this->buffer_recv[this->length_recv-2],
|
||||||
this->buffer_recv[this->length_recv-1]
|
this->buffer_recv[this->length_recv-1]
|
||||||
);
|
);
|
||||||
buffer_to_str(strbuffer+strlen(strbuffer), sizeof(strbuffer), (char*)(this->buffer_recv), this->length_recv-2);
|
const size_t len = strlen(strbuffer);
|
||||||
|
buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_recv), this->length_recv-2);
|
||||||
MDEBUG( "RESP :" << strbuffer);
|
MDEBUG( "RESP :" << strbuffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -293,7 +295,7 @@ namespace hw {
|
||||||
|
|
||||||
unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) {
|
unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) {
|
||||||
LONG rv;
|
LONG rv;
|
||||||
int sw;
|
unsigned int sw;
|
||||||
|
|
||||||
ASSERT_T0(this->length_send <= BUFFER_SEND_SIZE);
|
ASSERT_T0(this->length_send <= BUFFER_SEND_SIZE);
|
||||||
logCMD();
|
logCMD();
|
||||||
|
@ -302,6 +304,7 @@ namespace hw {
|
||||||
SCARD_PCI_T0, this->buffer_send, this->length_send,
|
SCARD_PCI_T0, this->buffer_send, this->length_send,
|
||||||
NULL, this->buffer_recv, &this->length_recv);
|
NULL, this->buffer_recv, &this->length_recv);
|
||||||
ASSERT_RV(rv);
|
ASSERT_RV(rv);
|
||||||
|
ASSERT_T0(this->length_recv >= 2);
|
||||||
ASSERT_T0(this->length_recv <= BUFFER_RECV_SIZE);
|
ASSERT_T0(this->length_recv <= BUFFER_RECV_SIZE);
|
||||||
logRESP();
|
logRESP();
|
||||||
|
|
||||||
|
|
|
@ -45,13 +45,13 @@ namespace hw {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_hexbuffer(std::string msg, const char* buff, size_t len) {
|
void log_hexbuffer(const std::string &msg, const char* buff, size_t len) {
|
||||||
char logstr[1025];
|
char logstr[1025];
|
||||||
buffer_to_str(logstr, sizeof(logstr), buff, len);
|
buffer_to_str(logstr, sizeof(logstr), buff, len);
|
||||||
MDEBUG(msg<< ": " << logstr);
|
MDEBUG(msg<< ": " << logstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_message(std::string msg, std::string info ) {
|
void log_message(const std::string &msg, const std::string &info ) {
|
||||||
MDEBUG(msg << ": " << info);
|
MDEBUG(msg << ": " << info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,16 +122,18 @@ namespace hw {
|
||||||
|
|
||||||
rct::keyV decrypt(const rct::keyV &keys) {
|
rct::keyV decrypt(const rct::keyV &keys) {
|
||||||
rct::keyV x ;
|
rct::keyV x ;
|
||||||
|
x.reserve(keys.size());
|
||||||
for (unsigned int j = 0; j<keys.size(); j++) {
|
for (unsigned int j = 0; j<keys.size(); j++) {
|
||||||
x.push_back(decrypt(keys[j]));
|
x.push_back(decrypt(keys[j]));
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check(std::string msg, std::string info, const char *h, const char *d, int len, bool crypted) {
|
static void check(const std::string &msg, const std::string &info, const char *h, const char *d, size_t len, bool crypted) {
|
||||||
char dd[32];
|
char dd[32];
|
||||||
char logstr[128];
|
char logstr[128];
|
||||||
|
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(len <= sizeof(dd), "invalid len");
|
||||||
memmove(dd,d,len);
|
memmove(dd,d,len);
|
||||||
if (crypted) {
|
if (crypted) {
|
||||||
CHECK_AND_ASSERT_THROW_MES(len<=32, "encrypted data greater than 32");
|
CHECK_AND_ASSERT_THROW_MES(len<=32, "encrypted data greater than 32");
|
||||||
|
@ -149,11 +151,11 @@ namespace hw {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check32(std::string msg, std::string info, const char *h, const char *d, bool crypted) {
|
void check32(const std::string &msg, const std::string &info, const char *h, const char *d, bool crypted) {
|
||||||
check(msg, info, h, d, 32, crypted);
|
check(msg, info, h, d, 32, crypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check8(std::string msg, std::string info, const char *h, const char *d, bool crypted) {
|
void check8(const std::string &msg, const std::string &info, const char *h, const char *d, bool crypted) {
|
||||||
check(msg, info, h, d, 8, crypted);
|
check(msg, info, h, d, 8, crypted);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -44,8 +44,8 @@ namespace hw {
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ;
|
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ;
|
||||||
void log_hexbuffer(std::string msg, const char* buff, size_t len);
|
void log_hexbuffer(const std::string &msg, const char* buff, size_t len);
|
||||||
void log_message(std::string msg, std::string info );
|
void log_message(const std::string &msg, const std::string &info );
|
||||||
#ifdef DEBUG_HWDEVICE
|
#ifdef DEBUG_HWDEVICE
|
||||||
#define TRACK printf("file %s:%d\n",__FILE__, __LINE__)
|
#define TRACK printf("file %s:%d\n",__FILE__, __LINE__)
|
||||||
//#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__)
|
//#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__)
|
||||||
|
@ -59,8 +59,8 @@ namespace hw {
|
||||||
crypto::ec_scalar decrypt(const crypto::ec_scalar &res);
|
crypto::ec_scalar decrypt(const crypto::ec_scalar &res);
|
||||||
rct::keyV decrypt(const rct::keyV &keys);
|
rct::keyV decrypt(const rct::keyV &keys);
|
||||||
|
|
||||||
void check32(std::string msg, std::string info, const char *h, const char *d, bool crypted=false);
|
void check32(const std::string &msg, const std::string &info, const char *h, const char *d, bool crypted=false);
|
||||||
void check8(std::string msg, std::string info, const char *h, const char *d, bool crypted=false);
|
void check8(const std::string &msg, const std::string &info, const char *h, const char *d, bool crypted=false);
|
||||||
|
|
||||||
void set_check_verbose(bool verbose);
|
void set_check_verbose(bool verbose);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1554,6 +1554,8 @@ namespace cryptonote
|
||||||
std::vector<txpool_histo> histo;
|
std::vector<txpool_histo> histo;
|
||||||
uint32_t num_double_spends;
|
uint32_t num_double_spends;
|
||||||
|
|
||||||
|
txpool_stats(): bytes_total(0), bytes_min(0), bytes_max(0), bytes_med(0), fee_total(0), oldest(0), txs_total(0), num_failing(0), num_10m(0), num_not_relayed(0), histo_98pc(0), num_double_spends(0) {}
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(bytes_total)
|
KV_SERIALIZE(bytes_total)
|
||||||
KV_SERIALIZE(bytes_min)
|
KV_SERIALIZE(bytes_min)
|
||||||
|
|
|
@ -104,6 +104,10 @@ bool ZmqServer::addTCPSocket(std::string address, std::string port)
|
||||||
|
|
||||||
rep_socket->setsockopt(ZMQ_RCVTIMEO, &DEFAULT_RPC_RECV_TIMEOUT_MS, sizeof(DEFAULT_RPC_RECV_TIMEOUT_MS));
|
rep_socket->setsockopt(ZMQ_RCVTIMEO, &DEFAULT_RPC_RECV_TIMEOUT_MS, sizeof(DEFAULT_RPC_RECV_TIMEOUT_MS));
|
||||||
|
|
||||||
|
if (address.empty())
|
||||||
|
address = "*";
|
||||||
|
if (port.empty())
|
||||||
|
port = "*";
|
||||||
std::string bind_address = addr_prefix + address + std::string(":") + port;
|
std::string bind_address = addr_prefix + address + std::string(":") + port;
|
||||||
rep_socket->bind(bind_address.c_str());
|
rep_socket->bind(bind_address.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,7 @@ namespace
|
||||||
const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
|
const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
|
||||||
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
|
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
|
||||||
const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
|
const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
|
||||||
|
const command_line::arg_descriptor<bool> arg_untrusted_daemon = {"untrusted-daemon", sw::tr("Disable commands which rely on a trusted daemon"), false};
|
||||||
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
|
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
|
||||||
const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
|
const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
|
||||||
const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
|
const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
|
||||||
|
@ -380,21 +381,10 @@ namespace
|
||||||
|
|
||||||
boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str)
|
boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str)
|
||||||
{
|
{
|
||||||
auto pos = str.find(":");
|
auto r = tools::parse_subaddress_lookahead(str);
|
||||||
bool r = pos != std::string::npos;
|
if (!r)
|
||||||
uint32_t major;
|
|
||||||
r = r && epee::string_tools::get_xtype_from_string(major, str.substr(0, pos));
|
|
||||||
uint32_t minor;
|
|
||||||
r = r && epee::string_tools::get_xtype_from_string(minor, str.substr(pos + 1));
|
|
||||||
if (r)
|
|
||||||
{
|
|
||||||
return std::make_pair(major, minor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail_msg_writer() << tr("invalid format for subaddress lookahead; must be <major>:<minor>");
|
fail_msg_writer() << tr("invalid format for subaddress lookahead; must be <major>:<minor>");
|
||||||
return {};
|
return r;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_transfer_exception(const std::exception_ptr &e, bool trusted_daemon)
|
void handle_transfer_exception(const std::exception_ptr &e, bool trusted_daemon)
|
||||||
|
@ -1077,7 +1067,7 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args)
|
||||||
fail_msg_writer() << tr("Failed to import multisig info: ") << e.what();
|
fail_msg_writer() << tr("Failed to import multisig info: ") << e.what();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_trusted_daemon)
|
if (is_daemon_trusted())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1229,7 +1219,7 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args)
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
handle_transfer_exception(std::current_exception(), m_trusted_daemon);
|
handle_transfer_exception(std::current_exception(), is_daemon_trusted());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -2027,7 +2017,7 @@ simple_wallet::simple_wallet()
|
||||||
tr("Stop mining in the daemon."));
|
tr("Stop mining in the daemon."));
|
||||||
m_cmd_binder.set_handler("set_daemon",
|
m_cmd_binder.set_handler("set_daemon",
|
||||||
boost::bind(&simple_wallet::set_daemon, this, _1),
|
boost::bind(&simple_wallet::set_daemon, this, _1),
|
||||||
tr("set_daemon <host>[:<port>]"),
|
tr("set_daemon <host>[:<port>] [trusted|untrusted]"),
|
||||||
tr("Set another daemon to connect to."));
|
tr("Set another daemon to connect to."));
|
||||||
m_cmd_binder.set_handler("save_bc",
|
m_cmd_binder.set_handler("save_bc",
|
||||||
boost::bind(&simple_wallet::save_bc, this, _1),
|
boost::bind(&simple_wallet::save_bc, this, _1),
|
||||||
|
@ -3117,18 +3107,22 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set --trusted-daemon if local
|
// set --trusted-daemon if local and not overridden
|
||||||
try
|
|
||||||
{
|
|
||||||
if (tools::is_local_address(m_wallet->get_daemon_address()))
|
|
||||||
{
|
|
||||||
MINFO(tr("Daemon is local, assuming trusted"));
|
|
||||||
m_trusted_daemon = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const std::exception &e) { }
|
|
||||||
|
|
||||||
if (!m_trusted_daemon)
|
if (!m_trusted_daemon)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_trusted_daemon = false;
|
||||||
|
if (tools::is_local_address(m_wallet->get_daemon_address()))
|
||||||
|
{
|
||||||
|
MINFO(tr("Daemon is local, assuming trusted"));
|
||||||
|
m_trusted_daemon = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_daemon_trusted())
|
||||||
message_writer() << (boost::format(tr("Warning: using an untrusted daemon at %s, privacy will be lessened")) % m_wallet->get_daemon_address()).str();
|
message_writer() << (boost::format(tr("Warning: using an untrusted daemon at %s, privacy will be lessened")) % m_wallet->get_daemon_address()).str();
|
||||||
|
|
||||||
if (m_wallet->get_ring_database().empty())
|
if (m_wallet->get_ring_database().empty())
|
||||||
|
@ -3162,7 +3156,10 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
|
||||||
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
|
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
|
||||||
m_restore_multisig_wallet = command_line::get_arg(vm, arg_restore_multisig_wallet);
|
m_restore_multisig_wallet = command_line::get_arg(vm, arg_restore_multisig_wallet);
|
||||||
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
|
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
|
||||||
m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon);
|
if (!command_line::is_arg_defaulted(vm, arg_trusted_daemon) || !command_line::is_arg_defaulted(vm, arg_untrusted_daemon))
|
||||||
|
m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon) && !command_line::get_arg(vm, arg_untrusted_daemon);
|
||||||
|
if (!command_line::is_arg_defaulted(vm, arg_trusted_daemon) && !command_line::is_arg_defaulted(vm, arg_untrusted_daemon))
|
||||||
|
message_writer() << tr("--trusted-daemon and --untrusted-daemon are both seen, assuming untrusted");
|
||||||
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
|
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
|
||||||
m_restore_height = command_line::get_arg(vm, arg_restore_height);
|
m_restore_height = command_line::get_arg(vm, arg_restore_height);
|
||||||
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
|
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
|
||||||
|
@ -3649,7 +3646,7 @@ bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool simple_wallet::start_mining(const std::vector<std::string>& args)
|
bool simple_wallet::start_mining(const std::vector<std::string>& args)
|
||||||
{
|
{
|
||||||
if (!m_trusted_daemon)
|
if (!is_daemon_trusted())
|
||||||
{
|
{
|
||||||
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
||||||
return true;
|
return true;
|
||||||
|
@ -3760,6 +3757,33 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
|
||||||
}
|
}
|
||||||
LOCK_IDLE_SCOPE();
|
LOCK_IDLE_SCOPE();
|
||||||
m_wallet->init(daemon_url);
|
m_wallet->init(daemon_url);
|
||||||
|
|
||||||
|
if (args.size() == 2)
|
||||||
|
{
|
||||||
|
if (args[1] == "trusted")
|
||||||
|
m_trusted_daemon = true;
|
||||||
|
else if (args[1] == "untrusted")
|
||||||
|
m_trusted_daemon = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Expected trusted or untrusted, got ") << args[1] << ": assuming untrusted";
|
||||||
|
m_trusted_daemon = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_trusted_daemon = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (tools::is_local_address(m_wallet->get_daemon_address()))
|
||||||
|
{
|
||||||
|
MINFO(tr("Daemon is local, assuming trusted"));
|
||||||
|
m_trusted_daemon = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) { }
|
||||||
|
}
|
||||||
|
success_msg_writer() << boost::format("Daemon set to %s, %s") % daemon_url % (*m_trusted_daemon ? tr("trusted") : tr("untrusted"));
|
||||||
} else {
|
} else {
|
||||||
fail_msg_writer() << tr("This does not seem to be a valid daemon URL.");
|
fail_msg_writer() << tr("This does not seem to be a valid daemon URL.");
|
||||||
}
|
}
|
||||||
|
@ -4145,7 +4169,7 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
|
bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
if (!m_trusted_daemon)
|
if (!is_daemon_trusted())
|
||||||
{
|
{
|
||||||
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
||||||
return true;
|
return true;
|
||||||
|
@ -4419,6 +4443,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<cryptonote::tx_destination_entry> dsts;
|
vector<cryptonote::tx_destination_entry> dsts;
|
||||||
|
size_t num_subaddresses = 0;
|
||||||
for (size_t i = 0; i < local_args.size(); i += 2)
|
for (size_t i = 0; i < local_args.size(); i += 2)
|
||||||
{
|
{
|
||||||
cryptonote::address_parse_info info;
|
cryptonote::address_parse_info info;
|
||||||
|
@ -4430,6 +4455,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
|
||||||
}
|
}
|
||||||
de.addr = info.address;
|
de.addr = info.address;
|
||||||
de.is_subaddress = info.is_subaddress;
|
de.is_subaddress = info.is_subaddress;
|
||||||
|
num_subaddresses += info.is_subaddress;
|
||||||
|
|
||||||
if (info.has_payment_id)
|
if (info.has_payment_id)
|
||||||
{
|
{
|
||||||
|
@ -4462,7 +4488,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
|
||||||
}
|
}
|
||||||
|
|
||||||
// prompt is there is no payment id and confirmation is required
|
// prompt is there is no payment id and confirmation is required
|
||||||
if (!payment_id_seen && m_wallet->confirm_missing_payment_id())
|
if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses)
|
||||||
{
|
{
|
||||||
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
|
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
|
||||||
if (std::cin.eof())
|
if (std::cin.eof())
|
||||||
|
@ -4491,16 +4517,16 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
unlock_block = bc_height + locked_blocks;
|
unlock_block = bc_height + locked_blocks;
|
||||||
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, m_trusted_daemon);
|
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
|
||||||
break;
|
break;
|
||||||
case TransferNew:
|
case TransferNew:
|
||||||
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, m_trusted_daemon);
|
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("Unknown transfer method, using original");
|
LOG_ERROR("Unknown transfer method, using original");
|
||||||
/* FALLTHRU */
|
/* FALLTHRU */
|
||||||
case TransferOriginal:
|
case TransferOriginal:
|
||||||
ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_trusted_daemon);
|
ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, is_daemon_trusted());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4676,7 +4702,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
handle_transfer_exception(std::current_exception(), m_trusted_daemon);
|
handle_transfer_exception(std::current_exception(), is_daemon_trusted());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -4713,7 +4739,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// figure out what tx will be necessary
|
// figure out what tx will be necessary
|
||||||
auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
|
auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(is_daemon_trusted());
|
||||||
|
|
||||||
if (ptx_vector.empty())
|
if (ptx_vector.empty())
|
||||||
{
|
{
|
||||||
|
@ -4782,9 +4808,23 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
||||||
commit_or_save(ptx_vector, m_do_not_relay);
|
commit_or_save(ptx_vector, m_do_not_relay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (const tools::error::not_enough_unlocked_money& e)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Not enough money in unlocked balance");
|
||||||
|
std::string accepted = input_line((boost::format(tr("Discarding %s of unmixable outputs that cannot be spent, which can be undone by \"rescan_spent\". Is this okay? (Y/Yes/N/No): ")) % print_money(e.available())).str());
|
||||||
|
if (std::cin.eof())
|
||||||
|
return true;
|
||||||
|
if (command_line::is_yes(accepted))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_wallet->discard_unmixable_outputs(is_daemon_trusted());
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
handle_transfer_exception(std::current_exception(), m_trusted_daemon);
|
handle_transfer_exception(std::current_exception(), is_daemon_trusted());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -4915,7 +4955,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
|
||||||
}
|
}
|
||||||
|
|
||||||
// prompt is there is no payment id and confirmation is required
|
// prompt is there is no payment id and confirmation is required
|
||||||
if (!payment_id_seen && m_wallet->confirm_missing_payment_id())
|
if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
|
||||||
{
|
{
|
||||||
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
|
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
|
||||||
if (std::cin.eof())
|
if (std::cin.eof())
|
||||||
|
@ -4933,7 +4973,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// figure out what tx will be necessary
|
// figure out what tx will be necessary
|
||||||
auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, m_trusted_daemon);
|
auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
|
||||||
|
|
||||||
if (ptx_vector.empty())
|
if (ptx_vector.empty())
|
||||||
{
|
{
|
||||||
|
@ -5017,7 +5057,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
handle_transfer_exception(std::current_exception(), m_trusted_daemon);
|
handle_transfer_exception(std::current_exception(), is_daemon_trusted());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -5128,7 +5168,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||||
}
|
}
|
||||||
|
|
||||||
// prompt if there is no payment id and confirmation is required
|
// prompt if there is no payment id and confirmation is required
|
||||||
if (!payment_id_seen && m_wallet->confirm_missing_payment_id())
|
if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
|
||||||
{
|
{
|
||||||
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
|
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
|
||||||
if (std::cin.eof())
|
if (std::cin.eof())
|
||||||
|
@ -5146,7 +5186,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// figure out what tx will be necessary
|
// figure out what tx will be necessary
|
||||||
auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, m_trusted_daemon);
|
auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, is_daemon_trusted());
|
||||||
|
|
||||||
if (ptx_vector.empty())
|
if (ptx_vector.empty())
|
||||||
{
|
{
|
||||||
|
@ -5216,7 +5256,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
handle_transfer_exception(std::current_exception(), m_trusted_daemon);
|
handle_transfer_exception(std::current_exception(), is_daemon_trusted());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -5521,7 +5561,7 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
handle_transfer_exception(std::current_exception(), m_trusted_daemon);
|
handle_transfer_exception(std::current_exception(), is_daemon_trusted());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -7109,7 +7149,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
|
||||||
fail_msg_writer() << tr("command not supported by HW wallet");
|
fail_msg_writer() << tr("command not supported by HW wallet");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!m_trusted_daemon)
|
if (!is_daemon_trusted())
|
||||||
{
|
{
|
||||||
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
|
||||||
return true;
|
return true;
|
||||||
|
@ -7495,6 +7535,7 @@ int main(int argc, char* argv[])
|
||||||
command_line::add_arg(desc_params, arg_non_deterministic );
|
command_line::add_arg(desc_params, arg_non_deterministic );
|
||||||
command_line::add_arg(desc_params, arg_electrum_seed );
|
command_line::add_arg(desc_params, arg_electrum_seed );
|
||||||
command_line::add_arg(desc_params, arg_trusted_daemon);
|
command_line::add_arg(desc_params, arg_trusted_daemon);
|
||||||
|
command_line::add_arg(desc_params, arg_untrusted_daemon);
|
||||||
command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
|
command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
|
||||||
command_line::add_arg(desc_params, arg_restore_height);
|
command_line::add_arg(desc_params, arg_restore_height);
|
||||||
command_line::add_arg(desc_params, arg_do_not_relay);
|
command_line::add_arg(desc_params, arg_do_not_relay);
|
||||||
|
|
|
@ -229,6 +229,7 @@ namespace cryptonote
|
||||||
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr);
|
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr);
|
||||||
std::string get_prompt() const;
|
std::string get_prompt() const;
|
||||||
bool print_seed(bool encrypted);
|
bool print_seed(bool encrypted);
|
||||||
|
bool is_daemon_trusted() const { return *m_trusted_daemon; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Prints the seed with a nice message
|
* \brief Prints the seed with a nice message
|
||||||
|
@ -331,7 +332,7 @@ namespace cryptonote
|
||||||
bool m_restore_deterministic_wallet; // recover flag
|
bool m_restore_deterministic_wallet; // recover flag
|
||||||
bool m_restore_multisig_wallet; // recover flag
|
bool m_restore_multisig_wallet; // recover flag
|
||||||
bool m_non_deterministic; // old 2-random generation
|
bool m_non_deterministic; // old 2-random generation
|
||||||
bool m_trusted_daemon;
|
boost::optional<bool> m_trusted_daemon;
|
||||||
bool m_allow_mismatched_daemon_version;
|
bool m_allow_mismatched_daemon_version;
|
||||||
bool m_restoring; // are we restoring, by whatever method?
|
bool m_restoring; // are we restoring, by whatever method?
|
||||||
uint64_t m_restore_height; // optional
|
uint64_t m_restore_height; // optional
|
||||||
|
|
|
@ -338,6 +338,7 @@ WalletImpl::WalletImpl(NetworkType nettype)
|
||||||
, m_trustedDaemon(false)
|
, m_trustedDaemon(false)
|
||||||
, m_wallet2Callback(nullptr)
|
, m_wallet2Callback(nullptr)
|
||||||
, m_recoveringFromSeed(false)
|
, m_recoveringFromSeed(false)
|
||||||
|
, m_recoveringFromDevice(false)
|
||||||
, m_synchronized(false)
|
, m_synchronized(false)
|
||||||
, m_rebuildWalletCache(false)
|
, m_rebuildWalletCache(false)
|
||||||
, m_is_connected(false)
|
, m_is_connected(false)
|
||||||
|
@ -385,6 +386,7 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co
|
||||||
|
|
||||||
clearStatus();
|
clearStatus();
|
||||||
m_recoveringFromSeed = false;
|
m_recoveringFromSeed = false;
|
||||||
|
m_recoveringFromDevice = false;
|
||||||
bool keys_file_exists;
|
bool keys_file_exists;
|
||||||
bool wallet_file_exists;
|
bool wallet_file_exists;
|
||||||
tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists);
|
tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists);
|
||||||
|
@ -584,11 +586,29 @@ bool WalletImpl::recoverFromKeysWithPassword(const std::string &path,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WalletImpl::recoverFromDevice(const std::string &path, const std::string &password, const std::string &device_name)
|
||||||
|
{
|
||||||
|
clearStatus();
|
||||||
|
m_recoveringFromSeed = false;
|
||||||
|
m_recoveringFromDevice = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_wallet->restore(path, password, device_name);
|
||||||
|
LOG_PRINT_L1("Generated new wallet from device: " + device_name);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
m_errorString = string(tr("failed to generate new wallet: ")) + e.what();
|
||||||
|
m_status = Status_Error;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool WalletImpl::open(const std::string &path, const std::string &password)
|
bool WalletImpl::open(const std::string &path, const std::string &password)
|
||||||
{
|
{
|
||||||
clearStatus();
|
clearStatus();
|
||||||
m_recoveringFromSeed = false;
|
m_recoveringFromSeed = false;
|
||||||
|
m_recoveringFromDevice = false;
|
||||||
try {
|
try {
|
||||||
// TODO: handle "deprecated"
|
// TODO: handle "deprecated"
|
||||||
// Check if wallet cache exists
|
// Check if wallet cache exists
|
||||||
|
@ -628,6 +648,7 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c
|
||||||
}
|
}
|
||||||
|
|
||||||
m_recoveringFromSeed = true;
|
m_recoveringFromSeed = true;
|
||||||
|
m_recoveringFromDevice = false;
|
||||||
crypto::secret_key recovery_key;
|
crypto::secret_key recovery_key;
|
||||||
std::string old_language;
|
std::string old_language;
|
||||||
if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) {
|
if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) {
|
||||||
|
@ -837,6 +858,16 @@ void WalletImpl::setRecoveringFromSeed(bool recoveringFromSeed)
|
||||||
m_recoveringFromSeed = recoveringFromSeed;
|
m_recoveringFromSeed = recoveringFromSeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WalletImpl::setRecoveringFromDevice(bool recoveringFromDevice)
|
||||||
|
{
|
||||||
|
m_recoveringFromDevice = recoveringFromDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WalletImpl::setSubaddressLookahead(uint32_t major, uint32_t minor)
|
||||||
|
{
|
||||||
|
m_wallet->set_subaddress_lookahead(major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t WalletImpl::balance(uint32_t accountIndex) const
|
uint64_t WalletImpl::balance(uint32_t accountIndex) const
|
||||||
{
|
{
|
||||||
return m_wallet->balance(accountIndex);
|
return m_wallet->balance(accountIndex);
|
||||||
|
@ -1839,7 +1870,7 @@ bool WalletImpl::isNewWallet() const
|
||||||
// with the daemon (pull hashes instead of pull blocks).
|
// with the daemon (pull hashes instead of pull blocks).
|
||||||
// If wallet cache is rebuilt, creation height stored in .keys is used.
|
// If wallet cache is rebuilt, creation height stored in .keys is used.
|
||||||
// Watch only wallet is a copy of an existing wallet.
|
// Watch only wallet is a copy of an existing wallet.
|
||||||
return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_rebuildWalletCache) && !watchOnly();
|
return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_recoveringFromDevice || m_rebuildWalletCache) && !watchOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit, bool ssl)
|
bool WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit, bool ssl)
|
||||||
|
|
|
@ -76,6 +76,9 @@ public:
|
||||||
const std::string &address_string,
|
const std::string &address_string,
|
||||||
const std::string &viewkey_string,
|
const std::string &viewkey_string,
|
||||||
const std::string &spendkey_string = "");
|
const std::string &spendkey_string = "");
|
||||||
|
bool recoverFromDevice(const std::string &path,
|
||||||
|
const std::string &password,
|
||||||
|
const std::string &device_name);
|
||||||
bool close(bool store = true);
|
bool close(bool store = true);
|
||||||
std::string seed() const;
|
std::string seed() const;
|
||||||
std::string getSeedLanguage() const;
|
std::string getSeedLanguage() const;
|
||||||
|
@ -113,6 +116,8 @@ public:
|
||||||
void setRefreshFromBlockHeight(uint64_t refresh_from_block_height);
|
void setRefreshFromBlockHeight(uint64_t refresh_from_block_height);
|
||||||
uint64_t getRefreshFromBlockHeight() const { return m_wallet->get_refresh_from_block_height(); };
|
uint64_t getRefreshFromBlockHeight() const { return m_wallet->get_refresh_from_block_height(); };
|
||||||
void setRecoveringFromSeed(bool recoveringFromSeed);
|
void setRecoveringFromSeed(bool recoveringFromSeed);
|
||||||
|
void setRecoveringFromDevice(bool recoveringFromDevice);
|
||||||
|
void setSubaddressLookahead(uint32_t major, uint32_t minor);
|
||||||
bool watchOnly() const;
|
bool watchOnly() const;
|
||||||
bool rescanSpent();
|
bool rescanSpent();
|
||||||
NetworkType nettype() const {return static_cast<NetworkType>(m_wallet->nettype());}
|
NetworkType nettype() const {return static_cast<NetworkType>(m_wallet->nettype());}
|
||||||
|
@ -216,6 +221,7 @@ private:
|
||||||
// so it shouldn't be considered as new and pull blocks (slow-refresh)
|
// so it shouldn't be considered as new and pull blocks (slow-refresh)
|
||||||
// instead of pulling hashes (fast-refresh)
|
// instead of pulling hashes (fast-refresh)
|
||||||
std::atomic<bool> m_recoveringFromSeed;
|
std::atomic<bool> m_recoveringFromSeed;
|
||||||
|
std::atomic<bool> m_recoveringFromDevice;
|
||||||
std::atomic<bool> m_synchronized;
|
std::atomic<bool> m_synchronized;
|
||||||
std::atomic<bool> m_rebuildWalletCache;
|
std::atomic<bool> m_rebuildWalletCache;
|
||||||
// cache connection status to avoid unnecessary RPC calls
|
// cache connection status to avoid unnecessary RPC calls
|
||||||
|
|
|
@ -468,6 +468,21 @@ struct Wallet
|
||||||
*/
|
*/
|
||||||
virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0;
|
virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief setRecoveringFromDevice - set state to recovering from device
|
||||||
|
*
|
||||||
|
* \param recoveringFromDevice - true/false
|
||||||
|
*/
|
||||||
|
virtual void setRecoveringFromDevice(bool recoveringFromDevice) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief setSubaddressLookahead - set size of subaddress lookahead
|
||||||
|
*
|
||||||
|
* \param major - size fot the major index
|
||||||
|
* \param minor - size fot the minor index
|
||||||
|
*/
|
||||||
|
virtual void setSubaddressLookahead(uint32_t major, uint32_t minor) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief connectToDaemon - connects to the daemon. TODO: check if it can be removed
|
* @brief connectToDaemon - connects to the daemon. TODO: check if it can be removed
|
||||||
* @return
|
* @return
|
||||||
|
@ -916,6 +931,23 @@ struct WalletManager
|
||||||
return createWalletFromKeys(path, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString);
|
return createWalletFromKeys(path, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief creates wallet using hardware device.
|
||||||
|
* \param path Name of wallet file to be created
|
||||||
|
* \param password Password of wallet file
|
||||||
|
* \param nettype Network type
|
||||||
|
* \param deviceName Device name
|
||||||
|
* \param restoreHeight restore from start height (0 sets to current height)
|
||||||
|
* \param subaddressLookahead Size of subaddress lookahead (empty sets to some default low value)
|
||||||
|
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
|
||||||
|
*/
|
||||||
|
virtual Wallet * createWalletFromDevice(const std::string &path,
|
||||||
|
const std::string &password,
|
||||||
|
NetworkType nettype,
|
||||||
|
const std::string &deviceName,
|
||||||
|
uint64_t restoreHeight = 0,
|
||||||
|
const std::string &subaddressLookahead = "") = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted
|
* \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted
|
||||||
* \param wallet previously opened / created wallet instance
|
* \param wallet previously opened / created wallet instance
|
||||||
|
|
|
@ -114,6 +114,26 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path,
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
|
||||||
|
const std::string &password,
|
||||||
|
NetworkType nettype,
|
||||||
|
const std::string &deviceName,
|
||||||
|
uint64_t restoreHeight,
|
||||||
|
const std::string &subaddressLookahead)
|
||||||
|
{
|
||||||
|
WalletImpl * wallet = new WalletImpl(nettype);
|
||||||
|
if(restoreHeight > 0){
|
||||||
|
wallet->setRefreshFromBlockHeight(restoreHeight);
|
||||||
|
}
|
||||||
|
auto lookahead = tools::parse_subaddress_lookahead(subaddressLookahead);
|
||||||
|
if (lookahead)
|
||||||
|
{
|
||||||
|
wallet->setSubaddressLookahead(lookahead->first, lookahead->second);
|
||||||
|
}
|
||||||
|
wallet->recoverFromDevice(path, password, deviceName);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
bool WalletManagerImpl::closeWallet(Wallet *wallet, bool store)
|
bool WalletManagerImpl::closeWallet(Wallet *wallet, bool store)
|
||||||
{
|
{
|
||||||
WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
|
WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
|
||||||
|
|
|
@ -64,6 +64,12 @@ public:
|
||||||
const std::string &addressString,
|
const std::string &addressString,
|
||||||
const std::string &viewKeyString,
|
const std::string &viewKeyString,
|
||||||
const std::string &spendKeyString = "");
|
const std::string &spendKeyString = "");
|
||||||
|
virtual Wallet * createWalletFromDevice(const std::string &path,
|
||||||
|
const std::string &password,
|
||||||
|
NetworkType nettype,
|
||||||
|
const std::string &deviceName,
|
||||||
|
uint64_t restoreHeight = 0,
|
||||||
|
const std::string &subaddressLookahead = "");
|
||||||
virtual bool closeWallet(Wallet *wallet, bool store = true);
|
virtual bool closeWallet(Wallet *wallet, bool store = true);
|
||||||
bool walletExists(const std::string &path);
|
bool walletExists(const std::string &path);
|
||||||
bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const;
|
bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const;
|
||||||
|
|
|
@ -940,6 +940,7 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
|
||||||
}
|
}
|
||||||
m_subaddress_labels.resize(index.major + 1, {"Untitled account"});
|
m_subaddress_labels.resize(index.major + 1, {"Untitled account"});
|
||||||
m_subaddress_labels[index.major].resize(index.minor + 1);
|
m_subaddress_labels[index.major].resize(index.minor + 1);
|
||||||
|
get_account_tags();
|
||||||
}
|
}
|
||||||
else if (m_subaddress_labels[index.major].size() <= index.minor)
|
else if (m_subaddress_labels[index.major].size() <= index.minor)
|
||||||
{
|
{
|
||||||
|
@ -1109,6 +1110,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||||
// Don't try to extract tx public key if tx has no ouputs
|
// Don't try to extract tx public key if tx has no ouputs
|
||||||
size_t pk_index = 0;
|
size_t pk_index = 0;
|
||||||
std::vector<tx_scan_info_t> tx_scan_info(tx.vout.size());
|
std::vector<tx_scan_info_t> tx_scan_info(tx.vout.size());
|
||||||
|
std::unordered_set<crypto::public_key> public_keys_seen;
|
||||||
while (!tx.vout.empty())
|
while (!tx.vout.empty())
|
||||||
{
|
{
|
||||||
// if tx.vout is not empty, we loop through all tx pubkeys
|
// if tx.vout is not empty, we loop through all tx pubkeys
|
||||||
|
@ -1124,6 +1126,13 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (public_keys_seen.find(pub_key_field.pub_key) != public_keys_seen.end())
|
||||||
|
{
|
||||||
|
MWARNING("The same transaction pubkey is present more than once, ignoring extra instance");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
public_keys_seen.insert(pub_key_field.pub_key);
|
||||||
|
|
||||||
int num_vouts_received = 0;
|
int num_vouts_received = 0;
|
||||||
tx_pub_key = pub_key_field.pub_key;
|
tx_pub_key = pub_key_field.pub_key;
|
||||||
tools::threadpool& tpool = tools::threadpool::getInstance();
|
tools::threadpool& tpool = tools::threadpool::getInstance();
|
||||||
|
@ -1143,13 +1152,16 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||||
// additional tx pubkeys and derivations for multi-destination transfers involving one or more subaddresses
|
// additional tx pubkeys and derivations for multi-destination transfers involving one or more subaddresses
|
||||||
std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
|
std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
|
||||||
std::vector<crypto::key_derivation> additional_derivations;
|
std::vector<crypto::key_derivation> additional_derivations;
|
||||||
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
|
if (pk_index == 1)
|
||||||
{
|
{
|
||||||
additional_derivations.push_back({});
|
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
|
||||||
if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
|
|
||||||
{
|
{
|
||||||
MWARNING("Failed to generate key derivation from tx pubkey, skipping");
|
additional_derivations.push_back({});
|
||||||
additional_derivations.pop_back();
|
if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
|
||||||
|
{
|
||||||
|
MWARNING("Failed to generate key derivation from tx pubkey, skipping");
|
||||||
|
additional_derivations.pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hwdev_lock.unlock();
|
hwdev_lock.unlock();
|
||||||
|
@ -1299,20 +1311,20 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||||
m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index);
|
m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_transfers[kit->second].m_spent || m_transfers[kit->second].amount() >= tx.vout[o].amount)
|
else if (m_transfers[kit->second].m_spent || m_transfers[kit->second].amount() >= tx_scan_info[o].amount)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Public key " << epee::string_tools::pod_to_hex(kit->first)
|
LOG_ERROR("Public key " << epee::string_tools::pod_to_hex(kit->first)
|
||||||
<< " from received " << print_money(tx.vout[o].amount) << " output already exists with "
|
<< " from received " << print_money(tx_scan_info[o].amount) << " output already exists with "
|
||||||
<< (m_transfers[kit->second].m_spent ? "spent" : "unspent") << " "
|
<< (m_transfers[kit->second].m_spent ? "spent" : "unspent") << " "
|
||||||
<< print_money(m_transfers[kit->second].amount()) << ", received output ignored");
|
<< print_money(m_transfers[kit->second].amount()) << " in tx " << m_transfers[kit->second].m_txid << ", received output ignored");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_ERROR("Public key " << epee::string_tools::pod_to_hex(kit->first)
|
LOG_ERROR("Public key " << epee::string_tools::pod_to_hex(kit->first)
|
||||||
<< " from received " << print_money(tx.vout[o].amount) << " output already exists with "
|
<< " from received " << print_money(tx_scan_info[o].amount) << " output already exists with "
|
||||||
<< print_money(m_transfers[kit->second].amount()) << ", replacing with new output");
|
<< print_money(m_transfers[kit->second].amount()) << ", replacing with new output");
|
||||||
// The new larger output replaced a previous smaller one
|
// The new larger output replaced a previous smaller one
|
||||||
tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx.vout[o].amount;
|
tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount;
|
||||||
|
|
||||||
if (!pool)
|
if (!pool)
|
||||||
{
|
{
|
||||||
|
@ -3260,6 +3272,12 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
|
||||||
cryptonote::block b;
|
cryptonote::block b;
|
||||||
generate_genesis(b);
|
generate_genesis(b);
|
||||||
m_blockchain.push_back(get_block_hash(b));
|
m_blockchain.push_back(get_block_hash(b));
|
||||||
|
if (m_subaddress_lookahead_major == SUBADDRESS_LOOKAHEAD_MAJOR && m_subaddress_lookahead_minor == SUBADDRESS_LOOKAHEAD_MINOR)
|
||||||
|
{
|
||||||
|
// the default lookahead setting (50:200) is clearly too much for hardware wallet
|
||||||
|
m_subaddress_lookahead_major = 5;
|
||||||
|
m_subaddress_lookahead_minor = 20;
|
||||||
|
}
|
||||||
add_subaddress_account(tr("Primary account"));
|
add_subaddress_account(tr("Primary account"));
|
||||||
if (!wallet_.empty()) {
|
if (!wallet_.empty()) {
|
||||||
store();
|
store();
|
||||||
|
@ -3772,7 +3790,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
|
||||||
{
|
{
|
||||||
wallet2::cache_file_data cache_file_data;
|
wallet2::cache_file_data cache_file_data;
|
||||||
std::string buf;
|
std::string buf;
|
||||||
bool r = epee::file_io_utils::load_file_to_string(m_wallet_file, buf);
|
bool r = epee::file_io_utils::load_file_to_string(m_wallet_file, buf, std::numeric_limits<size_t>::max());
|
||||||
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);
|
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);
|
||||||
|
|
||||||
// try to read it as an encrypted cache
|
// try to read it as an encrypted cache
|
||||||
|
@ -7340,8 +7358,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
cryptonote::transaction tx;
|
cryptonote::transaction tx;
|
||||||
pending_tx ptx;
|
pending_tx ptx;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
|
uint64_t needed_fee;
|
||||||
std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
|
std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
|
||||||
|
|
||||||
|
TX() : bytes(0), needed_fee(0) {}
|
||||||
|
|
||||||
void add(const account_public_address &addr, bool is_subaddress, uint64_t amount, unsigned int original_output_index, bool merge_destinations) {
|
void add(const account_public_address &addr, bool is_subaddress, uint64_t amount, unsigned int original_output_index, bool merge_destinations) {
|
||||||
if (merge_destinations)
|
if (merge_destinations)
|
||||||
{
|
{
|
||||||
|
@ -7734,6 +7755,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
tx.ptx = test_ptx;
|
tx.ptx = test_ptx;
|
||||||
tx.bytes = txBlob.size();
|
tx.bytes = txBlob.size();
|
||||||
tx.outs = outs;
|
tx.outs = outs;
|
||||||
|
tx.needed_fee = needed_fee;
|
||||||
accumulated_fee += test_ptx.fee;
|
accumulated_fee += test_ptx.fee;
|
||||||
accumulated_change += test_ptx.change_dts.amount;
|
accumulated_change += test_ptx.change_dts.amount;
|
||||||
adding_fee = false;
|
adding_fee = false;
|
||||||
|
@ -7785,7 +7807,7 @@ skip_tx:
|
||||||
fake_outs_count, /* CONST size_t fake_outputs_count, */
|
fake_outs_count, /* CONST size_t fake_outputs_count, */
|
||||||
tx.outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */
|
tx.outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */
|
||||||
unlock_time, /* CONST uint64_t unlock_time, */
|
unlock_time, /* CONST uint64_t unlock_time, */
|
||||||
needed_fee, /* CONST uint64_t fee, */
|
tx.needed_fee, /* CONST uint64_t fee, */
|
||||||
extra, /* const std::vector<uint8_t>& extra, */
|
extra, /* const std::vector<uint8_t>& extra, */
|
||||||
test_tx, /* OUT cryptonote::transaction& tx, */
|
test_tx, /* OUT cryptonote::transaction& tx, */
|
||||||
test_ptx, /* OUT cryptonote::transaction& tx, */
|
test_ptx, /* OUT cryptonote::transaction& tx, */
|
||||||
|
@ -7796,7 +7818,7 @@ skip_tx:
|
||||||
fake_outs_count,
|
fake_outs_count,
|
||||||
tx.outs,
|
tx.outs,
|
||||||
unlock_time,
|
unlock_time,
|
||||||
needed_fee,
|
tx.needed_fee,
|
||||||
extra,
|
extra,
|
||||||
detail::digit_split_strategy,
|
detail::digit_split_strategy,
|
||||||
tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD),
|
tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD),
|
||||||
|
@ -7817,7 +7839,7 @@ skip_tx:
|
||||||
for (size_t idx: tx.selected_transfers)
|
for (size_t idx: tx.selected_transfers)
|
||||||
tx_money += m_transfers[idx].amount();
|
tx_money += m_transfers[idx].amount();
|
||||||
LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
|
LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
|
||||||
": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() <<
|
" " << get_transaction_hash(tx.ptx.tx) << ": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() <<
|
||||||
" outputs to " << tx.dsts.size() << " destination(s), including " <<
|
" outputs to " << tx.dsts.size() << " destination(s), including " <<
|
||||||
print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change");
|
print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change");
|
||||||
ptx_vector.push_back(tx.ptx);
|
ptx_vector.push_back(tx.ptx);
|
||||||
|
@ -7916,7 +7938,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
cryptonote::transaction tx;
|
cryptonote::transaction tx;
|
||||||
pending_tx ptx;
|
pending_tx ptx;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
|
uint64_t needed_fee;
|
||||||
std::vector<std::vector<get_outs_entry>> outs;
|
std::vector<std::vector<get_outs_entry>> outs;
|
||||||
|
|
||||||
|
TX() : bytes(0), needed_fee(0) {}
|
||||||
};
|
};
|
||||||
std::vector<TX> txes;
|
std::vector<TX> txes;
|
||||||
uint64_t needed_fee, available_for_fee = 0;
|
uint64_t needed_fee, available_for_fee = 0;
|
||||||
|
@ -8014,6 +8039,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
tx.ptx = test_ptx;
|
tx.ptx = test_ptx;
|
||||||
tx.bytes = txBlob.size();
|
tx.bytes = txBlob.size();
|
||||||
tx.outs = outs;
|
tx.outs = outs;
|
||||||
|
tx.needed_fee = needed_fee;
|
||||||
accumulated_fee += test_ptx.fee;
|
accumulated_fee += test_ptx.fee;
|
||||||
accumulated_change += test_ptx.change_dts.amount;
|
accumulated_change += test_ptx.change_dts.amount;
|
||||||
if (!unused_transfers_indices.empty() || !unused_dust_indices.empty())
|
if (!unused_transfers_indices.empty() || !unused_dust_indices.empty())
|
||||||
|
@ -8034,10 +8060,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
cryptonote::transaction test_tx;
|
cryptonote::transaction test_tx;
|
||||||
pending_tx test_ptx;
|
pending_tx test_ptx;
|
||||||
if (use_rct) {
|
if (use_rct) {
|
||||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, needed_fee, extra,
|
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.needed_fee, extra,
|
||||||
test_tx, test_ptx, bulletproof);
|
test_tx, test_ptx, bulletproof);
|
||||||
} else {
|
} else {
|
||||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, needed_fee, extra,
|
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.needed_fee, extra,
|
||||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||||
}
|
}
|
||||||
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
||||||
|
@ -8054,7 +8080,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
for (size_t idx: tx.selected_transfers)
|
for (size_t idx: tx.selected_transfers)
|
||||||
tx_money += m_transfers[idx].amount();
|
tx_money += m_transfers[idx].amount();
|
||||||
LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
|
LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
|
||||||
": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() <<
|
" " << get_transaction_hash(tx.ptx.tx) << ": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() <<
|
||||||
" outputs to " << tx.dsts.size() << " destination(s), including " <<
|
" outputs to " << tx.dsts.size() << " destination(s), including " <<
|
||||||
print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change");
|
print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change");
|
||||||
ptx_vector.push_back(tx.ptx);
|
ptx_vector.push_back(tx.ptx);
|
||||||
|
@ -8241,6 +8267,16 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo
|
||||||
|
|
||||||
return create_transactions_from(m_account_public_address, false, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>(), trusted_daemon);
|
return create_transactions_from(m_account_public_address, false, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>(), trusted_daemon);
|
||||||
}
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
void wallet2::discard_unmixable_outputs(bool trusted_daemon)
|
||||||
|
{
|
||||||
|
// may throw
|
||||||
|
std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs(trusted_daemon);
|
||||||
|
for (size_t idx : unmixable_outputs)
|
||||||
|
{
|
||||||
|
m_transfers[idx].m_spent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const
|
bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const
|
||||||
{
|
{
|
||||||
|
@ -9145,9 +9181,9 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
|
||||||
uint64_t wallet2::get_approximate_blockchain_height() const
|
uint64_t wallet2::get_approximate_blockchain_height() const
|
||||||
{
|
{
|
||||||
// time of v2 fork
|
// time of v2 fork
|
||||||
const time_t fork_time = m_nettype == TESTNET ? 1448285909 : m_nettype == STAGENET ? (time_t)-1/*TODO*/ : 1458748658;
|
const time_t fork_time = m_nettype == TESTNET ? 1448285909 : m_nettype == STAGENET ? 1520937818 : 1458748658;
|
||||||
// v2 fork block
|
// v2 fork block
|
||||||
const uint64_t fork_block = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? (uint64_t)-1/*TODO*/ : 1009827;
|
const uint64_t fork_block = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827;
|
||||||
// avg seconds per block
|
// avg seconds per block
|
||||||
const int seconds_per_block = DIFFICULTY_TARGET_V2;
|
const int seconds_per_block = DIFFICULTY_TARGET_V2;
|
||||||
// Calculated blockchain height
|
// Calculated blockchain height
|
||||||
|
@ -9523,7 +9559,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
std::unordered_set<crypto::hash> spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input.
|
std::unordered_set<crypto::hash> spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input.
|
||||||
std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx
|
std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx
|
||||||
// was created by sweep_all, so we can't know the spent height and other detailed info.
|
// was created by sweep_all, so we can't know the spent height and other detailed info.
|
||||||
for(size_t i = 0; i < m_transfers.size(); ++i)
|
for(size_t i = 0; i < signed_key_images.size(); ++i)
|
||||||
{
|
{
|
||||||
transfer_details &td = m_transfers[i];
|
transfer_details &td = m_transfers[i];
|
||||||
uint64_t amount = td.amount();
|
uint64_t amount = td.amount();
|
||||||
|
|
|
@ -704,6 +704,7 @@ namespace tools
|
||||||
bool sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto::hash> &txids);
|
bool sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto::hash> &txids);
|
||||||
bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector<crypto::hash> &txids);
|
bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector<crypto::hash> &txids);
|
||||||
std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon);
|
std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon);
|
||||||
|
void discard_unmixable_outputs(bool trusted_daemon);
|
||||||
bool check_connection(uint32_t *version = NULL, uint32_t timeout = 200000);
|
bool check_connection(uint32_t *version = NULL, uint32_t timeout = 200000);
|
||||||
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
||||||
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments, uint64_t min_height = 0, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
|
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments, uint64_t min_height = 0, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
|
||||||
|
|
|
@ -179,6 +179,10 @@ namespace wallet_args
|
||||||
{
|
{
|
||||||
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
|
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
|
||||||
}
|
}
|
||||||
|
else if (!log_to_console)
|
||||||
|
{
|
||||||
|
mlog_set_categories("");
|
||||||
|
}
|
||||||
|
|
||||||
if (notice)
|
if (notice)
|
||||||
Print(print) << notice << ENDL;
|
Print(print) << notice << ENDL;
|
||||||
|
|
|
@ -362,6 +362,7 @@ namespace tools
|
||||||
if (!m_wallet) return not_open(er);
|
if (!m_wallet) return not_open(er);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
THROW_WALLET_EXCEPTION_IF(req.account_index >= m_wallet->get_num_subaddress_accounts(), error::account_index_outofbound);
|
||||||
res.addresses.clear();
|
res.addresses.clear();
|
||||||
std::vector<uint32_t> req_address_index;
|
std::vector<uint32_t> req_address_index;
|
||||||
if (req.address_index.empty())
|
if (req.address_index.empty())
|
||||||
|
@ -377,6 +378,7 @@ namespace tools
|
||||||
m_wallet->get_transfers(transfers);
|
m_wallet->get_transfers(transfers);
|
||||||
for (uint32_t i : req_address_index)
|
for (uint32_t i : req_address_index)
|
||||||
{
|
{
|
||||||
|
THROW_WALLET_EXCEPTION_IF(i >= m_wallet->get_num_subaddresses(req.account_index), error::address_index_outofbound);
|
||||||
res.addresses.resize(res.addresses.size() + 1);
|
res.addresses.resize(res.addresses.size() + 1);
|
||||||
auto& info = res.addresses.back();
|
auto& info = res.addresses.back();
|
||||||
const cryptonote::subaddress_index index = {req.account_index, i};
|
const cryptonote::subaddress_index index = {req.account_index, i};
|
||||||
|
@ -500,6 +502,7 @@ namespace tools
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::on_get_account_tags(const wallet_rpc::COMMAND_RPC_GET_ACCOUNT_TAGS::request& req, wallet_rpc::COMMAND_RPC_GET_ACCOUNT_TAGS::response& res, epee::json_rpc::error& er)
|
bool wallet_rpc_server::on_get_account_tags(const wallet_rpc::COMMAND_RPC_GET_ACCOUNT_TAGS::request& req, wallet_rpc::COMMAND_RPC_GET_ACCOUNT_TAGS::response& res, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
|
if (!m_wallet) return not_open(er);
|
||||||
const std::pair<std::map<std::string, std::string>, std::vector<std::string>> account_tags = m_wallet->get_account_tags();
|
const std::pair<std::map<std::string, std::string>, std::vector<std::string>> account_tags = m_wallet->get_account_tags();
|
||||||
for (const std::pair<std::string, std::string>& p : account_tags.first)
|
for (const std::pair<std::string, std::string>& p : account_tags.first)
|
||||||
{
|
{
|
||||||
|
@ -518,6 +521,7 @@ namespace tools
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::on_tag_accounts(const wallet_rpc::COMMAND_RPC_TAG_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_TAG_ACCOUNTS::response& res, epee::json_rpc::error& er)
|
bool wallet_rpc_server::on_tag_accounts(const wallet_rpc::COMMAND_RPC_TAG_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_TAG_ACCOUNTS::response& res, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
|
if (!m_wallet) return not_open(er);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_wallet->set_account_tag(req.accounts, req.tag);
|
m_wallet->set_account_tag(req.accounts, req.tag);
|
||||||
|
@ -532,6 +536,7 @@ namespace tools
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::on_untag_accounts(const wallet_rpc::COMMAND_RPC_UNTAG_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_UNTAG_ACCOUNTS::response& res, epee::json_rpc::error& er)
|
bool wallet_rpc_server::on_untag_accounts(const wallet_rpc::COMMAND_RPC_UNTAG_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_UNTAG_ACCOUNTS::response& res, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
|
if (!m_wallet) return not_open(er);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_wallet->set_account_tag(req.accounts, "");
|
m_wallet->set_account_tag(req.accounts, "");
|
||||||
|
@ -546,6 +551,7 @@ namespace tools
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::on_set_account_tag_description(const wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::request& req, wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::response& res, epee::json_rpc::error& er)
|
bool wallet_rpc_server::on_set_account_tag_description(const wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::request& req, wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::response& res, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
|
if (!m_wallet) return not_open(er);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_wallet->set_account_tag_description(req.tag, req.description);
|
m_wallet->set_account_tag_description(req.tag, req.description);
|
||||||
|
@ -2054,6 +2060,7 @@ namespace tools
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::on_make_uri(const wallet_rpc::COMMAND_RPC_MAKE_URI::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI::response& res, epee::json_rpc::error& er)
|
bool wallet_rpc_server::on_make_uri(const wallet_rpc::COMMAND_RPC_MAKE_URI::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI::response& res, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
|
if (!m_wallet) return not_open(er);
|
||||||
std::string error;
|
std::string error;
|
||||||
std::string uri = m_wallet->make_uri(req.address, req.payment_id, req.amount, req.tx_description, req.recipient_name, error);
|
std::string uri = m_wallet->make_uri(req.address, req.payment_id, req.amount, req.tx_description, req.recipient_name, error);
|
||||||
if (uri.empty())
|
if (uri.empty())
|
||||||
|
@ -2267,6 +2274,7 @@ namespace tools
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::on_stop_mining(const wallet_rpc::COMMAND_RPC_STOP_MINING::request& req, wallet_rpc::COMMAND_RPC_STOP_MINING::response& res, epee::json_rpc::error& er)
|
bool wallet_rpc_server::on_stop_mining(const wallet_rpc::COMMAND_RPC_STOP_MINING::request& req, wallet_rpc::COMMAND_RPC_STOP_MINING::response& res, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
|
if (!m_wallet) return not_open(er);
|
||||||
cryptonote::COMMAND_RPC_STOP_MINING::request daemon_req;
|
cryptonote::COMMAND_RPC_STOP_MINING::request daemon_req;
|
||||||
cryptonote::COMMAND_RPC_STOP_MINING::response daemon_res;
|
cryptonote::COMMAND_RPC_STOP_MINING::response daemon_res;
|
||||||
bool r = m_wallet->invoke_http_json("/stop_mining", daemon_req, daemon_res);
|
bool r = m_wallet->invoke_http_json("/stop_mining", daemon_req, daemon_res);
|
||||||
|
|
|
@ -158,6 +158,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool close() { return true; }
|
virtual bool close() { return true; }
|
||||||
|
virtual bool send_done() { return true; }
|
||||||
virtual bool call_run_once_service_io() { return true; }
|
virtual bool call_run_once_service_io() { return true; }
|
||||||
virtual bool request_callback() { return true; }
|
virtual bool request_callback() { return true; }
|
||||||
virtual boost::asio::io_service& get_io_service() { return m_io_service; }
|
virtual boost::asio::io_service& get_io_service() { return m_io_service; }
|
||||||
|
|
|
@ -150,6 +150,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool close() { /*std::cout << "test_connection::close()" << std::endl; */return true; }
|
virtual bool close() { /*std::cout << "test_connection::close()" << std::endl; */return true; }
|
||||||
|
virtual bool send_done() { /*std::cout << "test_connection::send_done()" << std::endl; */return true; }
|
||||||
virtual bool call_run_once_service_io() { std::cout << "test_connection::call_run_once_service_io()" << std::endl; return true; }
|
virtual bool call_run_once_service_io() { std::cout << "test_connection::call_run_once_service_io()" << std::endl; return true; }
|
||||||
virtual bool request_callback() { std::cout << "test_connection::request_callback()" << std::endl; return true; }
|
virtual bool request_callback() { std::cout << "test_connection::request_callback()" << std::endl; return true; }
|
||||||
virtual boost::asio::io_service& get_io_service() { std::cout << "test_connection::get_io_service()" << std::endl; return m_io_service; }
|
virtual boost::asio::io_service& get_io_service() { std::cout << "test_connection::get_io_service()" << std::endl; return m_io_service; }
|
||||||
|
|
Loading…
Reference in a new issue