Compare commits

..

35 Commits

Author SHA1 Message Date
wowario
cdb068cd0b Merge pull request 'upstream' (#402) from wowario/wownero:upstream into master
Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/402
2021-07-12 18:04:52 +00:00
wowario
4bb004d488 remove unbound 2021-07-12 20:51:39 +03:00
wowario
2135d96ce5 remove DNS ips 2021-07-12 20:31:04 +03:00
selsta
f2700d8a8c external: remove unbound submodule 2021-07-12 20:27:05 +03:00
wowario
06a8561506 msg on mining key 2021-07-12 20:16:55 +03:00
wowario
5fc33d80b7 change unable to send transaction warning to debug 2021-07-12 20:09:04 +03:00
moneromooo-monero
dfeafb77b9 protocol: fix delayed "you are now synchronized..." message 2021-07-12 08:47:56 +03:00
selsta
fb21f2748b simplewallet: don't truncate integ. address in export_transfers 2021-07-12 08:46:49 +03:00
selsta
38551fff2d trezor: add #if for ByteSizeLong
Turns out Ubuntu 18.04 ships with an old protobuf version.
2021-07-12 08:46:28 +03:00
tobtoht
78e3ea51d6 wallet_api: getPassword 2021-07-12 08:45:11 +03:00
wowario
bad59c1225 bump version 2021-07-12 08:38:28 +03:00
wowario
a17acc1dd8 update checkpoints 2021-07-12 08:36:58 +03:00
wowario
f50bd0c801 Merge pull request 'Update lza_menace seed node' (#401) from lza_menace-patch-1 into master
Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/401
2021-07-08 00:45:22 +00:00
lza_menace
c498f72c0f Update lza_menace seed node
This old AWS IP is gone
2021-07-07 20:55:36 +00:00
wowario
a92df99e55 Merge pull request 'change no incoming connections warning to debug' (#399) from wowario/wownero:warn into master
Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/399
2021-07-06 04:55:06 +00:00
wowario
9b66a396a6 change no incoming connections warning to debug 2021-07-06 07:43:54 +03:00
wowario
942e3abe96 Merge pull request 'add tor stuff' (#397) from wowario/wownero:tor into master
Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/397
2021-07-05 08:12:06 +00:00
wowario
047c0a3c23 Merge pull request 'update checkpoints' (#398) from wowario/wownero:checkpoints into master
Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/398
2021-07-05 08:06:22 +00:00
wowario
74fbd76b91 change ports 2021-07-05 11:03:42 +03:00
wowario
adf438d0fd update systemd service file 2021-07-05 11:02:54 +03:00
wowario
783803b5cf update checkpoints 2021-07-05 09:33:49 +03:00
wowario
e5e56aafb7 add tor stuff 2021-07-04 09:22:10 +03:00
wowario
ff5182f7f2 Merge pull request 'Wowletify' (#396) from wowletify into master
Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/396
2021-07-04 05:11:56 +00:00
dsc
a5b93c8414 remove unused variable 2021-07-04 00:09:29 +02:00
thotbot
0d751b9be7 Skip unneeded blocks in fast refresh 2021-07-04 00:03:51 +02:00
thotbot
76c875f248 subaddressIndex() 2021-07-04 00:03:51 +02:00
thotbot
dc1821ab0e Print wallet cache 2021-07-04 00:03:51 +02:00
thotbot
e31e8cd9f0 Misc. network related
- Add interface for bytes sent/received
- Allow wallet refresh while daemon is not synchronized
- emit success boolean for refreshed()
- don't call refreshThreadFunc (we don't need it)
- lower rpc timeout from 3m30s (?!) to 10 seconds
2021-07-04 00:03:50 +02:00
thotbot
f34e643c18 wallet_api: getPassword 2021-07-03 23:09:00 +02:00
thotbot
39e16ffcf2 Import transaction 2021-07-03 23:05:44 +02:00
thotbot
f5917eabe4 Misc. wallet API and wallet2 changes 2021-07-03 23:00:42 +02:00
thotbot
3121980b17 Coins 2021-07-03 22:15:39 +02:00
thotbot
cebe0ef944 Offline transaction signing 2021-07-03 22:10:22 +02:00
dsc
b6a21de70b estimate_fee requires new bp+ parameter 2021-07-03 21:40:08 +02:00
wowario
623c14e486 tag for gitian builds 2021-06-29 12:58:00 +03:00
51 changed files with 1769 additions and 186 deletions

View File

@@ -54,7 +54,7 @@ jobs:
- uses: eine/setup-msys2@v2
with:
update: true
install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb git
install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-unbound git
- name: build
run: |
ccache --max-size=150M

4
.gitmodules vendored
View File

@@ -1,7 +1,3 @@
[submodule "external/unbound"]
path = external/unbound
url = https://github.com/monero-project/unbound
branch = monero
[submodule "external/miniupnp"]
path = external/miniupnp
url = https://github.com/miniupnp/miniupnp

View File

@@ -307,7 +307,6 @@ if(NOT MANUAL_SUBMODULES)
message(STATUS "Checking submodules")
check_submodule(external/miniupnp)
check_submodule(external/unbound)
check_submodule(external/rapidjson)
check_submodule(external/RandomWOW)
check_submodule(external/supercop)
@@ -612,8 +611,7 @@ include_directories("${CMAKE_CURRENT_BINARY_DIR}/translations")
add_subdirectory(external)
# Final setup for libunbound
include_directories(${UNBOUND_INCLUDE})
link_directories(${UNBOUND_LIBRARY_DIRS})
include_directories(${UNBOUND_INCLUDE_DIR})
# Final setup for easylogging++
include_directories(${EASYLOGGING_INCLUDE})

View File

@@ -26,7 +26,7 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers.
### Blockchain Explorers
- https://explore.wownero.com
- http://wow5eqtzqvsg5jctqzg5g7uk3u62sfqiacj5x6lo4by7bvnj6jkvubyd.onion
- http://gffjxd5nn2heslj6jv5ts2ok5j6xi6m3pwlpz7le4i5bu56sirbxfiqd.onion:8081
- https://wownero.club
- https://explorer.wownero.fyi
@@ -91,7 +91,7 @@ Dates are provided in the format YYYY-MM-DD.
| 160,777 | 2019-11-20 | Gaping Goatse | v0.7.0.0 | v0.7.1.0 | Only allow >= 2 outputs, change to the block median used to calculate penalty, rct sigs in coinbase forbidden, 4 unlock time as protocol rule
| - | 2020-06-28 | Hallucinogenic Hypnotoad | v0.8.0.0 | v0.8.0.2 | Dandelion++ support
| 253,999 | 2020-10-09 | Illiterate Illuminati | v0.9.0.0 | v0.9.3.3 | Dynamic coinbase unlock (up to 1 mo.), Deterministic unlock times, Enforce maximum coinbase amount, show_qr_code wallet command, CLSAG
| 331,170 | 2021-07-04 | Junkie Jeff | v0.10.0.0 | v0.10.0.0 | Bulletproofs+, Miner Block Header Signing, Vote by Block, Change coinbase unlock time to 1 day, Reset difficulty and switch back to Monero's difficulty algorithm
| 331,170 | 2021-07-04 | Junkie Jeff | v0.10.0.0 | v0.10.0.2 | Bulletproofs+, Miner Block Header Signing, Vote by Block, Change coinbase unlock time to 1 day, Reset difficulty and switch back to Monero's difficulty algorithm
X's indicate that these details have not been determined as of commit date.
@@ -170,10 +170,10 @@ To run in background:
To run as a systemd service, copy
[wownerod.service](utils/systemd/wownerod.service) to `/etc/systemd/system/` and
[wownerod.conf](utils/conf/wownerod.conf) to `/etc/`. The [example
[wownerod.conf](wownerod.conf) to `/etc/`. The [example
service](utils/systemd/wownerod.service) assumes that the user `wownero` exists
and its home is the data directory specified in the [example
config](utils/conf/wownerod.conf).
config](wownerod.conf).
Once node is synced to network, run the CLI wallet by entering:
@@ -183,26 +183,37 @@ Type `help` in CLI wallet to see standard commands (for advanced options, type `
## Tor Anonymity Network
* Install [Tor Browser](https://www.torproject.org/download/)
* Open `torrc` file in a text editor ([installation directory]/Browser/TorBrowser/Data/Tor/torrc) and add hidden service information as follows:
### Ubuntu
* `sudo apt-get update && sudo apt-get install tor -y`
* `sudo nano /etc/tor/torrc`
add the following:
```
HiddenServiceDir [installation directory]/Browser/TorBrowser/Data/Tor/wow_node
HiddenServiceDir /var/lib/tor/wownero/
HiddenServicePort 34568 127.0.0.1:34568
HiddenServicePort 34566 127.0.0.1:34566
HiddenServiceVersion 3
HiddenServicePort 44568 127.0.0.1:44568
```
* Save `torrc` file and restart Tor Browser (keep open)
* Change directory to the `wow_node` folder, open `hostname` file, and copy your node's ".onion" address
* Start wownerod with the following parameters:
save and close nano
* `sudo /etc/init.d/tor restart && sudo systemctl enable tor`
* copy [wownerod.conf](https://git.wownero.com/wownero/wownero/raw/branch/master/wownerod.conf) file and save it in same directory as `wownerod`.
* start wownerod like this:
```
./wownerod --tx-proxy tor,127.0.0.1:9150,10 --add-peer hdps3qwnusz64r7odvynmae6myc2uyvrsc2emap6636qeuzll72eouid.onion:44568 --anonymous-inbound YOUR_NODE_ADDRESS.onion:44568,127.0.0.1:44568,25
./wownerod --config-file=wownerod.conf
```
* `sudo cat /var/lib/tor/wownero/hostname`
copy your onion address and share node with others [here](https://monero.fail/?crypto=wownero) and [here](https://forum.wownero.com/t/wownero-tor-onion-sites/623)
To share your node over p2p, uncomment first line of wownerod.conf and add your onion address.
More information on running Tor and i2p nodes is available [here](https://forum.wownero.com/t/how-to-setup-a-full-node-with-tor-i2p/588)
### Access remote Tor node from CLI wallet
```
./wownero-wallet-cli --proxy 127.0.0.1:9150 --daemon-address wow7dhbgiljnkspkzpjyy66auegbrye2ptfv4gucgbhireg5rrjza5ad.onion:34568
./wownero-wallet-cli --proxy 127.0.0.1:9050 --daemon-address iy6ry6uudpzvbd72zsipepukp6nsazjdu72n52vg3isfnxqn342flzad.onion:34568
```
Use port `9050` instead of `9150` if you installed Tor as a standalone daemon. For more information, check out [ANONYMITY_NETWORKS](https://git.wownero.com/wownero/wownero/src/branch/master/ANONYMITY_NETWORKS.md).

View File

@@ -1,8 +1,8 @@
package=expat
$(package)_version=2.2.4
$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_2_4
$(package)_version=2.4.1
$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_4_1
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=03ad85db965f8ab2d27328abcf0bc5571af6ec0a414874b2066ee3fdd372019e
$(package)_sha256_hash=2f9b6a580b94577b150a7d5617ad4643a4301a6616ff459307df3e225bcfbf40
define $(package)_set_vars
$(package)_config_opts=--enable-static

View File

@@ -1,8 +1,8 @@
package=ldns
$(package)_version=1.6.17
$(package)_download_path=https://www.nlnetlabs.nl/downloads/ldns/
$(package)_version=1.7.1
$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=8b88e059452118e8949a2752a55ce59bc71fa5bc414103e17f5b6b06f9bcc8cd
$(package)_sha256_hash=8ac84c16bdca60e710eea75782356f3ac3b55680d40e1530d7cea474ac208229
$(package)_dependencies=openssl
define $(package)_set_vars

View File

@@ -1,4 +1,4 @@
packages:=boost openssl zeromq libiconv
packages:=boost openssl zeromq libiconv expat ldns unbound
native_packages := native_ccache

View File

@@ -1,12 +1,12 @@
package=unbound
$(package)_version=1.6.8
$(package)_download_path=https://www.unbound.net/downloads/
$(package)_version=1.13.1
$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=e3b428e33f56a45417107448418865fe08d58e0e7fea199b855515f60884dd49
$(package)_sha256_hash=8504d97b8fc5bd897345c95d116e0ee0ddf8c8ff99590ab2b4bd13278c9f50b8
$(package)_dependencies=openssl expat ldns
define $(package)_set_vars
$(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) --with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads
$(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) --with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_w64=--enable-static-exe --sysconfdir=/etc --prefix=$(host_prefix) --target=$(host_prefix)
$(package)_build_opts_mingw32=LDFLAGS="$($(package)_ldflags) -lpthread"

View File

@@ -24,6 +24,9 @@ SET(Readline_INCLUDE_DIR @prefix@/include)
SET(Readline_LIBRARY @prefix@/lib/libreadline.a)
SET(Terminfo_LIBRARY @prefix@/lib/libtinfo.a)
SET(UNBOUND_INCLUDE_DIR @prefix@/include)
SET(UNBOUND_LIBRARIES @prefix@/lib/libunbound.a)
SET(LRELEASE_PATH @prefix@/native/bin CACHE FILEPATH "path to lrelease" FORCE)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")

View File

@@ -42,7 +42,9 @@ CookieAuthentication 1
CookieAuthFile $TORDIR/control.authcookie
CookieAuthFileGroupReadable 1
HiddenServiceDir $TORDIR
HiddenServicePort 38083 127.0.0.1:38083
HiddenServicePort 34568 127.0.0.1:34568
HiddenServicePort 34566 127.0.0.1:34566
HiddenServiceVersion 3
EOF
echo "Starting Tor..."
@@ -67,9 +69,15 @@ fi
echo "Starting wownerod..."
HOSTNAME=$(cat "$HOSTNAMEFILE")
"$monerod" \
--anonymous-inbound "$HOSTNAME":38083,127.0.0.1:38083,25 --tx-proxy tor,127.0.0.1:9050,10 \
--add-priority-node zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:38083 \
--add-priority-node 2xmrnode5itf65lz.onion:38083 \
--anonymous-inbound "$HOSTNAME":34566,127.0.0.1:34566,25 --tx-proxy tor,127.0.0.1:9050,10 \
--add-priority-node v2admi6gbeprxnk6i2oscizhgy4v5ixu6iezkhj5udiwbfjjs2w7dnid.onion:34568 \
--add-priority-node iy6ry6uudpzvbd72zsipepukp6nsazjdu72n52vg3isfnxqn342flzad.onion:34568 \
--add-priority-node 7ftpbpp6rbgqi5kjmhyin46essnh3eqb3m3rhfi7r2fr33iwkeuer3yd.onion:34568 \
--add-priority-node j7rf2jcccizcp47y5moehguyuqdpg4lusk642sw4nayuruitqaqbc7ad.onion:34568 \
--add-priority-node aje53o5z5twne5q2ljw44zkahhsuhjtwaxuburxddbf7n4pfsj4rj6qd.onion:34568 \
--add-priority-node nepc4lxndsooj2akn7ofrj3ooqc25242obchcag6tw3f2mxrms2uuvyd.onion:34568 \
--add-priority-node 666l2ajxqjgj5lskvbokvworjysgvqag4oitokjuy7wz6juisul4jqad.onion:34568 \
--add-priority-node ty7ppqozzodz75audgvkprekiiqsovbyrkfdjwadrkbe3etyzloatxad.onion:34568 \
--detach
ready=0
for i in `seq 10`

View File

@@ -55,26 +55,12 @@ set(UPNP_LIBRARIES "libminiupnpc-static" PARENT_SCOPE)
find_package(Unbound)
if(NOT UNBOUND_INCLUDE_DIR OR STATIC)
# NOTE: If STATIC is true, CMAKE_FIND_LIBRARY_SUFFIXES has been reordered.
# unbound has config tests which used OpenSSL libraries, so -ldl may need to
# be set in this case.
# The unbound CMakeLists.txt can set it, since it's also needed for the
# static OpenSSL libraries set up there after with target_link_libraries.
add_subdirectory(unbound)
set(UNBOUND_STATIC true PARENT_SCOPE)
set(UNBOUND_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/unbound/libunbound" PARENT_SCOPE)
set(UNBOUND_LIBRARY "unbound" PARENT_SCOPE)
set(UNBOUND_LIBRARY_DIRS "${LIBEVENT2_LIBDIR}" PARENT_SCOPE)
if(NOT UNBOUND_INCLUDE_DIR)
die("Could not find libunbound")
else()
message(STATUS "Found libunbound include (unbound.h) in ${UNBOUND_INCLUDE_DIR}")
if(UNBOUND_LIBRARIES)
message(STATUS "Found libunbound shared library")
set(UNBOUND_STATIC false PARENT_SCOPE)
set(UNBOUND_INCLUDE ${UNBOUND_INCLUDE_DIR} PARENT_SCOPE)
set(UNBOUND_LIBRARY ${UNBOUND_LIBRARIES} PARENT_SCOPE)
set(UNBOUND_LIBRARY_DIRS "" PARENT_SCOPE)
message(STATUS "Found libunbound library")
else()
die("Found libunbound includes, but could not find libunbound library. Please make sure you have installed libunbound or libunbound-dev or the equivalent")
endif()

1
external/unbound vendored

Submodule external/unbound deleted from 0f6c0579d6

Binary file not shown.

View File

@@ -220,6 +220,11 @@ namespace cryptonote
ADD_CHECKPOINT2(312130, "e0da085bd273fff9f5f8e604fce0e91908bc62b6b004731a93e16e89cb9b1f54", "0x3cfe7148f2e18");
ADD_CHECKPOINT2(324600, "b24cd1ed7c192bbcf3d5b15729f2b032566687f96bda6f8cb73a5b16df4c6e6b", "0x69caecbe78718");
ADD_CHECKPOINT2(327700, "f113c8cbe077aab9296ecbfb41780c147aeb54edfece7e4b9946b8abd0f06de7", "0x732431429c818");
ADD_CHECKPOINT2(331170, "05243fba853fe375c671a6783eecac28777bca51f5977d5285c235424e52bb69", "0x7c3469310d218"); //Hard fork to v18
ADD_CHECKPOINT2(331458, "f79a664a5e4bc11fa7d804be2c3c72db50c87a27f1f540f337564cbb6314e4cd", "0x7c34d47adf218"); //Hard fork to v19
ADD_CHECKPOINT2(331891, "faceea4b4ab33fc962c24dfa2f98c2aeda4788f67c1e0044c62419912c1a64fe", "0x7c359086aeb58"); // restart DIFFICULTY_WINDOW
ADD_CHECKPOINT2(332100, "d32c409058c1eceb9a105190c7a5f480b2d6f49f318b18652b49ae971c710124", "0x7c538441cca36");
ADD_CHECKPOINT2(334000, "17d3b15f8e1a73e1c61335ee7979e9e3d211b9055e8a7fb2481e5f49a51b1c22", "0x7ddd5a79d69c4");
return true;
}

View File

@@ -99,7 +99,7 @@ monero_add_library(common
target_link_libraries(common
PUBLIC
cncrypto
${UNBOUND_LIBRARY}
${UNBOUND_LIBRARIES}
${LIBUNWIND_LIBRARIES}
${Boost_DATE_TIME_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}

View File

@@ -45,11 +45,6 @@ using namespace epee;
static const char *DEFAULT_DNS_PUBLIC_ADDR[] =
{
"194.150.168.168", // CCC (Germany)
"80.67.169.40", // FDN (France)
"89.233.43.71", // http://censurfridns.dk (Denmark)
"109.69.8.51", // punCAT (Spain)
"193.58.251.251", // SkyDNS (Russia)
};
static boost::mutex instance_lock;

View File

@@ -5525,7 +5525,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "6dd0d016366b906ed9e493f721d3b3f60c0db628774206424651b6e8f2a76a95";
static const char expected_block_hashes_hash[] = "25fd44a93e0880a3d69c62d7f7c429d9f04ff345c812a04936773b2fbad78868";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)

View File

@@ -2095,6 +2095,8 @@ skip:
}
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
context.m_state = cryptonote_connection_context::state_normal;
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
on_connection_synchronized();
return true;
}
uint64_t next_needed_height = m_block_queue.get_next_needed_height(bc_height);
@@ -2242,6 +2244,8 @@ skip:
}
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
context.m_state = cryptonote_connection_context::state_normal;
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
on_connection_synchronized();
return true;
}
@@ -2433,10 +2437,7 @@ skip:
if (context.m_remote_blockchain_height >= m_core.get_target_blockchain_height())
{
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
{
MGINFO_GREEN("SYNCHRONIZED OK");
on_connection_synchronized();
}
}
else
{

View File

@@ -662,7 +662,7 @@ namespace levin
auto connections = get_out_connections(*zone_->p2p, height);
if (connections.empty())
MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
MDEBUG("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
" - no suitable outbound connections at height " << height);
zone_->strand.post(update_channels{zone_, std::move(connections)});

View File

@@ -157,7 +157,11 @@ namespace trezor{
#define PROTO_HEADER_SIZE 6
static size_t message_size(const google::protobuf::Message &req){
#if GOOGLE_PROTOBUF_VERSION < 3006001
return size_t(req.ByteSize());
#else
return req.ByteSizeLong();
#endif
}
static size_t serialize_message_buffer_size(size_t msg_size) {

View File

@@ -695,7 +695,7 @@ namespace nodetool
full_addrs.insert("164.90.230.176:34567"); // de1.wownodes.com
full_addrs.insert("64.227.81.144:34567"); // us1.wownodes.com
full_addrs.insert("188.166.237.187:34567"); // sg1.wownodes.com
full_addrs.insert("54.185.62.197:34567"); // node.suchwow.xyz
full_addrs.insert("51.161.131.176:34567"); // node.suchwow.xyz
full_addrs.insert("167.114.196.241:34567"); // wowbux.org
}
return full_addrs;
@@ -821,9 +821,14 @@ namespace nodetool
if (m_nettype == cryptonote::MAINNET)
{
return {
"xwvz3ekocr3dkyxfkmgm2hvbpzx2ysqmaxgter7znnqrhoicygkfswid.onion:18083",
"4pixvbejrvihnkxmduo2agsnmc3rrulrqc7s3cbwwrep6h6hrzsibeqd.onion:18083",
"zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083",
"v2admi6gbeprxnk6i2oscizhgy4v5ixu6iezkhj5udiwbfjjs2w7dnid.onion:34566",
"iy6ry6uudpzvbd72zsipepukp6nsazjdu72n52vg3isfnxqn342flzad.onion:34566",
"7ftpbpp6rbgqi5kjmhyin46essnh3eqb3m3rhfi7r2fr33iwkeuer3yd.onion:34566",
"j7rf2jcccizcp47y5moehguyuqdpg4lusk642sw4nayuruitqaqbc7ad.onion:34566",
"aje53o5z5twne5q2ljw44zkahhsuhjtwaxuburxddbf7n4pfsj4rj6qd.onion:34566",
"nepc4lxndsooj2akn7ofrj3ooqc25242obchcag6tw3f2mxrms2uuvyd.onion:34566",
"666l2ajxqjgj5lskvbokvworjysgvqag4oitokjuy7wz6juisul4jqad.onion:34566",
"ty7ppqozzodz75audgvkprekiiqsovbyrkfdjwadrkbe3etyzloatxad.onion:34566",
};
}
return {};
@@ -831,8 +836,6 @@ namespace nodetool
if (m_nettype == cryptonote::MAINNET)
{
return {
"s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080",
"sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080"
};
}
return {};
@@ -2044,7 +2047,7 @@ namespace nodetool
}
else
{
const el::Level level = el::Level::Warning;
const el::Level level = el::Level::Debug;
MCLOG_RED(level, "Debug", "No incoming connections - check firewalls/routers allow port " << get_this_peer_port());
}
}

View File

@@ -766,7 +766,7 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
std::cout << "secret: On device. Not available" << std::endl;
} else {
SCOPED_WALLET_UNLOCK();
printf("secret: ");
printf("secret (key used for mining): ");
print_secret_key(m_wallet->get_account().get_keys().m_spend_secret_key);
putchar('\n');
}
@@ -8922,12 +8922,12 @@ bool simple_wallet::export_transfers(const std::vector<std::string>& args_)
// header
file <<
boost::format("%8.8s,%9.9s,%8.8s,%25.25s,%20.20s,%20.20s,%64.64s,%16.16s,%14.14s,%100.100s,%20.20s,%s,%s") %
boost::format("%8.8s,%9.9s,%8.8s,%25.25s,%20.20s,%20.20s,%64.64s,%16.16s,%14.14s,%106.106s,%20.20s,%s,%s") %
tr("block") % tr("direction") % tr("unlocked") % tr("timestamp") % tr("amount") % tr("running balance") % tr("hash") % tr("payment ID") % tr("fee") % tr("destination") % tr("amount") % tr("index") % tr("note")
<< std::endl;
uint64_t running_balance = 0;
auto formatter = boost::format("%8.8llu,%9.9s,%8.8s,%25.25s,%20.20s,%20.20s,%64.64s,%16.16s,%14.14s,%100.100s,%20.20s,\"%s\",%s");
auto formatter = boost::format("%8.8llu,%9.9s,%8.8s,%25.25s,%20.20s,%20.20s,%64.64s,%16.16s,%14.14s,%106.106s,%20.20s,\"%s\",%s");
for (const auto& transfer : all_transfers)
{

View File

@@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.10.0.0"
#define DEF_MONERO_VERSION "0.10.0.2"
#define DEF_MONERO_RELEASE_NAME "Junkie Jeff"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@

View File

@@ -35,12 +35,16 @@ set(wallet_api_sources
wallet_manager.cpp
transaction_info.cpp
transaction_history.cpp
transaction_construction_info.cpp
pending_transaction_info.cpp
pending_transaction.cpp
utils.cpp
address_book.cpp
subaddress.cpp
subaddress_account.cpp
unsigned_transaction.cpp)
unsigned_transaction.cpp
coins.cpp
coins_info.cpp)
set(wallet_api_headers
wallet2_api.h)
@@ -50,12 +54,16 @@ set(wallet_api_private_headers
wallet_manager.h
transaction_info.h
transaction_history.h
transaction_construction_info.h
pending_transaction_info.h
pending_transaction.h
common_defines.h
address_book.h
subaddress.h
subaddress_account.h
unsigned_transaction.h)
unsigned_transaction.h
coins.h
coins_info.h)
monero_private_headers(wallet_api
${wallet_api_private_headers})

122
src/wallet/api/coins.cpp Normal file
View File

@@ -0,0 +1,122 @@
#include "coins.h"
#include "coins_info.h"
#include "wallet.h"
#include "crypto/hash.h"
#include "wallet/wallet2.h"
#include "common_defines.h"
#include <string>
#include <vector>
using namespace epee;
namespace Monero {
Coins::~Coins() = default;
CoinsImpl::CoinsImpl(WalletImpl *wallet)
: m_wallet(wallet) {}
CoinsImpl::~CoinsImpl()
{
for (auto t : m_rows)
delete t;
}
int CoinsImpl::count() const
{
boost::shared_lock<boost::shared_mutex> lock(m_rowsMutex);
int result = m_rows.size();
return result;
}
CoinsInfo *CoinsImpl::coin(int index) const
{
boost::shared_lock<boost::shared_mutex> lock(m_rowsMutex);
// sanity check
if (index < 0)
return nullptr;
auto index_ = static_cast<unsigned>(index);
return index_ < m_rows.size() ? m_rows[index_] : nullptr;
}
std::vector<CoinsInfo *> CoinsImpl::getAll() const
{
boost::shared_lock<boost::shared_mutex> lock(m_rowsMutex);
return m_rows;
}
void CoinsImpl::refresh()
{
LOG_PRINT_L2("Refreshing coins");
boost::unique_lock<boost::shared_mutex> lock(m_rowsMutex);
boost::shared_lock<boost::shared_mutex> transfers_lock(m_wallet->m_wallet->m_transfers_mutex);
// delete old outputs;
for (auto t : m_rows)
delete t;
m_rows.clear();
for (size_t i = 0; i < m_wallet->m_wallet->get_num_transfer_details(); ++i)
{
const tools::wallet2::transfer_details &td = m_wallet->m_wallet->get_transfer_details(i);
auto ci = new CoinsInfoImpl();
ci->m_blockHeight = td.m_block_height;
ci->m_hash = string_tools::pod_to_hex(td.m_txid);
ci->m_internalOutputIndex = td.m_internal_output_index;
ci->m_globalOutputIndex = td.m_global_output_index;
ci->m_spent = td.m_spent;
ci->m_frozen = td.m_frozen;
ci->m_spentHeight = td.m_spent_height;
ci->m_amount = td.m_amount;
ci->m_rct = td.m_rct;
ci->m_keyImageKnown = td.m_key_image_known;
ci->m_pkIndex = td.m_pk_index;
ci->m_subaddrIndex = td.m_subaddr_index.minor;
ci->m_subaddrAccount = td.m_subaddr_index.major;
ci->m_address = m_wallet->m_wallet->get_subaddress_as_str(td.m_subaddr_index); // todo: this is expensive, cache maybe?
ci->m_addressLabel = m_wallet->m_wallet->get_subaddress_label(td.m_subaddr_index);
ci->m_keyImage = string_tools::pod_to_hex(td.m_key_image);
ci->m_unlockTime = td.m_tx.unlock_time;
ci->m_unlocked = m_wallet->m_wallet->is_transfer_unlocked(td);
ci->m_pubKey = string_tools::pod_to_hex(td.get_public_key());
ci->m_coinbase = td.m_tx.vin.size() == 1 && td.m_tx.vin[0].type() == typeid(cryptonote::txin_gen);
m_rows.push_back(ci);
}
}
void CoinsImpl::setFrozen(int index)
{
try
{
m_wallet->m_wallet->freeze(index);
refresh();
}
catch (const std::exception& e)
{
LOG_ERROR("setLabel: " << e.what());
}
}
void CoinsImpl::thaw(int index)
{
try
{
m_wallet->m_wallet->thaw(index);
refresh();
}
catch (const std::exception& e)
{
LOG_ERROR("thaw: " << e.what());
}
}
bool CoinsImpl::isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) {
return m_wallet->m_wallet->is_transfer_unlocked(unlockTime, blockHeight);
}
} // namespace

34
src/wallet/api/coins.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef WOWLET_COINS_H
#define WOWLET_COINS_H
#include "wallet/api/wallet2_api.h"
#include "wallet/wallet2.h"
namespace Monero {
class WalletImpl;
class CoinsImpl : public Coins
{
public:
explicit CoinsImpl(WalletImpl * wallet);
~CoinsImpl() override;
int count() const override;
CoinsInfo * coin(int index) const override;
std::vector<CoinsInfo*> getAll() const override;
void refresh() override;
void setFrozen(int index) override;
void thaw(int index) override;
bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) override;
private:
WalletImpl *m_wallet;
std::vector<CoinsInfo*> m_rows;
mutable boost::shared_mutex m_rowsMutex;
};
}
#endif //WOWLET_COINS_H

View File

@@ -0,0 +1,118 @@
#include "coins_info.h"
using namespace std;
namespace Monero {
CoinsInfo::~CoinsInfo() = default;
CoinsInfoImpl::CoinsInfoImpl()
: m_blockHeight(0)
, m_internalOutputIndex(0)
, m_globalOutputIndex(0)
, m_spent(false)
, m_frozen(false)
, m_spentHeight(0)
, m_amount(0)
, m_rct(false)
, m_keyImageKnown(false)
, m_pkIndex(0)
, m_subaddrAccount(0)
, m_subaddrIndex(0)
, m_unlockTime(0)
, m_unlocked(false)
{
}
CoinsInfoImpl::~CoinsInfoImpl() = default;
uint64_t CoinsInfoImpl::blockHeight() const
{
return m_blockHeight;
}
string CoinsInfoImpl::hash() const
{
return m_hash;
}
size_t CoinsInfoImpl::internalOutputIndex() const {
return m_internalOutputIndex;
}
uint64_t CoinsInfoImpl::globalOutputIndex() const
{
return m_globalOutputIndex;
}
bool CoinsInfoImpl::spent() const
{
return m_spent;
}
bool CoinsInfoImpl::frozen() const
{
return m_frozen;
}
uint64_t CoinsInfoImpl::spentHeight() const
{
return m_spentHeight;
}
uint64_t CoinsInfoImpl::amount() const
{
return m_amount;
}
bool CoinsInfoImpl::rct() const {
return m_rct;
}
bool CoinsInfoImpl::keyImageKnown() const {
return m_keyImageKnown;
}
size_t CoinsInfoImpl::pkIndex() const {
return m_pkIndex;
}
uint32_t CoinsInfoImpl::subaddrIndex() const {
return m_subaddrIndex;
}
uint32_t CoinsInfoImpl::subaddrAccount() const {
return m_subaddrAccount;
}
string CoinsInfoImpl::address() const {
return m_address;
}
string CoinsInfoImpl::addressLabel() const {
return m_addressLabel;
}
string CoinsInfoImpl::keyImage() const {
return m_keyImage;
}
uint64_t CoinsInfoImpl::unlockTime() const {
return m_unlockTime;
}
bool CoinsInfoImpl::unlocked() const {
return m_unlocked;
}
string CoinsInfoImpl::pubKey() const {
return m_pubKey;
}
bool CoinsInfoImpl::coinbase() const {
return m_coinbase;
}
} // namespace
namespace Bitmonero = Monero;

View File

@@ -0,0 +1,67 @@
#ifndef WOWLET_COINS_INFO_H
#define WOWLET_COINS_INFO_H
#include "wallet/api/wallet2_api.h"
#include <string>
#include <ctime>
namespace Monero {
class CoinsImpl;
class CoinsInfoImpl : public CoinsInfo
{
public:
CoinsInfoImpl();
~CoinsInfoImpl();
virtual uint64_t blockHeight() const override;
virtual std::string hash() const override;
virtual size_t internalOutputIndex() const override;
virtual uint64_t globalOutputIndex() const override;
virtual bool spent() const override;
virtual bool frozen() const override;
virtual uint64_t spentHeight() const override;
virtual uint64_t amount() const override;
virtual bool rct() const override;
virtual bool keyImageKnown() const override;
virtual size_t pkIndex() const override;
virtual uint32_t subaddrIndex() const override;
virtual uint32_t subaddrAccount() const override;
virtual std::string address() const override;
virtual std::string addressLabel() const override;
virtual std::string keyImage() const override;
virtual uint64_t unlockTime() const override;
virtual bool unlocked() const override;
virtual std::string pubKey() const override;
virtual bool coinbase() const override;
private:
uint64_t m_blockHeight;
std::string m_hash;
size_t m_internalOutputIndex;
uint64_t m_globalOutputIndex;
bool m_spent;
bool m_frozen;
uint64_t m_spentHeight;
uint64_t m_amount;
bool m_rct;
bool m_keyImageKnown;
size_t m_pkIndex;
uint32_t m_subaddrIndex;
uint32_t m_subaddrAccount;
std::string m_address;
std::string m_addressLabel;
std::string m_keyImage;
uint64_t m_unlockTime;
bool m_unlocked;
std::string m_pubKey;
bool m_coinbase;
friend class CoinsImpl;
};
} // namespace
#endif //WOWLET_COINS_INFO_H

View File

@@ -35,6 +35,7 @@
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "common/base58.h"
#include "string_coding.h"
#include <memory>
#include <vector>
@@ -263,4 +264,50 @@ std::vector<std::string> PendingTransactionImpl::signersKeys() const {
return keys;
}
std::string PendingTransactionImpl::unsignedTxToBin() const {
return m_wallet.m_wallet->dump_tx_to_str(m_pending_tx);
}
std::string PendingTransactionImpl::unsignedTxToBase64() const {
return epee::string_encoding::base64_encode(m_wallet.m_wallet->dump_tx_to_str(m_pending_tx));
}
std::string PendingTransactionImpl::signedTxToHex(int index) const {
auto index_ = static_cast<unsigned>(index);
if (index < 0 || index_ >= m_pending_tx.size()) {
return "";
}
return epee::string_tools::buff_to_hex_nodelimer(cryptonote::tx_to_blob(m_pending_tx[index_].tx));
}
size_t PendingTransactionImpl::signedTxSize(int index) const {
auto index_ = static_cast<unsigned>(index);
if (index < 0 || index_ >= m_pending_tx.size()) {
return 0;
}
return cryptonote::tx_to_blob(m_pending_tx[index_].tx).size();
}
PendingTransactionInfo * PendingTransactionImpl::transaction(int index) const {
if (index < 0)
return nullptr;
auto index_ = static_cast<unsigned>(index);
return index_ < m_pending_tx_info.size() ? m_pending_tx_info[index_] : nullptr;
}
void PendingTransactionImpl::refresh() {
for (auto t : m_pending_tx_info)
delete t;
m_pending_tx_info.clear();
for (const auto& p : m_pending_tx)
m_pending_tx_info.push_back(new PendingTransactionInfoImpl(m_wallet, p));
}
std::vector<PendingTransactionInfo*> PendingTransactionImpl::getAll() const {
return m_pending_tx_info;
}
}

View File

@@ -30,6 +30,7 @@
#include "wallet/api/wallet2_api.h"
#include "wallet/wallet2.h"
#include "pending_transaction_info.h"
#include <string>
#include <vector>
@@ -53,6 +54,13 @@ public:
uint64_t txCount() const override;
std::vector<uint32_t> subaddrAccount() const override;
std::vector<std::set<uint32_t>> subaddrIndices() const override;
std::string unsignedTxToBin() const override;
std::string unsignedTxToBase64() const override;
std::string signedTxToHex(int index) const override;
size_t signedTxSize(int index) const override;
void refresh() override;
std::vector<PendingTransactionInfo*> getAll() const override;
PendingTransactionInfo * transaction(int index) const override;
// TODO: continue with interface;
std::string multisigSignData() override;
@@ -66,6 +74,7 @@ private:
int m_status;
std::string m_errorString;
std::vector<tools::wallet2::pending_tx> m_pending_tx;
std::vector<PendingTransactionInfo*> m_pending_tx_info;
std::unordered_set<crypto::public_key> m_signers;
std::vector<std::string> m_tx_device_aux;
std::vector<crypto::key_image> m_key_images;

View File

@@ -0,0 +1,47 @@
#include "pending_transaction_info.h"
#include "transaction_construction_info.h"
using namespace std;
namespace Monero {
PendingTransactionInfo::~PendingTransactionInfo() = default;
PendingTransactionInfoImpl::PendingTransactionInfoImpl(WalletImpl &wallet, const tools::wallet2::pending_tx & ptx)
: m_wallet(wallet)
, m_ptx(ptx)
, m_constructionData(new TransactionConstructionInfoImpl(wallet, ptx.construction_data))
{
}
PendingTransactionInfoImpl::~PendingTransactionInfoImpl() = default;
uint64_t PendingTransactionInfoImpl::fee() const
{
return m_ptx.fee;
}
uint64_t PendingTransactionInfoImpl::dust() const
{
return m_ptx.dust;
}
bool PendingTransactionInfoImpl::dustAddedToFee() const
{
return m_ptx.dust_added_to_fee;
}
std::string PendingTransactionInfoImpl::txKey() const
{
return epee::string_tools::pod_to_hex(m_ptx.tx_key);
}
TransactionConstructionInfo * PendingTransactionInfoImpl::constructionData() const {
return m_constructionData;
}
// TransactionConstructionInfo::Output TransactionConstructionInfoImpl::change() const {
// return Output(
// {m_ptx.change_dts.amount, m_ptx.change_dts.address(m_wallet.m_wallet->nettype(), crypto::hash())});
// }
}

View File

@@ -0,0 +1,37 @@
#ifndef WOWLET_PENDING_TX_H
#define WOWLET_PENDING_TX_H
#include "wallet/api/wallet2_api.h"
#include "wallet/wallet2.h"
#include "wallet.h"
#include <string>
namespace Monero {
class PendingTransactionImpl;
class PendingTransactionInfoImpl : public PendingTransactionInfo
{
public:
PendingTransactionInfoImpl(WalletImpl &wallet, const tools::wallet2::pending_tx & ptx);
~PendingTransactionInfoImpl() override;
uint64_t fee() const override;
uint64_t dust() const override;
bool dustAddedToFee() const override;
std::string txKey() const override;
TransactionConstructionInfo *constructionData() const override;
// Output change() const override;
private:
friend class WalletImpl;
WalletImpl &m_wallet;
tools::wallet2::pending_tx m_ptx;
TransactionConstructionInfo *m_constructionData;
};
}
#endif //FEATHER_PENDING_TX_H

View File

@@ -67,7 +67,10 @@ void SubaddressImpl::refresh(uint32_t accountIndex)
clearRows();
for (size_t i = 0; i < m_wallet->m_wallet->get_num_subaddresses(accountIndex); ++i)
{
m_rows.push_back(new SubaddressRow(i, m_wallet->m_wallet->get_subaddress_as_str({accountIndex, (uint32_t)i}), m_wallet->m_wallet->get_subaddress_label({accountIndex, (uint32_t)i})));
m_rows.push_back(new SubaddressRow(i,
m_wallet->m_wallet->get_subaddress_as_str({accountIndex, (uint32_t)i}),
m_wallet->m_wallet->get_subaddress_label({accountIndex, (uint32_t)i}),
m_wallet->m_wallet->get_subaddress_used({accountIndex, (uint32_t)i})));
}
}

View File

@@ -0,0 +1,63 @@
#include "transaction_construction_info.h"
using namespace std;
namespace Monero {
TransactionConstructionInfo::~TransactionConstructionInfo() = default;
TransactionConstructionInfo::Input::Input(uint64_t _amount, const std::string &_pubkey)
: amount(_amount), pubkey(_pubkey) {}
TransactionConstructionInfo::Output::Output(uint64_t _amount, const std::string &_address)
: amount(_amount), address(_address) {}
TransactionConstructionInfoImpl::TransactionConstructionInfoImpl(WalletImpl &wallet, const tools::wallet2::tx_construction_data & txcd)
: m_wallet(wallet)
, m_txcd(txcd) {}
TransactionConstructionInfoImpl::~TransactionConstructionInfoImpl() = default;
uint64_t TransactionConstructionInfoImpl::unlockTime() const {
return m_txcd.unlock_time;
}
std::set<std::uint32_t> TransactionConstructionInfoImpl::subaddressIndices() const {
return m_txcd.subaddr_indices;
}
std::vector<std::string> TransactionConstructionInfoImpl::subaddresses() const {
std::vector<std::string> s;
auto major = m_txcd.subaddr_account;
for (const auto &minor : m_txcd.subaddr_indices) {
s.push_back(m_wallet.m_wallet->get_subaddress_as_str({major, minor}));
}
return s;
}
uint64_t TransactionConstructionInfoImpl::minMixinCount() const {
uint64_t min_mixin = -1;
for (const auto &source : m_txcd.sources) {
size_t mixin = source.outputs.size() - 1;
if (mixin < min_mixin)
min_mixin = mixin;
}
return min_mixin;
}
std::vector<TransactionConstructionInfo::Input> TransactionConstructionInfoImpl::inputs() const {
std::vector<Input> inputs;
for (const auto &i : m_txcd.sources) {
inputs.emplace_back(i.amount, epee::string_tools::pod_to_hex(i.real_out_tx_key));
}
return inputs;
}
std::vector<TransactionConstructionInfo::Output> TransactionConstructionInfoImpl::outputs() const {
std::vector<Output> outputs;
for (const auto &o : m_txcd.splitted_dsts) {
outputs.emplace_back(o.amount, o.address(m_wallet.m_wallet->nettype(), crypto::hash()));
}
return outputs;
}
}

View File

@@ -0,0 +1,32 @@
#ifndef WOWLET_TRANSACTION_CONSTRUCTION_INFO_H
#define WOWLET_TRANSACTION_CONSTRUCTION_INFO_H
#include "wallet/api/wallet2_api.h"
#include "wallet/wallet2.h"
#include "wallet.h"
#include <string>
namespace Monero {
class TransactionConstructionInfoImpl : public TransactionConstructionInfo
{
public:
TransactionConstructionInfoImpl(WalletImpl &wallet, const tools::wallet2::tx_construction_data & ptx);
~TransactionConstructionInfoImpl() override;
uint64_t unlockTime() const override;
std::set<std::uint32_t> subaddressIndices() const override;
std::vector<std::string> subaddresses() const override;
uint64_t minMixinCount() const override;
std::vector<Input> inputs() const override;
std::vector<Output> outputs() const override;
private:
friend class WalletImpl;
WalletImpl &m_wallet;
tools::wallet2::tx_construction_data m_txcd;
};
}
#endif //WOWLET_TRANSACTION_CONSTRUCTION_INFO_H

View File

@@ -199,6 +199,9 @@ void TransactionHistoryImpl::refresh()
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)});
}
for (const auto &r: pd.m_rings) {
ti->m_rings.push_back({string_tools::pod_to_hex(r.first), cryptonote::relative_output_offsets_to_absolute(r.second)});
}
m_history.push_back(ti);
}
@@ -229,10 +232,15 @@ void TransactionHistoryImpl::refresh()
ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "";
ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = 0;
for (const auto &d : pd.m_dests)
for (const auto &d : pd.m_dests) {
{
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)});
}
}
for (const auto &r: pd.m_rings) {
ti->m_rings.push_back({string_tools::pod_to_hex(r.first), cryptonote::relative_output_offsets_to_absolute(r.second)});
}
m_history.push_back(ti);
}
@@ -266,3 +274,4 @@ void TransactionHistoryImpl::refresh()
}
} // namespace
}

View File

@@ -139,6 +139,11 @@ const std::vector<TransactionInfo::Transfer> &TransactionInfoImpl::transfers() c
return m_transfers;
}
const std::vector<std::pair<std::string, std::vector<uint64_t>>> &TransactionInfoImpl::rings() const
{
return m_rings;
}
uint64_t TransactionInfoImpl::confirmations() const
{
return m_confirmations;

View File

@@ -63,6 +63,8 @@ public:
virtual uint64_t confirmations() const override;
virtual uint64_t unlockTime() const override;
virtual const std::vector<std::pair<std::string, std::vector<uint64_t>>> &rings() const override;
private:
int m_direction;
bool m_pending;
@@ -81,6 +83,7 @@ private:
std::vector<Transfer> m_transfers;
uint64_t m_confirmations;
uint64_t m_unlock_time;
std::vector<std::pair<std::string, std::vector<uint64_t>>> m_rings;
friend class TransactionHistoryImpl;

View File

@@ -31,6 +31,7 @@
#include "unsigned_transaction.h"
#include "wallet.h"
#include "common_defines.h"
#include "transaction_construction_info.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
@@ -315,4 +316,24 @@ uint64_t UnsignedTransactionImpl::minMixinCount() const
return min_mixin;
}
TransactionConstructionInfo * UnsignedTransactionImpl::transaction(int index) const {
if (index < 0)
return nullptr;
auto index_ = static_cast<unsigned>(index);
return index_ < m_constructionInfo.size() ? m_constructionInfo[index_] : nullptr;
}
void UnsignedTransactionImpl::refresh() {
for (auto t : m_constructionInfo)
delete t;
m_constructionInfo.clear();
for (const auto& p : m_unsigned_tx_set.txes)
m_constructionInfo.push_back(new TransactionConstructionInfoImpl(m_wallet, p));
}
std::vector<TransactionConstructionInfo*> UnsignedTransactionImpl::getAll() const {
return m_constructionInfo;
}
} // namespace

View File

@@ -55,6 +55,9 @@ public:
bool sign(const std::string &signedFileName) override;
std::string confirmationMessage() const override {return m_confirmationMessage;}
uint64_t minMixinCount() const override;
void refresh() override;
std::vector<TransactionConstructionInfo*> getAll() const override;
TransactionConstructionInfo * transaction(int index) const override;
private:
// Callback function to check all loaded tx's and generate confirmationMessage
@@ -67,7 +70,7 @@ private:
std::string m_errorString;
tools::wallet2::unsigned_tx_set m_unsigned_tx_set;
std::string m_confirmationMessage;
std::vector<TransactionConstructionInfo*> m_constructionInfo;
};
}

View File

@@ -35,9 +35,11 @@
#include "transaction_history.h"
#include "address_book.h"
#include "subaddress.h"
#include "coins.h"
#include "subaddress_account.h"
#include "common_defines.h"
#include "common/util.h"
#include "string_coding.h"
#include "mnemonics/electrum-words.h"
#include "mnemonics/english.h"
@@ -63,8 +65,8 @@ namespace {
static const int MAX_REFRESH_INTERVAL_MILLIS = 1000 * 60 * 1;
// Default refresh interval when connected to remote node
static const int DEFAULT_REMOTE_NODE_REFRESH_INTERVAL_MILLIS = 1000 * 10;
// Connection timeout 30 sec
static const int DEFAULT_CONNECTION_TIMEOUT_MILLIS = 1000 * 30;
// Connection timeout 10 sec
static const int DEFAULT_CONNECTION_TIMEOUT_MILLIS = 1000 * 10;
std::string get_default_ringdb_path(cryptonote::network_type nettype)
{
@@ -163,11 +165,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
<< ", tx: " << tx_hash
<< ", amount: " << print_money(amount)
<< ", idx: " << subaddr_index);
// do not signal on received tx if wallet is not syncronized completely
if (m_listener && m_wallet->synchronized()) {
m_listener->moneyReceived(tx_hash, amount);
m_listener->updated();
}
m_listener->moneyReceived(tx_hash, amount);
m_listener->updated();
}
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
@@ -179,11 +178,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
<< ", tx: " << tx_hash
<< ", amount: " << print_money(amount)
<< ", idx: " << subaddr_index);
// do not signal on received tx if wallet is not syncronized completely
if (m_listener && m_wallet->synchronized()) {
m_listener->unconfirmedMoneyReceived(tx_hash, amount);
m_listener->updated();
}
m_listener->unconfirmedMoneyReceived(tx_hash, amount);
m_listener->updated();
}
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx,
@@ -195,11 +191,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
<< ", tx: " << tx_hash
<< ", amount: " << print_money(amount)
<< ", idx: " << subaddr_index);
// do not signal on sent tx if wallet is not syncronized completely
if (m_listener && m_wallet->synchronized()) {
m_listener->moneySpent(tx_hash, amount);
m_listener->updated();
}
m_listener->moneySpent(tx_hash, amount);
m_listener->updated();
}
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx)
@@ -433,15 +426,12 @@ WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds)
m_refreshEnabled = false;
m_addressBook.reset(new AddressBookImpl(this));
m_subaddress.reset(new SubaddressImpl(this));
m_coins.reset(new CoinsImpl(this));
m_subaddressAccount.reset(new SubaddressAccountImpl(this));
m_refreshIntervalMillis = DEFAULT_REFRESH_INTERVAL_MILLIS;
m_refreshThread = boost::thread([this] () {
this->refreshThreadFunc();
});
}
WalletImpl::~WalletImpl()
@@ -760,6 +750,35 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c
return status() == Status_Ok;
}
bool WalletImpl::recoverDeterministicWalletFromSpendKey(const std::string &path, const std::string &password, const std::string &language, const std::string &spendkey_string)
{
clearStatus();
m_errorString.clear();
m_recoveringFromSeed = true;
m_recoveringFromDevice = false;
// parse spend key
crypto::secret_key spendkey;
if (!spendkey_string.empty()) {
cryptonote::blobdata spendkey_data;
if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key))
{
setStatusError(tr("failed to parse secret spend key"));
return false;
}
spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data());
}
try {
m_wallet->generate(path, password, spendkey, true, false);
setSeedLanguage(language);
} catch (const std::exception &e) {
setStatusCritical(e.what());
}
return status() == Status_Ok;
}
bool WalletImpl::close(bool store)
{
@@ -836,6 +855,11 @@ bool WalletImpl::setPassword(const std::string &password)
return status() == Status_Ok;
}
const std::string& WalletImpl::getPassword() const
{
return m_password;
}
bool WalletImpl::setDevicePin(const std::string &pin)
{
clearStatus();
@@ -863,6 +887,27 @@ std::string WalletImpl::address(uint32_t accountIndex, uint32_t addressIndex) co
return m_wallet->get_subaddress_as_str({accountIndex, addressIndex});
}
bool WalletImpl::subaddressIndex(std::string address, std::pair<uint32_t, uint32_t> &index) const
{
clearStatus();
cryptonote::address_parse_info info;
if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address)) {
setStatusError(tr("Failed to parse address"));
return false;
}
auto i = m_wallet->get_subaddress_index(info.address);
if (!i) {
setStatusError(tr("Address doesn't belong to the wallet"));
return false;
}
index.first = i->major;
index.second = i->minor;
return true;
}
std::string WalletImpl::integratedAddress(const std::string &payment_id) const
{
crypto::hash8 pid;
@@ -1031,7 +1076,7 @@ uint64_t WalletImpl::daemonBlockChainHeight() const
if(m_wallet->light_wallet()) {
return m_wallet->get_light_wallet_scanned_block_height();
}
if (!m_is_connected)
if (!m_is_connected && m_synchronized)
return 0;
std::string err;
uint64_t result = m_wallet->get_daemon_blockchain_height(err);
@@ -1050,7 +1095,7 @@ uint64_t WalletImpl::daemonBlockChainTargetHeight() const
if(m_wallet->light_wallet()) {
return m_wallet->get_light_wallet_blockchain_height();
}
if (!m_is_connected)
if (!m_is_connected && m_synchronized)
return 0;
std::string err;
uint64_t result = m_wallet->get_daemon_blockchain_target_height(err);
@@ -1147,6 +1192,48 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file
return transaction;
}
UnsignedTransaction *WalletImpl::loadUnsignedTxFromStr(const std::string &unsigned_tx) {
clearStatus();
UnsignedTransactionImpl * transaction = new UnsignedTransactionImpl(*this);
if (!m_wallet->parse_unsigned_tx_from_str(unsigned_tx, transaction->m_unsigned_tx_set)) {
setStatusError(tr("Failed to load unsigned transactions"));
transaction->m_status = UnsignedTransaction::Status::Status_Error;
transaction->m_errorString = errorString();
return transaction;
}
// Check tx data and construct confirmation message
std::string extra_message;
if (!transaction->m_unsigned_tx_set.transfers.second.empty())
extra_message = (boost::format("%u outputs to import. ") % (unsigned)transaction->m_unsigned_tx_set.transfers.second.size()).str();
transaction->checkLoadedTx([&transaction](){return transaction->m_unsigned_tx_set.txes.size();}, [&transaction](size_t n)->const tools::wallet2::tx_construction_data&{return transaction->m_unsigned_tx_set.txes[n];}, extra_message);
setStatus(transaction->status(), transaction->errorString());
return transaction;
}
UnsignedTransaction *WalletImpl::loadUnsignedTxFromBase64Str(const std::string &unsigned_tx_base64) {
clearStatus();
std::string decoded_tx = epee::string_encoding::base64_decode(unsigned_tx_base64);
return this->loadUnsignedTxFromStr(decoded_tx);
}
PendingTransaction *WalletImpl::loadSignedTx(const std::string &signed_filename) {
clearStatus();
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
if (!m_wallet->load_tx(signed_filename, transaction->m_pending_tx)) {
setStatusError(tr("Failed to load unsigned transactions"));
return transaction;
}
return transaction;
}
bool WalletImpl::submitTransaction(const string &fileName) {
clearStatus();
std::unique_ptr<PendingTransactionImpl> transaction(new PendingTransactionImpl(*this));
@@ -1175,7 +1262,7 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all)
try
{
if (!m_wallet->export_key_images(filename), all)
if (!m_wallet->export_key_images(filename, all))
{
setStatusError(tr("failed to save file ") + filename);
return false;
@@ -1275,6 +1362,91 @@ bool WalletImpl::importOutputs(const string &filename)
return true;
}
bool WalletImpl::importTransaction(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen)
{
try
{
m_wallet->import_tx(txid, o_indices, height, block_version, ts, miner_tx, pool, double_spend_seen);
}
catch (const std::exception &e)
{
LOG_ERROR("Failed to import transaction: " << e.what());
setStatusError(string(tr("Failed to import transaction: ")) + e.what());
return false;
}
return true;
}
std::string WalletImpl::printBlockchain()
{
return m_wallet->printBlockchain();
}
std::string WalletImpl::printTransfers()
{
return m_wallet->printTransfers();
}
std::string WalletImpl::printPayments()
{
return m_wallet->printPayments();
}
std::string WalletImpl::printUnconfirmedPayments()
{
return m_wallet->printUnconfirmedPayments();
}
std::string WalletImpl::printConfirmedTransferDetails()
{
return m_wallet->printConfirmedTransferDetails();
}
std::string WalletImpl::printUnconfirmedTransferDetails()
{
return m_wallet->printUnconfirmedTransferDetails();
}
std::string WalletImpl::printPubKeys()
{
return m_wallet->printPubKeys();
}
std::string WalletImpl::printTxNotes()
{
return m_wallet->printTxNotes();
}
std::string WalletImpl::printSubaddresses()
{
return m_wallet->printSubaddresses();
}
std::string WalletImpl::printSubaddressLabels()
{
return m_wallet->printSubaddressLabels();
}
std::string WalletImpl::printAdditionalTxKeys()
{
return m_wallet->printAdditionalTxKeys();
}
std::string WalletImpl::printAttributes()
{
return m_wallet->printAttributes();
}
std::string WalletImpl::printKeyImages()
{
return m_wallet->printKeyImages();
}
std::string WalletImpl::printAccountTags()
{
return m_wallet->printAccountTags();
}
std::string WalletImpl::printTxKeys()
{
return m_wallet->printTxKeys();
}
std::string WalletImpl::printAddressBook()
{
return m_wallet->printAddressBook();
}
std::string WalletImpl::printScannedPoolTxs()
{
return m_wallet->printScannedPoolTxs();
}
void WalletImpl::addSubaddressAccount(const std::string& label)
{
m_wallet->add_subaddress_account(label);
@@ -1652,6 +1824,137 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices);
}
PendingTransaction *WalletImpl::createTransactionSingle(const string &key_image, const string &dst_addr,
const size_t outputs, PendingTransaction::Priority priority)
{
clearStatus();
// Pause refresh thread while creating transaction
pauseRefresh();
cryptonote::address_parse_info info;
size_t fake_outs_count = m_wallet->adjust_mixin(m_wallet->default_mixin());
//uint32_t adjusted_priority = m_wallet->adjust_priority(static_cast<uint32_t>(priority));
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
do {
std::vector<uint8_t> extra;
std::string extra_nonce;
vector<cryptonote::tx_destination_entry> dsts;
bool error = false;
crypto::key_image ki;
if (!epee::string_tools::hex_to_pod(key_image, ki))
{
setStatusError(tr("failed to parse key image"));
error = true;
break;
}
if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), dst_addr))
{
setStatusError(tr("Invalid destination address"));
error = true;
break;
}
if (info.has_payment_id) {
if (!extra_nonce.empty()) {
setStatusError(tr("a single transaction cannot use more than one payment id"));
error = true;
break;
}
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
}
if (error) {
break;
}
if (!extra_nonce.empty() && !add_extra_nonce_to_tx_extra(extra, extra_nonce)) {
setStatusError(tr("failed to set up payment id, though it was decoded correctly"));
break;
}
try {
transaction->m_pending_tx = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress,
outputs, fake_outs_count, 0 /* unlock time */, priority, extra);
pendingTxPostProcess(transaction);
if (multisig().isMultisig) {
auto tx_set = m_wallet->make_multisig_tx_set(transaction->m_pending_tx);
transaction->m_pending_tx = tx_set.m_ptx;
transaction->m_signers = tx_set.m_signers;
}
} catch (const tools::error::daemon_busy&) {
// TODO: make it translatable with "tr"?
setStatusError(tr("daemon is busy. Please try again later."));
} catch (const tools::error::no_connection_to_daemon&) {
setStatusError(tr("no connection to daemon. Please make sure daemon is running."));
} catch (const tools::error::wallet_rpc_error& e) {
setStatusError(tr("RPC error: ") + e.to_string());
} catch (const tools::error::get_outs_error &e) {
setStatusError((boost::format(tr("failed to get outputs to mix: %s")) % e.what()).str());
} catch (const tools::error::not_enough_unlocked_money& e) {
std::ostringstream writer;
writer << boost::format(tr("not enough money to transfer, available only %s, sent amount %s")) %
print_money(e.available()) %
print_money(e.tx_amount());
setStatusError(writer.str());
} catch (const tools::error::not_enough_money& e) {
std::ostringstream writer;
writer << boost::format(tr("not enough money to transfer, overall balance only %s, sent amount %s")) %
print_money(e.available()) %
print_money(e.tx_amount());
setStatusError(writer.str());
} catch (const tools::error::tx_not_possible& e) {
std::ostringstream writer;
writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) %
print_money(e.available()) %
print_money(e.tx_amount() + e.fee()) %
print_money(e.tx_amount()) %
print_money(e.fee());
setStatusError(writer.str());
} catch (const tools::error::not_enough_outs_to_mix& e) {
std::ostringstream writer;
writer << tr("not enough outputs for specified ring size") << " = " << (e.mixin_count() + 1) << ":";
for (const std::pair<uint64_t, uint64_t> outs_for_amount : e.scanty_outs()) {
writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.first) << ", " << tr("found outputs to use") << " = " << outs_for_amount.second;
}
writer << "\n" << tr("Please sweep unmixable outputs.");
setStatusError(writer.str());
} catch (const tools::error::tx_not_constructed&) {
setStatusError(tr("transaction was not constructed"));
} catch (const tools::error::tx_rejected& e) {
std::ostringstream writer;
writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
setStatusError(writer.str());
} catch (const tools::error::tx_sum_overflow& e) {
setStatusError(e.what());
} catch (const tools::error::zero_destination&) {
setStatusError(tr("one of destinations is zero"));
} catch (const tools::error::tx_too_big& e) {
setStatusError(tr("failed to find a suitable way to split transactions"));
} catch (const tools::error::transfer_error& e) {
setStatusError(string(tr("unknown transfer error: ")) + e.what());
} catch (const tools::error::wallet_internal_error& e) {
setStatusError(string(tr("internal error: ")) + e.what());
} catch (const std::exception& e) {
setStatusError(string(tr("unexpected error: ")) + e.what());
} catch (...) {
setStatusError(tr("unknown error"));
}
} while (false);
statusWithErrorString(transaction->m_status, transaction->m_errorString);
// Resume refresh thread
startRefresh();
return transaction;
}
PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
{
@@ -1755,6 +2058,7 @@ uint64_t WalletImpl::estimateTransactionFee(const std::vector<std::pair<std::str
extra_size,
m_wallet->use_fork_rules(8, 0),
m_wallet->use_fork_rules(HF_VERSION_CLSAG, 0),
true,
m_wallet->get_base_fee(),
m_wallet->get_fee_multiplier(m_wallet->adjust_priority(static_cast<uint32_t>(priority))),
m_wallet->get_fee_quantization_mask());
@@ -1770,6 +2074,11 @@ AddressBook *WalletImpl::addressBook()
return m_addressBook.get();
}
Coins *WalletImpl::coins()
{
return m_coins.get();
}
Subaddress *WalletImpl::subaddress()
{
return m_subaddress.get();
@@ -2238,37 +2547,34 @@ void WalletImpl::refreshThreadFunc()
void WalletImpl::doRefresh()
{
bool success = true;
bool rescan = m_refreshShouldRescan.exchange(false);
// synchronizing async and sync refresh calls
boost::lock_guard<boost::mutex> guarg(m_refreshMutex2);
do try {
LOG_PRINT_L3(__FUNCTION__ << ": doRefresh, rescan = "<<rescan);
// Syncing daemon and refreshing wallet simultaneously is very resource intensive.
// Disable refresh if wallet is disconnected or daemon isn't synced.
if (m_wallet->light_wallet() || daemonSynced()) {
if(rescan)
m_wallet->rescan_blockchain(false);
m_wallet->refresh(trustedDaemon());
if (!m_synchronized) {
m_synchronized = true;
}
// assuming if we have empty history, it wasn't initialized yet
// for further history changes client need to update history in
// "on_money_received" and "on_money_sent" callbacks
if (m_history->count() == 0) {
m_history->refresh();
}
m_wallet->find_and_save_rings(false);
} else {
LOG_PRINT_L3(__FUNCTION__ << ": skipping refresh - daemon is not synced");
if(rescan)
m_wallet->rescan_blockchain(false);
m_wallet->refresh(trustedDaemon());
if (!m_synchronized) {
m_synchronized = true;
}
// assuming if we have empty history, it wasn't initialized yet
// for further history changes client need to update history in
// "on_money_received" and "on_money_sent" callbacks
if (m_history->count() == 0) {
m_history->refresh();
}
m_wallet->find_and_save_rings(false);
} catch (const std::exception &e) {
success = false;
setStatusError(e.what());
break;
}while(!rescan && (rescan=m_refreshShouldRescan.exchange(false))); // repeat if not rescanned and rescan was requested
m_is_connected = success;
if (m_wallet2Callback->getListener()) {
m_wallet2Callback->getListener()->refreshed();
m_wallet2Callback->getListener()->refreshed(success);
}
}
@@ -2331,8 +2637,14 @@ void WalletImpl::pendingTxPostProcess(PendingTransactionImpl * pending)
bool WalletImpl::doInit(const string &daemon_address, const std::string &proxy_address, uint64_t upper_transaction_size_limit, bool ssl)
{
if (!m_wallet->init(daemon_address, m_daemon_login, proxy_address, upper_transaction_size_limit))
return false;
if (!m_wallet->init(daemon_address,
m_daemon_login,
proxy_address,
upper_transaction_size_limit,
trustedDaemon(),
ssl ? epee::net_utils::ssl_support_t::e_ssl_support_autodetect : epee::net_utils::ssl_support_t::e_ssl_support_disabled)) {
return false;
}
// in case new wallet, this will force fast-refresh (pulling hashes instead of blocks)
// If daemon isn't synced a calculated block height will be used instead

View File

@@ -46,8 +46,11 @@ class PendingTransactionImpl;
class UnsignedTransactionImpl;
class AddressBookImpl;
class SubaddressImpl;
class CoinsImpl;
class SubaddressAccountImpl;
struct Wallet2CallbackImpl;
class PendingTransactionInfoImpl;
class TransactionConstructionInfoImpl;
class WalletImpl : public Wallet
{
@@ -76,6 +79,10 @@ public:
const std::string &address_string,
const std::string &viewkey_string,
const std::string &spendkey_string = "");
bool recoverDeterministicWalletFromSpendKey(const std::string &path,
const std::string &password,
const std::string &language,
const std::string &spendkey_string);
bool recoverFromDevice(const std::string &path,
const std::string &password,
const std::string &device_name);
@@ -89,9 +96,11 @@ public:
std::string errorString() const override;
void statusWithErrorString(int& status, std::string& errorString) const override;
bool setPassword(const std::string &password) override;
const std::string& getPassword() const override;
bool setDevicePin(const std::string &password) override;
bool setDevicePassphrase(const std::string &password) override;
std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const override;
bool subaddressIndex(std::string address, std::pair<uint32_t, uint32_t> &index) const override;
std::string integratedAddress(const std::string &payment_id) const override;
std::string secretViewKey() const override;
std::string publicViewKey() const override;
@@ -162,19 +171,46 @@ public:
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {}) override;
PendingTransaction * createTransactionSingle(const std::string &key_image, const std::string &dst_addr,
size_t outputs = 1, PendingTransaction::Priority priority = PendingTransaction::Priority_Low) override;
virtual PendingTransaction * createSweepUnmixableTransaction() override;
bool submitTransaction(const std::string &fileName) override;
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override;
virtual UnsignedTransaction * loadUnsignedTxFromStr(const std::string &unsigned_tx) override;
virtual UnsignedTransaction * loadUnsignedTxFromBase64Str(const std::string &unsigned_tx) override;
virtual PendingTransaction * loadSignedTx(const std::string &signed_filename) override;
bool exportKeyImages(const std::string &filename, bool all = false) override;
bool importKeyImages(const std::string &filename) override;
bool exportOutputs(const std::string &filename, bool all = false) override;
bool importOutputs(const std::string &filename) override;
bool importTransaction(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen) override;
virtual std::string printBlockchain() override;
virtual std::string printTransfers() override;
virtual std::string printPayments() override;
virtual std::string printUnconfirmedPayments() override;
virtual std::string printConfirmedTransferDetails() override;
virtual std::string printUnconfirmedTransferDetails() override;
virtual std::string printPubKeys() override;
virtual std::string printTxNotes() override;
virtual std::string printSubaddresses() override;
virtual std::string printSubaddressLabels() override;
virtual std::string printAdditionalTxKeys() override;
virtual std::string printAttributes() override;
virtual std::string printKeyImages() override;
virtual std::string printAccountTags() override;
virtual std::string printTxKeys() override;
virtual std::string printAddressBook() override;
virtual std::string printScannedPoolTxs() override;
virtual void disposeTransaction(PendingTransaction * t) override;
virtual uint64_t estimateTransactionFee(const std::vector<std::pair<std::string, uint64_t>> &destinations,
PendingTransaction::Priority priority) const override;
virtual TransactionHistory * history() override;
virtual AddressBook * addressBook() override;
virtual Coins * coins() override;
virtual Subaddress * subaddress() override;
virtual SubaddressAccount * subaddressAccount() override;
virtual void setListener(WalletListener * l) override;
@@ -244,7 +280,10 @@ private:
friend struct Wallet2CallbackImpl;
friend class AddressBookImpl;
friend class SubaddressImpl;
friend class CoinsImpl;
friend class SubaddressAccountImpl;
friend class PendingTransactionInfoImpl;
friend class TransactionConstructionInfoImpl;
std::unique_ptr<tools::wallet2> m_wallet;
mutable boost::mutex m_statusMutex;
@@ -255,6 +294,7 @@ private:
std::unique_ptr<Wallet2CallbackImpl> m_wallet2Callback;
std::unique_ptr<AddressBookImpl> m_addressBook;
std::unique_ptr<SubaddressImpl> m_subaddress;
std::unique_ptr<CoinsImpl> m_coins;
std::unique_ptr<SubaddressAccountImpl> m_subaddressAccount;
// multi-threaded refresh stuff

View File

@@ -66,6 +66,47 @@ enum NetworkType : uint8_t {
bool set;
};
/*
* @brief Transaction construction data
*/
struct TransactionConstructionInfo
{
struct Input {
Input(uint64_t _amount, const std::string &_pubkey);
const uint64_t amount;
const std::string pubkey;
};
struct Output {
Output(uint64_t _amount, const std::string &_address);
const uint64_t amount;
const std::string address;
};
virtual ~TransactionConstructionInfo() = 0;
virtual uint64_t unlockTime() const = 0;
virtual std::set<std::uint32_t> subaddressIndices() const = 0;
virtual std::vector<std::string> subaddresses() const = 0;
virtual uint64_t minMixinCount() const = 0;
virtual std::vector<Input> inputs() const = 0;
virtual std::vector<Output> outputs() const = 0;
};
/*
* @brief Detailed pending transaction information
*/
struct PendingTransactionInfo
{
virtual ~PendingTransactionInfo() = 0;
virtual uint64_t fee() const = 0;
virtual uint64_t dust() const = 0;
virtual bool dustAddedToFee() const = 0;
virtual std::string txKey() const = 0;
virtual TransactionConstructionInfo * constructionData() const = 0;
};
/**
* @brief Transaction-like interface for sending money
*/
@@ -101,6 +142,13 @@ struct PendingTransaction
virtual uint64_t txCount() const = 0;
virtual std::vector<uint32_t> subaddrAccount() const = 0;
virtual std::vector<std::set<uint32_t>> subaddrIndices() const = 0;
virtual std::string unsignedTxToBin() const = 0;
virtual std::string unsignedTxToBase64() const = 0;
virtual std::string signedTxToHex(int index) const = 0;
virtual size_t signedTxSize(int index) const = 0;
virtual PendingTransactionInfo * transaction(int index) const = 0;
virtual void refresh() = 0;
virtual std::vector<PendingTransactionInfo*> getAll() const = 0;
/**
* @brief multisigSignData
@@ -160,6 +208,9 @@ struct UnsignedTransaction
* return - true on success
*/
virtual bool sign(const std::string &signedFileName) = 0;
virtual void refresh() = 0;
virtual std::vector<TransactionConstructionInfo*> getAll() const = 0;
virtual TransactionConstructionInfo * transaction(int index) const = 0;
};
/**
@@ -198,6 +249,7 @@ struct TransactionInfo
virtual std::string paymentId() const = 0;
//! only applicable for output transactions
virtual const std::vector<Transfer> & transfers() const = 0;
virtual const std::vector<std::pair<std::string, std::vector<uint64_t>>> & rings() const = 0;
};
/**
* @brief The TransactionHistory - interface for displaying transaction history
@@ -260,22 +312,66 @@ struct AddressBook
virtual int lookupPaymentID(const std::string &payment_id) const = 0;
};
/**
* @brief The CoinsInfo - interface for displaying coins information
*/
struct CoinsInfo
{
virtual ~CoinsInfo() = 0;
virtual uint64_t blockHeight() const = 0;
virtual std::string hash() const = 0;
virtual size_t internalOutputIndex() const = 0;
virtual uint64_t globalOutputIndex() const = 0;
virtual bool spent() const = 0;
virtual bool frozen() const = 0;
virtual uint64_t spentHeight() const = 0;
virtual uint64_t amount() const = 0;
virtual bool rct() const = 0;
virtual bool keyImageKnown() const = 0;
virtual size_t pkIndex() const = 0;
virtual uint32_t subaddrIndex() const = 0;
virtual uint32_t subaddrAccount() const = 0;
virtual std::string address() const = 0;
virtual std::string addressLabel() const = 0;
virtual std::string keyImage() const = 0;
virtual uint64_t unlockTime() const = 0;
virtual bool unlocked() const = 0;
virtual std::string pubKey() const = 0;
virtual bool coinbase() const = 0;
};
struct Coins
{
virtual ~Coins() = 0;
virtual int count() const = 0;
virtual CoinsInfo * coin(int index) const = 0;
virtual std::vector<CoinsInfo*> getAll() const = 0;
virtual void refresh() = 0;
virtual void setFrozen(int index) = 0;
virtual void thaw(int index) = 0;
virtual bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) = 0;
};
struct SubaddressRow {
public:
SubaddressRow(std::size_t _rowId, const std::string &_address, const std::string &_label):
SubaddressRow(std::size_t _rowId, const std::string &_address, const std::string &_label, bool _used):
m_rowId(_rowId),
m_address(_address),
m_label(_label) {}
m_label(_label),
m_used(_used) {}
private:
std::size_t m_rowId;
std::string m_address;
std::string m_label;
bool m_used;
public:
std::string extra;
std::string getAddress() const {return m_address;}
std::string getLabel() const {return m_label;}
std::size_t getRowId() const {return m_rowId;}
bool isUsed() const {return m_used;}
};
struct Subaddress
@@ -382,7 +478,7 @@ struct WalletListener
/**
* @brief refreshed - called when wallet refreshed by background thread or explicitly refreshed by calling "refresh" synchronously
*/
virtual void refreshed() = 0;
virtual void refreshed(bool success) = 0;
/**
* @brief called by device if the action is required
@@ -456,9 +552,11 @@ struct Wallet
//! returns both error and error string atomically. suggested to use in instead of status() and errorString()
virtual void statusWithErrorString(int& status, std::string& errorString) const = 0;
virtual bool setPassword(const std::string &password) = 0;
virtual const std::string& getPassword() const = 0;
virtual bool setDevicePin(const std::string &pin) { (void)pin; return false; };
virtual bool setDevicePassphrase(const std::string &passphrase) { (void)passphrase; return false; };
virtual std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const = 0;
virtual bool subaddressIndex(std::string address, std::pair<uint32_t, uint32_t> &index) const = 0;
std::string mainAddress() const { return address(0, 0); }
virtual std::string path() const = 0;
virtual NetworkType nettype() const = 0;
@@ -868,6 +966,18 @@ struct Wallet
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {}) = 0;
/*!
* \brief createTransactionSingle creates transaction with single input
* \param key_image key image as string
* \param dst_addr destination address as string
* \param priority
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
* after object returned
*/
virtual PendingTransaction * createTransactionSingle(const std::string &key_image, const std::string &dst_addr,
size_t outputs = 1, PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0;
/*!
* \brief createSweepUnmixableTransaction creates transaction with unmixable outputs.
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
@@ -882,7 +992,27 @@ struct Wallet
* after object returned
*/
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0;
/*!
* \brief loadUnsignedTx - creates transaction from unsigned tx string
* \return - UnsignedTransaction object. caller is responsible to check UnsignedTransaction::status()
* after object returned
*/
virtual UnsignedTransaction * loadUnsignedTxFromStr(const std::string &unsigned_tx) = 0;
/*!
* \brief loadUnsignedTx - creates transaction from unsigned base64 encoded tx string
* \return - UnsignedTransaction object. caller is responsible to check UnsignedTransaction::status()
* after object returned
*/
virtual UnsignedTransaction * loadUnsignedTxFromBase64Str(const std::string &unsigned_tx_base64) = 0;
/*!
* \brief loadSignedTx - creates transaction from signed tx file
* \return - PendingTransaction object.
*/
virtual PendingTransaction * loadSignedTx(const std::string &signed_filename) = 0;
/*!
* \brief submitTransaction - submits transaction in signed tx file
* \return - true on success
@@ -933,8 +1063,29 @@ struct Wallet
*/
virtual bool importOutputs(const std::string &filename) = 0;
virtual bool importTransaction(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen) = 0;
virtual std::string printBlockchain() = 0;
virtual std::string printTransfers() = 0;
virtual std::string printPayments() = 0;
virtual std::string printUnconfirmedPayments() = 0;
virtual std::string printConfirmedTransferDetails() = 0;
virtual std::string printUnconfirmedTransferDetails() = 0;
virtual std::string printPubKeys() = 0;
virtual std::string printTxNotes() = 0;
virtual std::string printSubaddresses() = 0;
virtual std::string printSubaddressLabels() = 0;
virtual std::string printAdditionalTxKeys() = 0;
virtual std::string printAttributes() = 0;
virtual std::string printKeyImages() = 0;
virtual std::string printAccountTags() = 0;
virtual std::string printTxKeys() = 0;
virtual std::string printAddressBook() = 0;
virtual std::string printScannedPoolTxs() = 0;
virtual TransactionHistory * history() = 0;
virtual AddressBook * addressBook() = 0;
virtual Coins * coins() = 0;
virtual Subaddress * subaddress() = 0;
virtual SubaddressAccount * subaddressAccount() = 0;
virtual void setListener(WalletListener *) = 0;
@@ -991,7 +1142,8 @@ struct Wallet
/*
* \brief signMessage - sign a message with the spend private key
* \param message - the message to sign (arbitrary byte data)
* \return the signature
* \param address - the address to make the signature with, defaults to primary address (optional)
* \return the signature, empty string if the address is invalid or does not belong to the wallet
*/
virtual std::string signMessage(const std::string &message, const std::string &address = "") = 0;
/*!
@@ -1200,6 +1352,25 @@ struct WalletManager
return createWalletFromKeys(path, password, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString);
}
/*!
* \brief recover deterministic wallet from spend key.
* \param path Name of wallet file to be created
* \param password Password of wallet file
* \param language language
* \param nettype Network type
* \param restoreHeight restore from start height
* \param spendKeyString spend key
* \param kdf_rounds Number of rounds for key derivation function
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
*/
virtual Wallet * createDeterministicWalletFromSpendKey(const std::string &path,
const std::string &password,
const std::string &language,
NetworkType nettype,
uint64_t restoreHeight,
const std::string &spendKeyString,
uint64_t kdf_rounds = 1) = 0;
/*!
* \deprecated this method creates a wallet WITHOUT a passphrase, use createWalletFromKeys(..., password, ...) instead
* \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted

View File

@@ -122,6 +122,22 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path,
return wallet;
}
Wallet *WalletManagerImpl::createDeterministicWalletFromSpendKey(const std::string &path,
const std::string &password,
const std::string &language,
NetworkType nettype,
uint64_t restoreHeight,
const std::string &spendkey_string,
uint64_t kdf_rounds)
{
WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds);
if(restoreHeight > 0){
wallet->setRefreshFromBlockHeight(restoreHeight);
}
wallet->recoverDeterministicWalletFromSpendKey(path, password, language, spendkey_string);
return wallet;
}
Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
const std::string &password,
NetworkType nettype,

View File

@@ -67,6 +67,13 @@ public:
const std::string &addressString,
const std::string &viewKeyString,
const std::string &spendKeyString = "") override;
virtual Wallet * createDeterministicWalletFromSpendKey(const std::string &path,
const std::string &password,
const std::string &language,
NetworkType nettype,
uint64_t restoreHeight,
const std::string &spendkey_string,
uint64_t kdf_rounds) override;
virtual Wallet * createWalletFromDevice(const std::string &path,
const std::string &password,
NetworkType nettype,

View File

@@ -51,7 +51,7 @@ using namespace epee;
namespace tools
{
static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
static const std::chrono::seconds rpc_timeout = std::chrono::seconds(10);
NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::abstract_http_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex)
: m_http_client(http_client)
@@ -162,7 +162,7 @@ boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height)
auto res = get_info();
if (res)
return res;
height = m_target_height;
height = m_target_height > m_height ? m_target_height : m_height;
return boost::optional<std::string>();
}

View File

@@ -1537,6 +1537,14 @@ void wallet2::add_subaddress_account(const std::string& label)
m_subaddress_labels[index_major][0] = label;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_subaddress_used(const cryptonote::subaddress_index& index)
{
return std::find_if(m_transfers.begin(), m_transfers.end(),
[this, index](const transfer_details &td) {
return td.m_subaddr_index == index;
}) != m_transfers.end();
}
//----------------------------------------------------------------------------------------------------
void wallet2::add_subaddress(uint32_t index_major, const std::string& label)
{
THROW_WALLET_EXCEPTION_IF(index_major >= m_subaddress_labels.size(), error::account_index_outofbound);
@@ -2169,13 +2177,14 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount;
if (!pool)
{
m_transfers.push_back(transfer_details{});
transfer_details& td = m_transfers.back();
td.m_block_height = height;
td.m_internal_output_index = o;
td.m_global_output_index = o_indices[o];
td.m_tx = (const cryptonote::transaction_prefix&)tx;
td.m_txid = txid;
boost::unique_lock<boost::shared_mutex> lock(m_transfers_mutex);
m_transfers.push_back(transfer_details{});
transfer_details& td = m_transfers.back();
td.m_block_height = height;
td.m_internal_output_index = o;
td.m_global_output_index = o_indices[o];
td.m_tx = (const cryptonote::transaction_prefix&)tx;
td.m_txid = txid;
td.m_key_image = tx_scan_info[o].ki;
td.m_key_image_known = !m_watch_only && !m_multisig;
if (!td.m_key_image_known)
@@ -2233,6 +2242,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
update_multisig_rescan_info(*m_multisig_rescan_k, *m_multisig_rescan_info, m_transfers.size() - 1);
}
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
lock.unlock();
if (0 != m_callback)
m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time);
}
@@ -2271,12 +2282,13 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
uint64_t extra_amount = amount - m_transfers[kit->second].amount();
if (!pool)
{
boost::unique_lock<boost::shared_mutex> lock(m_transfers_mutex);
transfer_details &td = m_transfers[kit->second];
td.m_block_height = height;
td.m_internal_output_index = o;
td.m_global_output_index = o_indices[o];
td.m_tx = (const cryptonote::transaction_prefix&)tx;
td.m_txid = txid;
td.m_block_height = height;
td.m_internal_output_index = o;
td.m_global_output_index = o_indices[o];
td.m_tx = (const cryptonote::transaction_prefix&)tx;
td.m_txid = txid;
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
td.m_subaddr_index = tx_scan_info[o].received->index;
@@ -3212,6 +3224,54 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
}
MTRACE("update_pool_state end");
}
//----------------------------------------------------------------------------------------------------
void wallet2::import_tx(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen)
{
crypto::hash hash;
epee::string_tools::hex_to_pod(txid, hash);
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req;
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res;
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(hash));
req.decode_as_json = false;
req.prune = true;
bool r;
{
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
uint64_t pre_call_credits = m_rpc_payment_state.credits;
req.client = get_client_signature();
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
if (r && res.status == CORE_RPC_STATUS_OK)
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, res.txs.size() * COST_PER_TX);
}
MDEBUG("Got " << r << " and " << res.status);
if (!(r && res.status == CORE_RPC_STATUS_OK)) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Error calling gettransactions daemon RPC: r " + std::to_string(r) + ", status " + get_rpc_status(res.status));
}
if (res.txs.size() != 1) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Expected 1 tx, got " + std::to_string(res.txs.size()));
}
const auto &tx_entry = res.txs[0];
cryptonote::transaction tx;
cryptonote::blobdata bd;
crypto::hash tx_hash;
if (!get_pruned_tx(tx_entry, tx, tx_hash)) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Failed to parse transaction from daemon");
}
if (tx_hash != hash) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Got txid " + epee::string_tools::pod_to_hex(tx_hash) + " which we did not ask for");
}
process_new_transaction(tx_hash, tx, o_indices, height, block_version, ts, miner_tx, pool, double_spend_seen, {});
}
//----------------------------------------------------------------------------------------------------
void wallet2::process_pool_state(const std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> &txs)
{
@@ -3235,11 +3295,19 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height,
{
std::vector<crypto::hash> hashes;
const uint64_t checkpoint_height = m_checkpoints.get_max_height();
// Get highest checkpoint that is lower than stop_height
uint64_t checkpoint_height = 0;
for (auto i : m_checkpoints.get_points()) {
if (i.first > stop_height) {
break;
}
checkpoint_height = i.first;
}
if ((stop_height > checkpoint_height && m_blockchain.size()-1 < checkpoint_height) && !force)
{
// we will drop all these, so don't bother getting them
uint64_t missing_blocks = m_checkpoints.get_max_height() - m_blockchain.size();
uint64_t missing_blocks = checkpoint_height - m_blockchain.size();
while (missing_blocks-- > 0)
m_blockchain.push_back(crypto::null_hash); // maybe a bit suboptimal, but deque won't do huge reallocs like vector
m_blockchain.push_back(m_checkpoints.get_points().at(checkpoint_height));
@@ -5504,6 +5572,315 @@ void wallet2::write_watch_only_wallet(const std::string& wallet_name, const epee
bool r = store_keys(new_keys_filename, password, true);
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, new_keys_filename);
}
std::string wallet2::printBlockchain()
{
std::string blstr;
blstr += "offset: " + std::to_string(m_blockchain.offset()) + "\n";
blstr += "genesis: " + string_tools::pod_to_hex(m_blockchain.genesis()) + "\n";
for (size_t i = m_blockchain.offset(); i < m_blockchain.size(); i++) {
blstr += std::to_string(i) + " : " + string_tools::pod_to_hex(m_blockchain[i]) + "\n";
}
return blstr;
}
std::string wallet2::printTransfers()
{
std::string str;
for (const auto &td : m_transfers) {
str += "block_height: " + std::to_string(td.m_block_height) + "\n";
str += printTxPrefix(td.m_tx);
str += "txid: " + string_tools::pod_to_hex(td.m_txid) + "\n";
str += "internal_output_index: " + std::to_string(td.m_internal_output_index) + "\n";
str += "global_output_index: " + std::to_string(td.m_global_output_index) + "\n";
str += "spent: " + std::to_string(td.m_spent) + "\n";
str += "frozen: " + std::to_string(td.m_frozen) + "\n";
str += "spent_height: " + std::to_string(td.m_spent_height) + "\n";
str += "key_image: " + string_tools::pod_to_hex(td.m_key_image) + "\n";
str += "mask: " + string_tools::pod_to_hex(td.m_mask) + "\n";
str += "amount: " + std::to_string(td.m_amount) + "\n";
str += "rct: " + std::to_string(td.m_rct) + "\n";
str += "key_image_known: " + std::to_string(td.m_key_image_known) + "\n";
str += "key_image_request: " + std::to_string(td.m_key_image_request) + "\n";
str += "pk_index: " + std::to_string(td.m_pk_index) + "\n";
str += "subaddr_index: " + std::to_string(td.m_subaddr_index.major) + "," + std::to_string(td.m_subaddr_index.minor) + "\n";
str += "key_image_partial: " + std::to_string(td.m_key_image_partial) + "\n";
str += "multisig_k:\n";
for (const auto &el : td.m_multisig_k) {
str += " " + string_tools::pod_to_hex(el) + "\n";
}
str += "multisig_info:\n";
for (const auto &el : td.m_multisig_info) {
str += " signer: " + string_tools::pod_to_hex(el.m_signer) + "\n";
str += " LR:\n";
for (const auto &em : el.m_LR) {
str += " L: " + string_tools::pod_to_hex(em.m_L) + "\n";
str += " R: " + string_tools::pod_to_hex(em.m_R) + "\n";
}
str += "\n";
str += " partial_key_images:\n";
for (const auto &em : el.m_partial_key_images) {
str += " " + string_tools::pod_to_hex(em) + "\n";
}
str += "\n";
}
str += "uses:\n";
for (const auto &el : td.m_uses) {
str += " " + std::to_string(el.first) + " : " + string_tools::pod_to_hex(el.second) + "\n";
}
str += "\n";
}
return str;
}
std::string wallet2::printUnconfirmedPayments()
{
std::string str;
for (const auto &el : m_unconfirmed_payments) {
auto ppd = el.second;
str += "double_spend_seen: " + std::to_string(ppd.m_double_spend_seen) + "\n";
str += printPaymentDetails(ppd.m_pd);
str += "\n";
}
return str;
}
std::string wallet2::printConfirmedTransferDetails()
{
std::string str;
for (const auto &el : m_confirmed_txs) {
auto ctd = el.second;
str += "amount_in: " + std::to_string(ctd.m_amount_in) + "\n";
str += "amount_out: " + std::to_string(ctd.m_amount_out) + "\n";
str += "change: " + std::to_string(ctd.m_change) + "\n";
str += "block_height: " + std::to_string(ctd.m_block_height) + "\n";
str += "dests:\n";
for (const auto &em : ctd.m_dests) {
str += printTxDestinationEntry(em);
}
str += "payment_id: " + string_tools::pod_to_hex(ctd.m_payment_id) + "\n";
str += "timestamp: " + std::to_string(ctd.m_timestamp) + "\n";
str += "unlock_time: " + std::to_string(ctd.m_unlock_time) + "\n";
str += "subaddr_account: " + std::to_string(ctd.m_subaddr_account) + "\n";
str += "subaddr_indices: ";
for (auto em : ctd.m_subaddr_indices) {
str += std::to_string(em);
}
str += "\n\n";
}
return str;
}
std::string wallet2::printUnconfirmedTransferDetails()
{
std::string str;
for (const auto &el : m_unconfirmed_txs) {
auto utd = el.second;
str += printTxPrefix(utd.m_tx);
str += "amount_in: " + std::to_string(utd.m_amount_in) + "\n";
str += "amount_out: " + std::to_string(utd.m_amount_out) + "\n";
str += "change: " + std::to_string(utd.m_change) + "\n";
str += "sent_time: " + std::to_string(utd.m_sent_time) + "\n";
str += "dests:\n";
for (const auto &em : utd.m_dests) {
str += printTxDestinationEntry(em);
}
str += "payment_id: " + string_tools::pod_to_hex(utd.m_payment_id) + "\n";
str += "timestamp: " + std::to_string(utd.m_timestamp) + "\n";
str += "subaddr_account: " + std::to_string(utd.m_subaddr_account) + "\n";
str += "subaddr_indices: ";
for (auto em : utd.m_subaddr_indices) {
str += std::to_string(em);
}
str += "\n\n";
}
return str;
}
std::string wallet2::printPayments()
{
std::string str;
for (const auto &el : m_payments) {
str += printPaymentDetails(el.second) + "\n";
}
return str;
}
std::string wallet2::printPubKeys()
{
std::string str;
vector<std::pair<crypto::public_key, size_t>> v;
for (const auto &el : m_pub_keys) {
v.push_back(el);
}
std::sort(v.begin(), v.end(),
[](std::pair<crypto::public_key, size_t> a, std::pair<crypto::public_key, size_t> b){return a.second < b.second;});
for (const auto &el : v){
str += string_tools::pod_to_hex(el.first) + " : " + boost::to_string(el.second) + "\n";
}
return str;
}
std::string wallet2::printTxNotes()
{
std::string str;
for (std::pair<crypto::hash, std::string> el : m_tx_notes) {
str += string_tools::pod_to_hex(el.first) + " : " + el.second + "\n";
}
return str;
}
std::string wallet2::printSubaddresses()
{
std::string str;
vector<std::pair<crypto::public_key, cryptonote::subaddress_index>> v;
for (const auto &el : m_subaddresses) {
v.push_back(el);
}
std::sort(v.begin(), v.end(), [](std::pair<crypto::public_key, cryptonote::subaddress_index> a, std::pair<crypto::public_key, cryptonote::subaddress_index> b) {
if (a.second.major == b.second.major) {
return a.second.minor < b.second.minor;
}
return a.second.major < b.second.major;
});
for (const auto &el : v) {
str += string_tools::pod_to_hex(el.first) + " : " + std::to_string(el.second.major) + "," + std::to_string(el.second.minor) + "\n";
}
return str;
}
std::string wallet2::printSubaddressLabels()
{
std::string str;
for (size_t i = 0; i < m_subaddress_labels.size(); i++) {
for (size_t j = 0; j < m_subaddress_labels[i].size(); j++) {
str += std::to_string(i) + "," + std::to_string(j) + " : " + m_subaddress_labels[i][j] + "\n";
}
}
return str;
}
std::string wallet2::printAdditionalTxKeys()
{
std::string str;
for (std::pair<crypto::hash, std::vector<crypto::secret_key>> el : m_additional_tx_keys) {
str += "Txid: " + string_tools::pod_to_hex(el.first) + " (" + std::to_string(el.second.size()) + ")\n";
for (auto em : el.second) {
str += " " + string_tools::pod_to_hex(em) + "\n";
}
}
return str;
}
std::string wallet2::printAttributes()
{
std::string str;
for (auto el : m_attributes) {
str += el.first + " : " + el.second + "\n";
}
return str;
}
std::string wallet2::printKeyImages()
{
std::string str;
vector<std::pair<crypto::key_image, size_t>> v;
for (const auto &el : m_key_images) {
v.push_back(el);
}
std::sort(v.begin(), v.end(), [](std::pair<crypto::key_image, size_t> a, std::pair<crypto::key_image, size_t> b){return a.second < b.second;});
for (const auto &el: v) {
str += string_tools::pod_to_hex(el.first) + " : " + boost::to_string(el.second) + "\n";
}
return str;
}
std::string wallet2::printAccountTags()
{
std::string str;
for (size_t i = 0; i < m_account_tags.second.size(); i++) {
str += std::to_string(i) + " : " + m_account_tags.second[i] + "\n";
}
return str;
}
std::string wallet2::printTxKeys()
{
std::string str;
for (std::pair<crypto::hash, crypto::secret_key> el : m_tx_keys) {
str += string_tools::pod_to_hex(el.first) + " : " + string_tools::pod_to_hex(el.second) + "\n";
}
return str;
}
std::string wallet2::printAddressBook()
{
std::string str;
for (auto el : m_address_book) {
str += "address: " + string_tools::pod_to_hex(el.m_address) + "\n";
str += "payment_id: " + string_tools::pod_to_hex(el.m_payment_id) + "\n";
str += "description: " + el.m_description + "\n";
str += "is_subaddress: " + std::to_string(el.m_is_subaddress) + "\n";
str += "has_payment_id: " + std::to_string(el.m_has_payment_id) + "\n";
str += "\n";
}
return str;
}
std::string wallet2::printScannedPoolTxs()
{
std::string str;
for (size_t i = 0; i < 2; i++) {
str += "scanned_pool_txs[" + std::to_string(i) + "]\n";
for (auto el : m_scanned_pool_txs[i]) {
str += string_tools::pod_to_hex(el) + "\n";
}
str += "\n";
}
return str;
}
std::string wallet2::printTxPrefix(const cryptonote::transaction_prefix &tx)
{
std::string str;
str += "tx.version: " + std::to_string(tx.version) + "\n";
str += "tx.unlock_time: " + std::to_string(tx.unlock_time) + "\n";
return str;
}
std::string wallet2::printPaymentDetails(const payment_details &pd)
{
std::string str;
str += "tx_hash: " + string_tools::pod_to_hex(pd.m_tx_hash) + "\n";
str += "amount: " + std::to_string(pd.m_amount) + "\n";
str += "amounts: ";
for (auto em : pd.m_amounts) {
str += std::to_string(em);
}
str += "\n";
str += "fee: " + std::to_string(pd.m_fee) + "\n";
str += "block_height: " + std::to_string(pd.m_block_height) + "\n";
str += "unlock_time: " + std::to_string(pd.m_unlock_time) + "\n";
str += "timestamp: " + std::to_string(pd.m_timestamp) + "\n";
str += "coinbase: " + std::to_string(pd.m_coinbase) + "\n";
str += "subaddr_index: " + std::to_string(pd.m_subaddr_index.major) + "," + std::to_string(pd.m_subaddr_index.minor) + "\n";
return str;
}
std::string wallet2::printTxDestinationEntry(const cryptonote::tx_destination_entry &tx)
{
std::string str;
str += " original: " + tx.original + "\n";
str += " amount: " + std::to_string(tx.amount) + "\n";
str += " addr: " + string_tools::pod_to_hex(tx.addr) + "\n";
str += " is_subaddress: " + std::to_string(tx.is_subaddress) + "\n";
str += " is_integrated: " + std::to_string(tx.is_integrated) + "\n";
return str;
}
//----------------------------------------------------------------------------------------------------
void wallet2::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exists)
{

View File

@@ -232,7 +232,7 @@ private:
friend class wallet_keys_unlocker;
friend class wallet_device_callback;
public:
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::seconds(10);
enum RefreshType {
RefreshFull,
@@ -910,6 +910,7 @@ private:
std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) const;
std::string get_address_as_str() const { return get_subaddress_as_str({0, 0}); }
std::string get_integrated_address_as_str(const crypto::hash8& payment_id) const;
bool get_subaddress_used(const cryptonote::subaddress_index& index);
void add_subaddress_account(const std::string& label);
size_t get_num_subaddress_accounts() const { return m_subaddress_labels.size(); }
size_t get_num_subaddresses(uint32_t index_major) const { return index_major < m_subaddress_labels.size() ? m_subaddress_labels[index_major].size() : 0; }
@@ -1388,6 +1389,7 @@ private:
bool import_key_images(std::vector<crypto::key_image> key_images, size_t offset=0, boost::optional<std::unordered_set<size_t>> selected_transfers=boost::none);
bool import_key_images(signed_tx_set & signed_tx, size_t offset=0, bool only_selected_transfers=false);
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
void import_tx(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen);
void update_pool_state(std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> &process_txs, bool refreshed = false);
void process_pool_state(const std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> &txs);
@@ -1532,6 +1534,27 @@ private:
uint64_t get_bytes_sent() const;
uint64_t get_bytes_received() const;
std::string printBlockchain();
std::string printTransfers();
std::string printKeyImages();
std::string printUnconfirmedTransferDetails();
std::string printPayments();
std::string printUnconfirmedPayments();
std::string printConfirmedTransferDetails();
std::string printPubKeys();
std::string printTxNotes();
std::string printSubaddresses();
std::string printSubaddressLabels();
std::string printAdditionalTxKeys();
std::string printAttributes();
std::string printAccountTags();
std::string printTxKeys();
std::string printAddressBook();
std::string printScannedPoolTxs();
std::string printTxPrefix(const cryptonote::transaction_prefix &tx);
std::string printPaymentDetails(const payment_details &pd);
std::string printTxDestinationEntry(const cryptonote::tx_destination_entry &tx);
// MMS -------------------------------------------------------------------------------------------------
mms::message_store& get_message_store() { return m_message_store; };
const mms::message_store& get_message_store() const { return m_message_store; };
@@ -1558,6 +1581,7 @@ private:
static std::string get_default_daemon_address() { CRITICAL_REGION_LOCAL(default_daemon_address_lock); return default_daemon_address; }
boost::shared_mutex m_transfers_mutex;
private:
/*!
* \brief Stores wallet information to wallet file.

View File

@@ -1,8 +0,0 @@
# Configuration for wownerod
# Syntax: any command line option may be specified as 'clioptionname=value'.
# Boolean options such as 'no-igd' are specified as 'no-igd=1'.
# See 'wownerod --help' for all available options.
data-dir=/var/lib/wownero
log-file=/var/log/wownero/wownero.log
log-level=0

View File

@@ -1,38 +1,17 @@
[Unit]
Description=Wownero Full Node
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
User=wownero
Group=wownero
WorkingDirectory=~
RuntimeDirectory=wownero
Environment="MONERO_RANDOMX_UMASK=1"
StateDirectory=wownero
LogsDirectory=wownero
# Clearnet config
#
Type=forking
PIDFile=/run/wownero/wownerod.pid
ExecStart=/usr/bin/wownerod --config-file /etc/wownerod.conf \
--detach --pidfile /run/wownero/wownerod.pid
# Tor config
#
## We have to use simple, not forking, because we cannot pass --detach
## because stderr/stdout is not available when detached, but torsocks
## attempts to write to it, and fails with 'invalid argument', causing
## wownerod to fail.
#Type=simple
#Environment=DNS_PUBLIC=tcp
## The following is needed only when accessing wallet from a different
## host in the LAN, VPN, etc, the RPC must bind to 0.0.0.0, but
## by default torsocks only allows binding to localhost.
#Environment=TORSOCKS_ALLOW_INBOUND=1
#ExecStart=/usr/bin/torsocks /usr/bin/wownerod --config-file /etc/wownerod.conf \
# --non-interactive
Type=simple
ExecStart=/usr/local/bin/wownerod --config-file /etc/wownerod.conf --non-interactive
Restart=always
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target

28
wownerod.conf Normal file
View File

@@ -0,0 +1,28 @@
#anonymous-inbound=YOUR_ONION_ADDRESS:34566,127.0.0.1:34566,64
check-updates=disabled
log-level=0
no-igd=1
no-zmq=1
restricted-rpc=1
p2p-bind-ip=0.0.0.0
p2p-bind-port=34567
public-node=1
confirm-external-bind=1
rpc-bind-ip=0.0.0.0
rpc-bind-port=34568
rpc-ssl=autodetect
disable-rpc-ban=1
db-sync-mode=safe
out-peers=64
in-peers=64
limit-rate-up=1048576
limit-rate-down=1048576
tx-proxy=tor,127.0.0.1:9050,23
add-priority-node=v2admi6gbeprxnk6i2oscizhgy4v5ixu6iezkhj5udiwbfjjs2w7dnid.onion:34568
add-priority-node=iy6ry6uudpzvbd72zsipepukp6nsazjdu72n52vg3isfnxqn342flzad.onion:34568
add-priority-node=7ftpbpp6rbgqi5kjmhyin46essnh3eqb3m3rhfi7r2fr33iwkeuer3yd.onion:34568
add-priority-node=j7rf2jcccizcp47y5moehguyuqdpg4lusk642sw4nayuruitqaqbc7ad.onion:34568
add-priority-node=aje53o5z5twne5q2ljw44zkahhsuhjtwaxuburxddbf7n4pfsj4rj6qd.onion:34568
add-priority-node=nepc4lxndsooj2akn7ofrj3ooqc25242obchcag6tw3f2mxrms2uuvyd.onion:34568
add-priority-node=666l2ajxqjgj5lskvbokvworjysgvqag4oitokjuy7wz6juisul4jqad.onion:34568
add-priority-node=ty7ppqozzodz75audgvkprekiiqsovbyrkfdjwadrkbe3etyzloatxad.onion:34568