mirror of
https://codeberg.org/nahuhh/wownero
synced 2026-03-04 21:57:40 -05:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bdd70d65d | ||
|
|
4b24a52ecd | ||
|
|
0dba26ab80 | ||
|
|
47c13b50b9 | ||
|
|
ab30fb2ebe | ||
|
|
0a6ad9686f | ||
|
|
9da6e41b98 | ||
|
|
dd88245898 | ||
|
|
57fdbe2902 | ||
|
|
cdb068cd0b | ||
|
|
4bb004d488 | ||
|
|
2135d96ce5 | ||
|
|
f2700d8a8c | ||
|
|
06a8561506 | ||
|
|
5fc33d80b7 | ||
|
|
dfeafb77b9 | ||
|
|
fb21f2748b | ||
|
|
38551fff2d | ||
|
|
78e3ea51d6 | ||
|
|
bad59c1225 | ||
|
|
a17acc1dd8 | ||
|
|
f50bd0c801 | ||
|
|
c498f72c0f | ||
|
|
a92df99e55 | ||
|
|
9b66a396a6 | ||
|
|
942e3abe96 | ||
|
|
047c0a3c23 | ||
|
|
74fbd76b91 | ||
|
|
adf438d0fd | ||
|
|
783803b5cf | ||
|
|
e5e56aafb7 | ||
|
|
ff5182f7f2 | ||
|
|
a5b93c8414 | ||
|
|
0d751b9be7 | ||
|
|
76c875f248 | ||
|
|
dc1821ab0e | ||
|
|
e31e8cd9f0 | ||
|
|
f34e643c18 | ||
|
|
39e16ffcf2 | ||
|
|
f5917eabe4 | ||
|
|
3121980b17 | ||
|
|
cebe0ef944 | ||
|
|
b6a21de70b |
8
.gitmodules
vendored
8
.gitmodules
vendored
@@ -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
|
||||
@@ -16,3 +12,7 @@
|
||||
path = external/RandomWOW
|
||||
url = https://git.wownero.com/wownero/RandomWOW
|
||||
branch = 1.1.9-wow
|
||||
[submodule "external/unbound"]
|
||||
path = external/unbound
|
||||
url = https://github.com/monero-project/unbound
|
||||
branch = monero
|
||||
|
||||
41
README.md
41
README.md
@@ -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.1 | 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.3 | 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).
|
||||
|
||||
@@ -42,19 +42,12 @@
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if (CCACHE_FOUND)
|
||||
# Try to compile a test program with ccache, in order to verify if it really works. (needed on exotic setups)
|
||||
set(TEST_PROJECT "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeTmp")
|
||||
file(WRITE "${TEST_PROJECT}/CMakeLists.txt" [=[
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(test)
|
||||
option (CCACHE "")
|
||||
file(WRITE "${CMAKE_SOURCE_DIR}/test.cpp" "int main() { return 0; }")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE}")
|
||||
add_executable(test test.cpp)
|
||||
]=])
|
||||
try_compile(RET "${TEST_PROJECT}/build" "${TEST_PROJECT}" "test" CMAKE_FLAGS -DCCACHE="${CCACHE_FOUND}")
|
||||
unset(TEST_PROJECT)
|
||||
if (${RET})
|
||||
# Create a temporary file with a simple program.
|
||||
set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp")
|
||||
file(WRITE "${TEMP_CPP_FILE}" "int main() { return 0; }")
|
||||
# And run the found ccache on it.
|
||||
execute_process(COMMAND "${CCACHE_FOUND}" "${CMAKE_CXX_COMPILER}" "${TEMP_CPP_FILE}" RESULT_VARIABLE RET)
|
||||
if (${RET} EQUAL 0)
|
||||
# Success
|
||||
message(STATUS "Found usable ccache: ${CCACHE_FOUND}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
|
||||
|
||||
@@ -24,6 +24,7 @@ SET(Readline_INCLUDE_DIR @prefix@/include)
|
||||
SET(Readline_LIBRARY @prefix@/lib/libreadline.a)
|
||||
SET(Terminfo_LIBRARY @prefix@/lib/libtinfo.a)
|
||||
|
||||
|
||||
SET(LRELEASE_PATH @prefix@/native/bin CACHE FILEPATH "path to lrelease" FORCE)
|
||||
|
||||
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
|
||||
@@ -49,7 +49,7 @@ files: []
|
||||
script: |
|
||||
|
||||
WRAP_DIR=$HOME/wrapped
|
||||
HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu i686-linux-gnu"
|
||||
HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu"
|
||||
FAKETIME_HOST_PROGS=""
|
||||
FAKETIME_PROGS="date"
|
||||
HOST_CFLAGS="-O2 -g"
|
||||
|
||||
@@ -23,12 +23,6 @@ packages:
|
||||
- "rename"
|
||||
- "cmake"
|
||||
alternatives:
|
||||
-
|
||||
package: "i686-w64-mingw32-g++"
|
||||
path: "/usr/bin/i686-w64-mingw32-g++-posix"
|
||||
-
|
||||
package: "i686-w64-mingw32-gcc"
|
||||
path: "/usr/bin/i686-w64-mingw32-gcc-posix"
|
||||
-
|
||||
package: "x86_64-w64-mingw32-g++"
|
||||
path: "/usr/bin/x86_64-w64-mingw32-g++-posix"
|
||||
@@ -41,7 +35,7 @@ remotes:
|
||||
files: []
|
||||
script: |
|
||||
WRAP_DIR=$HOME/wrapped
|
||||
HOSTS="i686-w64-mingw32 x86_64-w64-mingw32"
|
||||
HOSTS="x86_64-w64-mingw32"
|
||||
FAKETIME_HOST_PROGS="windres objcopy"
|
||||
FAKETIME_PROGS="date zip"
|
||||
HOST_CFLAGS="-O2 -g"
|
||||
|
||||
@@ -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`
|
||||
|
||||
Binary file not shown.
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)});
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -680,7 +680,7 @@ namespace nodetool
|
||||
if (m_nettype == cryptonote::TESTNET)
|
||||
{
|
||||
full_addrs.insert("207.254.29.107:11180");
|
||||
full_addrs.insert("51.81.32.130:11180");
|
||||
full_addrs.insert("135.148.138.255:11180");
|
||||
}
|
||||
else if (m_nettype == cryptonote::STAGENET)
|
||||
{
|
||||
@@ -695,8 +695,10 @@ 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
|
||||
full_addrs.insert("135.148.138.255:34567");
|
||||
full_addrs.insert("207.254.29.107:34567");
|
||||
}
|
||||
return full_addrs;
|
||||
}
|
||||
@@ -821,9 +823,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 +838,6 @@ namespace nodetool
|
||||
if (m_nettype == cryptonote::MAINNET)
|
||||
{
|
||||
return {
|
||||
"s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080",
|
||||
"sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080"
|
||||
};
|
||||
}
|
||||
return {};
|
||||
@@ -2044,7 +2049,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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_MONERO_VERSION "0.10.0.1"
|
||||
#define DEF_MONERO_VERSION "0.10.0.3"
|
||||
#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@
|
||||
|
||||
@@ -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
122
src/wallet/api/coins.cpp
Normal 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
34
src/wallet/api/coins.h
Normal 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
|
||||
118
src/wallet/api/coins_info.cpp
Normal file
118
src/wallet/api/coins_info.cpp
Normal 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;
|
||||
67
src/wallet/api/coins_info.h
Normal file
67
src/wallet/api/coins_info.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
47
src/wallet/api/pending_transaction_info.cpp
Normal file
47
src/wallet/api/pending_transaction_info.cpp
Normal 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())});
|
||||
// }
|
||||
}
|
||||
37
src/wallet/api/pending_transaction_info.h
Normal file
37
src/wallet/api/pending_transaction_info.h
Normal 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
|
||||
@@ -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})));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
63
src/wallet/api/transaction_construction_info.cpp
Normal file
63
src/wallet/api/transaction_construction_info.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
32
src/wallet/api/transaction_construction_info.h
Normal file
32
src/wallet/api/transaction_construction_info.h
Normal 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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
28
wownerod.conf
Normal 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
|
||||
Reference in New Issue
Block a user