mirror of
https://github.com/monero-project/monero.git
synced 2025-12-23 07:29:11 -08:00
Compare commits
481 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b97a2f72db | ||
|
|
183d3657f3 | ||
|
|
b2adfa8c51 | ||
|
|
95b9e85e2d | ||
|
|
b1bdb4e529 | ||
|
|
2f2c6460ae | ||
|
|
c03da2b2dd | ||
|
|
c2a9229310 | ||
|
|
9d19e62fa2 | ||
|
|
dd144b14bc | ||
|
|
0fb5dc870d | ||
|
|
4299bdf614 | ||
|
|
9d906159c3 | ||
|
|
655eafd160 | ||
|
|
117194a397 | ||
|
|
39a9db9eb1 | ||
|
|
1a286061ff | ||
|
|
3b4539ee7e | ||
|
|
5b7f1fc8e4 | ||
|
|
aa7a926681 | ||
|
|
7e324b7ad7 | ||
|
|
84d3107600 | ||
|
|
67844f826e | ||
|
|
7141d317df | ||
|
|
5df92877c7 | ||
|
|
66dc23c458 | ||
|
|
81c6bb9a40 | ||
|
|
c5c45ca660 | ||
|
|
aeb13289bb | ||
|
|
19585d4914 | ||
|
|
f6fcf0ef26 | ||
|
|
2d0fbaf35b | ||
|
|
930aceb242 | ||
|
|
0f99423080 | ||
|
|
99f725cbe2 | ||
|
|
9b00d80f85 | ||
|
|
f4a3ce15c1 | ||
|
|
b9c5f29d1d | ||
|
|
dfbb85b6fe | ||
|
|
12b59460c2 | ||
|
|
8e1a8c6adc | ||
|
|
e6b05ed95a | ||
|
|
22e16e88e3 | ||
|
|
f9503d2789 | ||
|
|
9907fc689c | ||
|
|
0b91d82574 | ||
|
|
3b00527500 | ||
|
|
2f1732a7e5 | ||
|
|
6c44f5c6eb | ||
|
|
648ea6bef1 | ||
|
|
18462aa065 | ||
|
|
d1a75754df | ||
|
|
46a0dcc1d2 | ||
|
|
76958fc75a | ||
|
|
45bb393577 | ||
|
|
cc73d5000f | ||
|
|
b500a64524 | ||
|
|
f2ea2afb77 | ||
|
|
8086379680 | ||
|
|
4a0be41dfe | ||
|
|
d59dc59744 | ||
|
|
daf5dbebb0 | ||
|
|
416f7fbd5f | ||
|
|
98150be7d8 | ||
|
|
977dd9b76c | ||
|
|
836c748366 | ||
|
|
2fd43e25ee | ||
|
|
3c05aeda1b | ||
|
|
42d07e865f | ||
|
|
3d533d1037 | ||
|
|
fe89782512 | ||
|
|
35e5909a10 | ||
|
|
6e3a96bc4a | ||
|
|
60633cf674 | ||
|
|
bdd3fb85d6 | ||
|
|
73ac3b8e26 | ||
|
|
f4772bae81 | ||
|
|
3f7d6fb57d | ||
|
|
7c0dd5e46c | ||
|
|
59443bf9df | ||
|
|
4adde0423b | ||
|
|
204b1bff62 | ||
|
|
0e18f46522 | ||
|
|
c96f9b0255 | ||
|
|
bef51e677e | ||
|
|
3465c4ebc7 | ||
|
|
fcd178ef33 | ||
|
|
8f6ec90c83 | ||
|
|
5783dd8c99 | ||
|
|
82ba2108e9 | ||
|
|
d9001b43ac | ||
|
|
8b0e04cb12 | ||
|
|
c3527dafd5 | ||
|
|
0059218908 | ||
|
|
657a70e004 | ||
|
|
d6086f5b4e | ||
|
|
91ffb61c25 | ||
|
|
c36cb54340 | ||
|
|
4248d5131c | ||
|
|
2497a2d547 | ||
|
|
7f7d7cab5d | ||
|
|
b1a5d4bd5d | ||
|
|
ce8a2315cf | ||
|
|
694efaaf28 | ||
|
|
3fa1b6623a | ||
|
|
a26b27f66e | ||
|
|
25369df4d8 | ||
|
|
f801dc8567 | ||
|
|
52175502de | ||
|
|
570acdc686 | ||
|
|
2121f3b2f0 | ||
|
|
d094c45822 | ||
|
|
17b6bd6d35 | ||
|
|
8dadf02c4f | ||
|
|
6d76072612 | ||
|
|
92dea04929 | ||
|
|
f025198f19 | ||
|
|
1d9e223944 | ||
|
|
f6660e1851 | ||
|
|
e227d6e7ac | ||
|
|
2c0173c722 | ||
|
|
e05907b3e7 | ||
|
|
1df0fc719e | ||
|
|
67e910a1a0 | ||
|
|
ab7b56e0e2 | ||
|
|
73e8a76d86 | ||
|
|
7abfc5474c | ||
|
|
5fc36f981c | ||
|
|
69b188c4b2 | ||
|
|
fd181b03bb | ||
|
|
452aeca5cd | ||
|
|
d01f5c7f1f | ||
|
|
e6264a2c35 | ||
|
|
dbf2ab56c5 | ||
|
|
5df6f0be80 | ||
|
|
2988e1be8c | ||
|
|
e2816fefc5 | ||
|
|
b7b54b6cff | ||
|
|
9e3cedce87 | ||
|
|
4eb7347fdd | ||
|
|
a0131c8be3 | ||
|
|
f8066116dd | ||
|
|
5fe363cd22 | ||
|
|
11ae1873f8 | ||
|
|
072d646a45 | ||
|
|
23d80b15fd | ||
|
|
d72376d467 | ||
|
|
47413a5626 | ||
|
|
14cb088300 | ||
|
|
a99ab49dd5 | ||
|
|
18772a3ba9 | ||
|
|
bd4da18525 | ||
|
|
d48f2e9bc6 | ||
|
|
9363b2ac19 | ||
|
|
56c4514486 | ||
|
|
265e4605ec | ||
|
|
4fca34ddb4 | ||
|
|
e1dd15b050 | ||
|
|
eb6d66e4fc | ||
|
|
41b2886795 | ||
|
|
696fcba2a0 | ||
|
|
fd4342097a | ||
|
|
300cb7b27b | ||
|
|
70d4915980 | ||
|
|
cd929b89b0 | ||
|
|
77e5bec0ab | ||
|
|
65528aef4e | ||
|
|
2078cb6f2f | ||
|
|
6a2bb62827 | ||
|
|
524ff61ad5 | ||
|
|
797fbbca2b | ||
|
|
a3cd7230f8 | ||
|
|
3fd13080b7 | ||
|
|
0e0bf432a4 | ||
|
|
5f568533aa | ||
|
|
0e418d2a58 | ||
|
|
358e068e87 | ||
|
|
c27c0feb3d | ||
|
|
1669621937 | ||
|
|
d61bd8187e | ||
|
|
9150a16ed1 | ||
|
|
63772e4048 | ||
|
|
38727f7d2f | ||
|
|
7931cb19ef | ||
|
|
dc5e0e45cd | ||
|
|
56c594a8fe | ||
|
|
06ca304b06 | ||
|
|
144a7f090a | ||
|
|
acf908c834 | ||
|
|
5c4cb96cfb | ||
|
|
c441a61ef6 | ||
|
|
4dcb74f97f | ||
|
|
e8a55db29d | ||
|
|
18fdd8116e | ||
|
|
7c7a6cf2f8 | ||
|
|
96e0138ebf | ||
|
|
35da3cb074 | ||
|
|
c57ce06a97 | ||
|
|
af2ceb29fa | ||
|
|
c05cecf036 | ||
|
|
3bd0456144 | ||
|
|
dce47d52af | ||
|
|
6523694581 | ||
|
|
4c44d896d3 | ||
|
|
04003fe8e2 | ||
|
|
0fa6cbef3f | ||
|
|
40a68e22fa | ||
|
|
0c530de057 | ||
|
|
8aba0d4b4c | ||
|
|
c80f4d416d | ||
|
|
63fe6fd9ba | ||
|
|
bc9b498598 | ||
|
|
9d9ab38fcd | ||
|
|
eb194925ec | ||
|
|
97288a5ce2 | ||
|
|
af8a2600aa | ||
|
|
1372f255af | ||
|
|
6f7f21f4e9 | ||
|
|
e59caf87d3 | ||
|
|
64094e5f4e | ||
|
|
b5d6faada3 | ||
|
|
d51f1af75f | ||
|
|
a970a4e3cf | ||
|
|
b06c1abaa6 | ||
|
|
6f85b20d92 | ||
|
|
f189fe51ac | ||
|
|
d53bc2eddf | ||
|
|
95e0010fbb | ||
|
|
77284c026f | ||
|
|
1e153c2fc6 | ||
|
|
703999b21a | ||
|
|
7edf76f92a | ||
|
|
6711b982e7 | ||
|
|
b57d1e1efb | ||
|
|
38dc0bf497 | ||
|
|
4869db702a | ||
|
|
18f66f44ef | ||
|
|
e6deb8abda | ||
|
|
82dbba10d4 | ||
|
|
f5ccfa4001 | ||
|
|
3c2cad2d46 | ||
|
|
bb560dd814 | ||
|
|
43ec2d002a | ||
|
|
7e6d3cf441 | ||
|
|
1f9e6a46d8 | ||
|
|
4bfb81a7f5 | ||
|
|
f71b06770b | ||
|
|
48b57d813c | ||
|
|
ffd8c41f36 | ||
|
|
836669d276 | ||
|
|
83b0511731 | ||
|
|
1710a7dbc2 | ||
|
|
726e8e7676 | ||
|
|
2746cceeea | ||
|
|
3e43732455 | ||
|
|
6b3b23cc30 | ||
|
|
3365f770dd | ||
|
|
6a303b9a3a | ||
|
|
971f3ae031 | ||
|
|
b9149d4d00 | ||
|
|
fdef09f11c | ||
|
|
145d0b78ef | ||
|
|
54c9400fbe | ||
|
|
d28db2368e | ||
|
|
a269f03e5d | ||
|
|
56b07f7b89 | ||
|
|
069d688cf7 | ||
|
|
31abac4daf | ||
|
|
092f7c528d | ||
|
|
eb4ecd442d | ||
|
|
18e406a0e6 | ||
|
|
30946700a3 | ||
|
|
6fa35e3539 | ||
|
|
2f4f6c7c26 | ||
|
|
6a2157b610 | ||
|
|
a0975e59ed | ||
|
|
ff8825210d | ||
|
|
854abeb3bb | ||
|
|
4e98d2958c | ||
|
|
31ceb830e5 | ||
|
|
13187379cc | ||
|
|
92095104fe | ||
|
|
839280d5fc | ||
|
|
59f0d4b574 | ||
|
|
10a79eae24 | ||
|
|
1e163666f3 | ||
|
|
c93c1ad0e5 | ||
|
|
4f6ea2eb6a | ||
|
|
b3d4505ae1 | ||
|
|
09f62ed33e | ||
|
|
f800390ccc | ||
|
|
7c5431624e | ||
|
|
b9f31bbc10 | ||
|
|
7426b5374f | ||
|
|
9feb358e46 | ||
|
|
e48ef1684c | ||
|
|
2bb0bdc8b8 | ||
|
|
af2b1ec606 | ||
|
|
b53c9e5549 | ||
|
|
f3c374fe08 | ||
|
|
372f338682 | ||
|
|
12d861694d | ||
|
|
0b93dd39db | ||
|
|
4fd56a52bc | ||
|
|
d63fabdc62 | ||
|
|
0a41b03fc7 | ||
|
|
bfc1de7aa2 | ||
|
|
06b642dfe4 | ||
|
|
b6b86ab347 | ||
|
|
2bf65dfb8d | ||
|
|
a3748f40ea | ||
|
|
04da979f46 | ||
|
|
8231997b66 | ||
|
|
985f61a4ec | ||
|
|
88faec75fe | ||
|
|
0950be9e34 | ||
|
|
0eba1335be | ||
|
|
5e10fb042d | ||
|
|
094f4c8cc6 | ||
|
|
e76dcdd810 | ||
|
|
2d7083ca56 | ||
|
|
b5f20012d3 | ||
|
|
3429bfb71d | ||
|
|
e06a4daf33 | ||
|
|
afc70df7ea | ||
|
|
9ebf7b6dcf | ||
|
|
1fe75c1ea7 | ||
|
|
ab002a1d97 | ||
|
|
a6bc1103fd | ||
|
|
9c73128835 | ||
|
|
34fcfcd7cc | ||
|
|
3db0ebafe5 | ||
|
|
9ea25cc866 | ||
|
|
eeb7ecfd81 | ||
|
|
7db29d6903 | ||
|
|
dd6c44327b | ||
|
|
e95d3f359b | ||
|
|
4038e86527 | ||
|
|
74dfdb0b30 | ||
|
|
412da63622 | ||
|
|
304c087dd0 | ||
|
|
a8cd65646c | ||
|
|
0673db16ad | ||
|
|
fe43461c2b | ||
|
|
8cd01bc378 | ||
|
|
0589209eb4 | ||
|
|
3126ba7425 | ||
|
|
d8eae67ef2 | ||
|
|
3cb2436528 | ||
|
|
1eaa3e8040 | ||
|
|
36a89ab435 | ||
|
|
9798bde11e | ||
|
|
b9c8c0db06 | ||
|
|
9f31e2d8c0 | ||
|
|
ea95b22009 | ||
|
|
697ce1d435 | ||
|
|
a4390dae07 | ||
|
|
62b3708ea5 | ||
|
|
11fab41c36 | ||
|
|
559f379327 | ||
|
|
8b0cb8caa4 | ||
|
|
db3282cdf0 | ||
|
|
85f5e73d9c | ||
|
|
bb9094f1fe | ||
|
|
2f5196937b | ||
|
|
4e6d70808d | ||
|
|
2a0ad8b2fe | ||
|
|
80c5de9fa0 | ||
|
|
79bb5a670a | ||
|
|
ae987907c6 | ||
|
|
a8e03344e5 | ||
|
|
bd43d8add2 | ||
|
|
07c5907c32 | ||
|
|
2723cd12e1 | ||
|
|
e72b6a7ade | ||
|
|
ab60c0503c | ||
|
|
bfdac4b5ff | ||
|
|
4cb1348548 | ||
|
|
d60826c0b9 | ||
|
|
60e527f1c2 | ||
|
|
895d20f901 | ||
|
|
714ee99678 | ||
|
|
e34ef4de6c | ||
|
|
fa1d5efb5a | ||
|
|
1be1e4a47d | ||
|
|
0f3c865a98 | ||
|
|
36d80b4475 | ||
|
|
db90a16f03 | ||
|
|
298a0723e8 | ||
|
|
8a67e3c95e | ||
|
|
2ef81914b5 | ||
|
|
2f683291f4 | ||
|
|
71538f3240 | ||
|
|
10be9036da | ||
|
|
fb1785ab94 | ||
|
|
3644aa94f3 | ||
|
|
b67383055a | ||
|
|
8ed0d72b12 | ||
|
|
65ea8364f8 | ||
|
|
a4044df923 | ||
|
|
6390673137 | ||
|
|
442bfd1600 | ||
|
|
2e20ca9009 | ||
|
|
e57379a819 | ||
|
|
179b1f43af | ||
|
|
1eae90512a | ||
|
|
e5f8642f52 | ||
|
|
ea45d61f5d | ||
|
|
8b20cbfa7d | ||
|
|
80b4da3330 | ||
|
|
baa3e80140 | ||
|
|
10fe626e13 | ||
|
|
0019e3106b | ||
|
|
1f73f80c94 | ||
|
|
8f94fcf6a3 | ||
|
|
63321bbbae | ||
|
|
995dde4f95 | ||
|
|
af831bed5c | ||
|
|
f195a447cc | ||
|
|
0b9888a4ee | ||
|
|
1b23f1b224 | ||
|
|
25be1d3ed4 | ||
|
|
68ac0607da | ||
|
|
7d020bde5e | ||
|
|
d5f918a0b1 | ||
|
|
3451963855 | ||
|
|
e5e6d88655 | ||
|
|
9b8a06203b | ||
|
|
8438fb4ae3 | ||
|
|
4789347b27 | ||
|
|
2dacb193d0 | ||
|
|
25e5efc238 | ||
|
|
a6688200fb | ||
|
|
aef92f27d9 | ||
|
|
15c0882f4e | ||
|
|
a7882da2f6 | ||
|
|
bba6af9064 | ||
|
|
01ec1959c3 | ||
|
|
446ebbcd7b | ||
|
|
bd773e7805 | ||
|
|
7d7f684c9f | ||
|
|
9872dcbbe3 | ||
|
|
d9b0bf9f35 | ||
|
|
98f19d40aa | ||
|
|
cfd71e6bde | ||
|
|
78b13d6dac | ||
|
|
1e6aedba8b | ||
|
|
9e54616924 | ||
|
|
53603163bd | ||
|
|
3627cea34a | ||
|
|
cda4cb969a | ||
|
|
545a48f098 | ||
|
|
3079c5756b | ||
|
|
7b4a85b309 | ||
|
|
9de3ec3e2a | ||
|
|
e01a9ea507 | ||
|
|
cf74a137f3 | ||
|
|
90f818b646 | ||
|
|
2025e8241c | ||
|
|
5a9fa3736b | ||
|
|
179d89f111 | ||
|
|
2a5139644a | ||
|
|
cec090fc8a | ||
|
|
5e3e362c85 | ||
|
|
d2e11f374a | ||
|
|
13258422ba | ||
|
|
8d4674bd85 | ||
|
|
7b09e9ff77 | ||
|
|
8b4e7c6c9c | ||
|
|
0d036bec26 | ||
|
|
2e18e10beb | ||
|
|
fc855c1a21 | ||
|
|
69c9824fc0 | ||
|
|
1f8a70c03a | ||
|
|
12427dd8d3 | ||
|
|
344e96cc08 | ||
|
|
d5d0856ce6 | ||
|
|
cdb6c96f89 | ||
|
|
b73bed2992 | ||
|
|
7f009bb7e2 | ||
|
|
b8fb9d1919 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -103,3 +103,4 @@ local.properties
|
||||
.texlipse
|
||||
.idea/
|
||||
|
||||
/testnet
|
||||
120
.travis.yml
120
.travis.yml
@@ -1,120 +0,0 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: cpp
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
#
|
||||
# Coveralls.io
|
||||
#
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
- cmake
|
||||
- doxygen
|
||||
- g++
|
||||
- gcc
|
||||
- clang
|
||||
- graphviz
|
||||
- libdb++-dev
|
||||
- libdb-dev
|
||||
- libgtest-dev
|
||||
- libminiupnpc-dev
|
||||
- libssl-dev
|
||||
- libssl1.0.0
|
||||
- libunbound-dev
|
||||
- libunwind8-dev
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:kojoley/boost
|
||||
- sudo apt-get -q update
|
||||
- pip install --user cpp-coveralls
|
||||
install:
|
||||
- sudo apt-get -y install libboost-{chrono,program-options,date-time,thread,system,filesystem,regex,serialization}1.58{-dev,.0}
|
||||
env:
|
||||
# exclude long-running and failing tests (#895)
|
||||
- ARGS=" -E 'coretests|libwallet_api_tests' "
|
||||
script:
|
||||
- make -j2 coverage
|
||||
after_success:
|
||||
- travis_wait coveralls -e external -e tests -e cmake -e contrib -e translations -e utils --gcov-options '\-lp' &> /dev/null
|
||||
|
||||
#
|
||||
# Monero release-all (gcc)
|
||||
#
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
- cmake
|
||||
- doxygen
|
||||
- g++
|
||||
- gcc
|
||||
- clang
|
||||
- graphviz
|
||||
- libdb++-dev
|
||||
- libdb-dev
|
||||
- libgtest-dev
|
||||
- libminiupnpc-dev
|
||||
- libssl-dev
|
||||
- libssl1.0.0
|
||||
- libunbound-dev
|
||||
- libunwind8-dev
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:kojoley/boost
|
||||
- sudo apt-get -q update
|
||||
install:
|
||||
- sudo apt-get -y install libboost-{chrono,program-options,date-time,thread,system,filesystem,regex,serialization}1.58{-dev,.0}
|
||||
script:
|
||||
- make -j2 && HAVE_DOT=YES doxygen Doxyfile
|
||||
|
||||
#
|
||||
# Monero release-all (clang)
|
||||
#
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- build-essential
|
||||
- cmake
|
||||
- doxygen
|
||||
- clang
|
||||
- graphviz
|
||||
- libdb++-dev
|
||||
- libdb-dev
|
||||
- libgtest-dev
|
||||
- libminiupnpc-dev
|
||||
- libssl-dev
|
||||
- libssl1.0.0
|
||||
- libunbound-dev
|
||||
- libunwind8-dev
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:kojoley/boost
|
||||
- sudo apt-get -q update
|
||||
install:
|
||||
- sudo apt-get -y install libboost-{chrono,program-options,date-time,thread,system,filesystem,regex,serialization}1.58{-dev,.0}
|
||||
script:
|
||||
- make -j2 && HAVE_DOT=YES doxygen Doxyfile
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
on_success: change
|
||||
on_failure: change
|
||||
channels:
|
||||
- "chat.freenode.net#monero-bots"
|
||||
nick: monero
|
||||
template:
|
||||
- "%{result} | %{repository}#%{build_number} (%{commit} : %{author}) | Build details : %{build_url}"
|
||||
@@ -65,10 +65,10 @@ else()
|
||||
set(ARCH_ID "${ARCH}")
|
||||
endif()
|
||||
string(TOLOWER "${ARCH_ID}" ARM_ID)
|
||||
string(SUBSTRING "${ARCH_ID}" 0 3 ARM_TEST)
|
||||
string(SUBSTRING "${ARM_ID}" 0 3 ARM_TEST)
|
||||
if (ARM_TEST STREQUAL "arm")
|
||||
set(ARM 1)
|
||||
string(SUBSTRING "${ARCH_ID}" 0 5 ARM_TEST)
|
||||
string(SUBSTRING "${ARM_ID}" 0 5 ARM_TEST)
|
||||
if (ARM_TEST STREQUAL "armv6")
|
||||
set(ARM6 1)
|
||||
endif()
|
||||
@@ -77,7 +77,7 @@ if (ARM_TEST STREQUAL "arm")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ARCH_ID STREQUAL "aarch64")
|
||||
if (ARM_ID STREQUAL "aarch64")
|
||||
set(ARM 1)
|
||||
set(ARM8 1)
|
||||
endif()
|
||||
@@ -182,10 +182,11 @@ option(STATIC "Link libraries statically" ${DEFAULT_STATIC})
|
||||
|
||||
# This is a CMake built-in switch that concerns internal libraries
|
||||
if (NOT DEFINED BUILD_SHARED_LIBS AND NOT STATIC AND CMAKE_BUILD_TYPE_LOWER STREQUAL "debug")
|
||||
set(BUILD_SHARED_LIBS ON CACHE STRING "Build internal libs as shared")
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
message(STATUS "Building internal libraries as shared")
|
||||
message(STATUS "Building internal libraries with position independent code")
|
||||
set(PIC_FLAG "-fPIC")
|
||||
else()
|
||||
message(STATUS "Building internal libraries as static")
|
||||
@@ -378,9 +379,6 @@ else()
|
||||
set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage --coverage")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
|
||||
|
||||
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
|
||||
# is fixed in the code (Issue #847), force compiler to be conservative.
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
|
||||
@@ -408,8 +406,8 @@ else()
|
||||
message(STATUS "AES support disabled")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
|
||||
|
||||
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
|
||||
# is fixed in the code (Issue #847), force compiler to be conservative.
|
||||
@@ -512,11 +510,6 @@ else()
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled, so explicitly disable
|
||||
set(USE_LTO false)
|
||||
# explicitly define stdlib for older versions of clang
|
||||
if(CMAKE_C_COMPILER_VERSION VERSION_LESS 3.7)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libstdc++")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -577,6 +570,8 @@ find_package(Boost 1.58 QUIET REQUIRED COMPONENTS system filesystem thread date_
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES})
|
||||
if(NOT Boost_FOUND)
|
||||
die("Could not find Boost libraries, please make sure you have installed Boost or libboost-all-dev (1.58) or the equivalent")
|
||||
elseif(Boost_FOUND)
|
||||
message(STATUS "Found Boost Version: ${Boost_VERSION}")
|
||||
endif()
|
||||
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
|
||||
36
CONTRIBUTING
Normal file
36
CONTRIBUTING
Normal file
@@ -0,0 +1,36 @@
|
||||
A good way to help is to test, and report bugs.
|
||||
See http://www.chiark.greenend.org.uk/~sgtatham/bugs.html if you
|
||||
want to help that way. Testing is invaluable in making a piece
|
||||
of software solid and usable.
|
||||
|
||||
Patches are preferably to be sent via a github pull request. If that
|
||||
can't be done, patches in "git format-patch" format can be sent
|
||||
(eg, posted to fpaste.org with a long enough timeout and a link
|
||||
posted to #monero-dev on irc.freenode.net).
|
||||
|
||||
Patches should be self contained. A good rule of thumb is to have
|
||||
one patch per separate issue, feature, or logical change. Also, no
|
||||
other changes, such as random whitespace changes or reindentation.
|
||||
Following the code style of the particular chunk of code you're
|
||||
modifying is encourgaged. Proper squashing should be done (eg, if
|
||||
you're making a buggy patch, then a later patch to fix the bug,
|
||||
both patches should be merged).
|
||||
|
||||
Commit messages should be sensible. That means a subject line that
|
||||
describes the patch, with an optional longer body that gives details,
|
||||
documentation, etc.
|
||||
|
||||
Comments are encouraged.
|
||||
|
||||
If modifying code for which Doxygen headers exist, that header must
|
||||
be modified to match.
|
||||
|
||||
When submitting a pull request on github, make sure your branch is
|
||||
rebased. No merge commits nor stray commits from other people in
|
||||
your submitted branch, please. You may be asked to rebase if there
|
||||
are conflicts (even trivially resolvable ones).
|
||||
|
||||
PGP signing commits is strongly encouraged. That should explain why
|
||||
the previous paragraph is here.
|
||||
|
||||
Tests would be nice to have if you're adding functionality.
|
||||
2
Doxyfile
2
Doxyfile
@@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
|
||||
# title of most generated pages and in a few other places.
|
||||
# The default value is: My Project.
|
||||
|
||||
PROJECT_NAME = "Bitmonero"
|
||||
PROJECT_NAME = "Monero"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
|
||||
4
Makefile
4
Makefile
@@ -62,11 +62,11 @@ coverage:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON ../.. && $(MAKE) && $(MAKE) test
|
||||
|
||||
release-static-arm6:
|
||||
release-static-armv6:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
|
||||
release-static-arm7:
|
||||
release-static-armv7:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ To edit translations for Spanish:
|
||||
|
||||
linguist translations/monero_es.ts
|
||||
|
||||
To build translations after modiying them:
|
||||
To build translations after modifying them:
|
||||
|
||||
./utils/translations/build-translations.sh
|
||||
|
||||
|
||||
129
README.md
129
README.md
@@ -2,16 +2,36 @@
|
||||
|
||||
Copyright (c) 2014-2016, The Monero Project
|
||||
|
||||
[](https://travis-ci.org/monero-project/monero)
|
||||
[](https://coveralls.io/github/monero-project/monero?branch=master)
|
||||
|
||||
## Development Resources
|
||||
|
||||
- Web: [getmonero.org](https://getmonero.org)
|
||||
- Forum: [forum.getmonero.org](https://forum.getmonero.org)
|
||||
- Mail: [dev@getmonero.org](mailto:dev@getmonero.org)
|
||||
- GitHub: [https://github.com/monero-project/monero](https://github.com/monero-project/monero)
|
||||
- IRC: [#monero-dev on Freenode](irc://chat.freenode.net/#monero-dev)
|
||||
- IRC: [#monero-dev on Freenode](http://webchat.freenode.net/?randomnick=1&channels=%23monero-dev&prompt=1&uio=d4)
|
||||
|
||||
## Build
|
||||
|
||||
| Operating System | Processor | Status |
|
||||
| --------------------- | -------- |--------|
|
||||
| Ubuntu 16.04 | i686 | [](https://build.getmonero.org/builders/monero-static-ubuntu-i686)
|
||||
| Ubuntu 16.04 | amd64 | [](https://build.getmonero.org/builders/monero-static-ubuntu-amd64)
|
||||
| Ubuntu 16.04 | armv7 | [](https://build.getmonero.org/builders/monero-static-ubuntu-arm7)
|
||||
| Debian Stable | armv8 | [](https://build.getmonero.org/builders/monero-static-debian-armv8)
|
||||
| OSX 10.10 | amd64 | [](https://build.getmonero.org/builders/monero-static-osx-10.10)
|
||||
| OSX 10.11 | amd64 | [](https://build.getmonero.org/builders/monero-static-osx-10.11)
|
||||
| OSX 10.12 | amd64 | [](https://build.getmonero.org/builders/monero-static-osx-10.12)
|
||||
| FreeBSD 10.3 | amd64 | [](https://build.getmonero.org/builders/monero-static-freebsd64)
|
||||
| Windows (MSYS2/MinGW) | i686 | [](https://build.getmonero.org/builders/monero-static-win32)
|
||||
| Windows (MSYS2/MinGW) | amd64 | [](https://build.getmonero.org/builders/monero-static-win64)
|
||||
|
||||
## Coverage
|
||||
|
||||
| Type | Status |
|
||||
|-----------|--------|
|
||||
| Coverity | [](https://scan.coverity.com/projects/9657/)
|
||||
| Coveralls | [](https://coveralls.io/github/monero-project/monero?branch=master)
|
||||
| License | [](https://opensource.org/licenses/BSD-3-Clause)
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -19,7 +39,7 @@ Monero is a private, secure, untraceable, decentralised digital currency. You ar
|
||||
|
||||
**Privacy:** Monero uses a cryptographically sound system to allow you to send and receive funds without your transactions being easily revealed on the blockchain (the ledger of transactions that everyone has). This ensures that your purchases, receipts, and all transfers remain absolutely private by default.
|
||||
|
||||
**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 24 word mnemonic seed that is only displayed once, and can be written down to backup the wallet. Wallet files are encrypted with a passphrase to ensure they are useless if stolen.
|
||||
**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 25 word mnemonic seed that is only displayed once, and can be written down to backup the wallet. Wallet files are encrypted with a passphrase to ensure they are useless if stolen.
|
||||
|
||||
**Untraceability:** By taking advantage of ring signatures, a special property of a certain type of cryptography, Monero is able to ensure that transactions are not only untraceable, but have an optional measure of ambiguity that ensures that transactions cannot easily be tied back to an individual user or computer.
|
||||
|
||||
@@ -57,6 +77,20 @@ There are also several mining pools that kindly donate a portion of their fees,
|
||||
|
||||
See [LICENSE](LICENSE).
|
||||
|
||||
## Monero software updates and consensus protocol changes (hard forking)
|
||||
|
||||
Monero uses a hardforking mechanism to implement new features which requires that
|
||||
users of Monero software run current versions and update their software on a
|
||||
regular schedule. Here is the current schedule, versions, and compatability.
|
||||
Dates are provided in the format YYYYMMDD.
|
||||
|
||||
|
||||
| Date | Consensus version | Minimum Monero Version | Recommended Monero Version | Details |
|
||||
| ----------------- | ----------------- | ---------------------- | -------------------------- | ------------------ |
|
||||
| 2016-09-21 | v3 | v0.9.4 | v0.10.0 | Splits coinbase into denominations |
|
||||
| 2017-01-05 | v4 | v0.10.1 | v0.10.1 | Allow normal and RingCT transactions |
|
||||
| 2017-09-21 | v5 | v0.10.1 | v0.10.1 | Allow only RingCT transactions |
|
||||
|
||||
## Installing Monero from a Package
|
||||
|
||||
Packages are available for
|
||||
@@ -111,7 +145,7 @@ library archives (`.a`).
|
||||
| Graphviz | any | NO | `graphviz` | `graphviz` | YES | documentation |
|
||||
|
||||
[^] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
|
||||
build the library binary manually.
|
||||
build the library binary manually. This can be done with the following command ```sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libg* /usr/lib/ ```
|
||||
|
||||
### Build instructions
|
||||
|
||||
@@ -131,7 +165,11 @@ invokes cmake commands as needed.
|
||||
this to be worthwhile, the machine should have one core and about 2GB of RAM
|
||||
available per thread.
|
||||
|
||||
* The resulting executables can be found in `build/release/bin`.
|
||||
* The resulting executables can be found in `build/release/bin`
|
||||
|
||||
* Add `PATH="$PATH:$HOME/monero/build/release/bin"` to `.profile`
|
||||
|
||||
* Run Monero with `monerod --detach`
|
||||
|
||||
* **Optional**: build and run the test suite to verify the binaries:
|
||||
|
||||
@@ -151,6 +189,50 @@ invokes cmake commands as needed.
|
||||
|
||||
HAVE_DOT=YES doxygen Doxyfile
|
||||
|
||||
#### On the Raspberry Pi
|
||||
|
||||
Tested on a Raspberry Pi 2 with a clean install of minimal Debian Jessie from https://www.raspberrypi.org/downloads/raspbian/
|
||||
|
||||
* `apt-get update && apt-get upgrade` to install all of the latest software
|
||||
|
||||
* Install the dependencies for Monero except libunwind and libboost-all-dev
|
||||
|
||||
* Increase the system swap size:
|
||||
```
|
||||
sudo /etc/init.d/dphys-swapfile stop
|
||||
sudo nano /etc/dphys-swapfile
|
||||
CONF_SWAPSIZE=1024
|
||||
sudo /etc/init.d/dphys-swapfile start
|
||||
```
|
||||
* Install the latest version of boost (this may first require invoking `apt-get remove --purge libboost*` to remove a previous version if you're not using a clean install):
|
||||
```
|
||||
cd
|
||||
wget https://sourceforge.net/projects/boost/files/boost/1.62.0/boost_1_62_0.tar.bz2
|
||||
tar xvfo boost_1_62_0.tar.bz2
|
||||
cd boost_1_62_0
|
||||
./bootstrap.sh
|
||||
sudo ./b2
|
||||
```
|
||||
* Wait ~8 hours
|
||||
|
||||
sudo ./bjam install
|
||||
|
||||
* Wait ~4 hours
|
||||
|
||||
* Change to the root of the source code directory and build:
|
||||
|
||||
cd monero
|
||||
make release
|
||||
|
||||
* Wait ~4 hours
|
||||
|
||||
* The resulting executables can be found in `build/release/bin`
|
||||
|
||||
* Add `PATH="$PATH:$HOME/monero/build/release/bin"` to `.profile`
|
||||
|
||||
* Run Monero with `monerod --detach`
|
||||
|
||||
* You may wish to reduce the size of the swap file after the build has finished, and delete the boost directory from your home directory
|
||||
|
||||
#### On Windows:
|
||||
|
||||
@@ -164,11 +246,7 @@ application.
|
||||
|
||||
* Download and install the [MSYS2 installer](http://msys2.github.io), either the 64-bit or the 32-bit package, depending on your system.
|
||||
* Open the MSYS shell via the `MSYS2 Shell` shortcut
|
||||
* Update the core packages in your MSYS2 install:
|
||||
|
||||
update-core
|
||||
|
||||
* Exit the MSYS shell using Alt+F4, then restart MSYS and update packages using pacman:
|
||||
* Update packages using pacman:
|
||||
|
||||
pacman -Syuu
|
||||
|
||||
@@ -232,9 +310,9 @@ By default, in either dynamically or statically linked builds, binaries target t
|
||||
|
||||
* ```make release-static-64``` builds binaries on Linux on x86_64 portable across POSIX systems on x86_64 processors
|
||||
* ```make release-static-32``` builds binaries on Linux on x86_64 or i686 portable across POSIX systems on i686 processors
|
||||
* ```make release-static-arm8``` builds binaries on Linux on armv8 portable across POSIX systems on armv8 processors
|
||||
* ```make release-static-arm7``` builds binaries on Linux on armv7 portable across POSIX systems on armv7 processors
|
||||
* ```make release-static-arm6``` builds binaries on Linux on armv7 or armv6 portable across POSIX systems on armv6 processors, such as the Raspberry Pi
|
||||
* ```make release-static-armv8``` builds binaries on Linux portable across POSIX systems on armv8 processors
|
||||
* ```make release-static-armv7``` builds binaries on Linux portable across POSIX systems on armv7 processors
|
||||
* ```make release-static-armv6``` builds binaries on Linux portable across POSIX systems on armv6 processors
|
||||
* ```make release-static-win64``` builds binaries on 64-bit Windows portable across 64-bit Windows systems
|
||||
* ```make release-static-win32``` builds binaries on 64-bit or 32-bit Windows portable across 32-bit Windows systems
|
||||
|
||||
@@ -296,3 +374,24 @@ While monerod and monero-wallet-cli do not use readline directly, most of the fu
|
||||
|
||||
Note: rlwrap will save things like your seed and private keys, if you supply them on prompt. You may want to not use rlwrap when you use simplewallet to restore from seed, etc.
|
||||
|
||||
# Contributing
|
||||
|
||||
If you want to help out, see CONTRIBUTING for a set of guidelines.
|
||||
|
||||
# Debugging
|
||||
|
||||
This section contains general instructions for debugging failed installs or problems encountered with Monero. First ensure you are running the latest version built from the github repo.
|
||||
|
||||
## LMDB
|
||||
|
||||
Instructions for debugging suspected blockchain corruption as per @HYC
|
||||
|
||||
There is an `mdb_stat` command in the LMDB source that can print statistics about the database but it's not routinely built. This can be built with the following command:
|
||||
|
||||
`cd ~/monero/external/db_drivers/liblmdb && make`
|
||||
|
||||
The output of `mdb_stat -ea <path to blockchain dir>` will indicate inconsistencies in the blocks, block_heights and block_info table.
|
||||
|
||||
The output of `mdb_dump -s blocks <path to blockchain dir>` and `mdb_dump -s block_info <path to blockchain dir>` is useful for indicating whether blocks and block_info contain the same keys.
|
||||
|
||||
These records are dumped as hex data, where the first line is the key and the second line is the data.
|
||||
|
||||
@@ -155,6 +155,20 @@ namespace epee
|
||||
else if (0 < retval)
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
while (m_run.load(std::memory_order_relaxed))
|
||||
{
|
||||
int retval = ::WaitForSingleObject(::GetStdHandle(STD_INPUT_HANDLE), 100);
|
||||
switch (retval)
|
||||
{
|
||||
case WAIT_FAILED:
|
||||
return false;
|
||||
case WAIT_OBJECT_0:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
||||
@@ -300,7 +300,6 @@ namespace net_utils
|
||||
boost::thread::id m_main_thread_id;
|
||||
critical_section m_threads_lock;
|
||||
volatile uint32_t m_thread_index; // TODO change to std::atomic
|
||||
void detach_threads();
|
||||
|
||||
t_connection_type m_connection_type;
|
||||
|
||||
|
||||
@@ -727,7 +727,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
m_address = address;
|
||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port));
|
||||
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_.open(endpoint.protocol());
|
||||
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
@@ -827,7 +827,7 @@ POP_WARNINGS
|
||||
}
|
||||
CRITICAL_REGION_END();
|
||||
// Wait for all threads in the pool to exit.
|
||||
if (wait) // && ! ::cryptonote::core::get_is_stopping()) // TODO fast_exit
|
||||
if (wait)
|
||||
{
|
||||
_fact("JOINING all threads");
|
||||
for (std::size_t i = 0; i < m_threads.size(); ++i) {
|
||||
@@ -897,10 +897,6 @@ POP_WARNINGS
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::send_stop_signal()
|
||||
{
|
||||
if (::cryptonote::core::get_fast_exit() == true)
|
||||
{
|
||||
detach_threads();
|
||||
}
|
||||
m_stop_signal_sent = true;
|
||||
TRY_ENTRY();
|
||||
connections_mutex.lock();
|
||||
@@ -974,7 +970,7 @@ POP_WARNINGS
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
@@ -1014,7 +1010,7 @@ POP_WARNINGS
|
||||
boost::unique_lock<boost::mutex> lock(local_shared_context->connect_mut);
|
||||
auto connect_callback = [](boost::system::error_code ec_, boost::shared_ptr<local_async_context> shared_context)
|
||||
{
|
||||
shared_context->connect_mut.lock(); shared_context->ec = ec_; shared_context->connect_mut.unlock(); shared_context->cond.notify_one();
|
||||
shared_context->connect_mut.lock(); shared_context->ec = ec_; shared_context->cond.notify_one(); shared_context->connect_mut.unlock();
|
||||
};
|
||||
|
||||
sock_.async_connect(remote_endpoint, boost::bind<void>(connect_callback, _1, local_shared_context));
|
||||
@@ -1078,7 +1074,7 @@ POP_WARNINGS
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
@@ -1144,14 +1140,6 @@ POP_WARNINGS
|
||||
return true;
|
||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::connect_async", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::detach_threads()
|
||||
{
|
||||
for (auto thread : m_threads)
|
||||
thread->detach();
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
@@ -156,6 +156,17 @@ using namespace std;
|
||||
|
||||
return csTmp;
|
||||
}
|
||||
static inline int get_index(const char *s, char c) { const char *ptr = (const char*)memchr(s, c, 16); return ptr ? ptr-s : -1; }
|
||||
static inline
|
||||
std::string hex_to_dec_2bytes(const char *s)
|
||||
{
|
||||
const char *hex = get_hex_vals();
|
||||
int i0 = get_index(hex, toupper(s[0]));
|
||||
int i1 = get_index(hex, toupper(s[1]));
|
||||
if (i0 < 0 || i1 < 0)
|
||||
return std::string("%") + std::string(1, s[0]) + std::string(1, s[1]);
|
||||
return std::string(1, i0 * 16 | i1);
|
||||
}
|
||||
|
||||
static inline std::string convert(char val)
|
||||
{
|
||||
@@ -180,6 +191,25 @@ using namespace std;
|
||||
|
||||
return result;
|
||||
}
|
||||
static inline std::string convert_from_url_format(const std::string& uri)
|
||||
{
|
||||
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
if(uri[i] == '%' && i + 2 < uri.size())
|
||||
{
|
||||
result += hex_to_dec_2bytes(uri.c_str() + i + 1);
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
result += uri[i];
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline std::string convert_to_url_format_force_all(const std::string& uri)
|
||||
{
|
||||
|
||||
@@ -373,7 +373,7 @@ public:
|
||||
invoke_response_handlers_guard.unlock();
|
||||
|
||||
if(timer_cancelled)
|
||||
response_handler->handle(m_current_head.m_command, buff_to_invoke, m_connection_context);
|
||||
response_handler->handle(m_current_head.m_return_code, buff_to_invoke, m_connection_context);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace net_utils
|
||||
stop_handling = true;
|
||||
return false;
|
||||
default:
|
||||
LOG_ERROR("Error in munin state machine! Unkonwon state=" << m_machine_state);
|
||||
LOG_ERROR("Error in munin state machine! Unknown state=" << m_machine_state);
|
||||
stop_handling = true;
|
||||
m_machine_state = http_state_error;
|
||||
return false;
|
||||
|
||||
@@ -281,7 +281,7 @@ namespace epee
|
||||
|
||||
|
||||
#define END_INVOKE_MAP2() \
|
||||
LOG_ERROR("Unkonown command:" << command); \
|
||||
LOG_ERROR("Unknown command:" << command); \
|
||||
return LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED; \
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <locale>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <type_traits>
|
||||
//#include <strsafe.h>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
@@ -171,6 +172,7 @@ namespace string_tools
|
||||
template<class t_pod_type>
|
||||
bool parse_tpod_from_hex_string(const std::string& str_hash, t_pod_type& t_pod)
|
||||
{
|
||||
static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
|
||||
std::string buf;
|
||||
bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf);
|
||||
if (!res || buf.size() != sizeof(t_pod_type))
|
||||
@@ -570,6 +572,7 @@ POP_WARNINGS
|
||||
template<class t_pod_type>
|
||||
std::string pod_to_hex(const t_pod_type& s)
|
||||
{
|
||||
static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
|
||||
std::string buff;
|
||||
buff.assign(reinterpret_cast<const char*>(&s), sizeof(s));
|
||||
return buff_to_hex_nodelimer(buff);
|
||||
@@ -578,6 +581,7 @@ POP_WARNINGS
|
||||
template<class t_pod_type>
|
||||
bool hex_to_pod(const std::string& hex_str, t_pod_type& s)
|
||||
{
|
||||
static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
|
||||
std::string hex_str_tr = trim(hex_str);
|
||||
if(sizeof(s)*2 != hex_str.size())
|
||||
return false;
|
||||
|
||||
35
contrib/rlwrap/monerocommands_bitmonerod.txt
Normal file
35
contrib/rlwrap/monerocommands_bitmonerod.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
ban
|
||||
bans
|
||||
diff
|
||||
exit
|
||||
flush_txpool
|
||||
hard_fork_info
|
||||
help
|
||||
hide_hr
|
||||
is_key_image_spent
|
||||
limit
|
||||
limit_down
|
||||
limit_up
|
||||
out_peers
|
||||
output_histogram
|
||||
print_bc
|
||||
print_block
|
||||
print_cn
|
||||
print_height
|
||||
print_pl
|
||||
print_pool
|
||||
print_pool_sh
|
||||
print_pool_stats
|
||||
print_status
|
||||
print_tx
|
||||
q
|
||||
save
|
||||
set_log
|
||||
show_hr
|
||||
start_mining
|
||||
start_save_graph
|
||||
status
|
||||
stop_daemon
|
||||
stop_mining
|
||||
stop_save_graph
|
||||
unban
|
||||
33
contrib/rlwrap/monerocommands_monero-wallet-cli.txt
Normal file
33
contrib/rlwrap/monerocommands_monero-wallet-cli.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
address
|
||||
balance
|
||||
bc_height
|
||||
check_tx_key
|
||||
export_key_images
|
||||
get_tx_key
|
||||
get_tx_note
|
||||
help
|
||||
import_key_images
|
||||
incoming_transfers
|
||||
integrated_address
|
||||
payments
|
||||
refresh
|
||||
rescan_bc
|
||||
rescan_spent
|
||||
save
|
||||
save_bc
|
||||
save_watch_only
|
||||
seed
|
||||
set
|
||||
set_tx_note
|
||||
show_transfers
|
||||
sign
|
||||
spendkey
|
||||
start_mining
|
||||
status
|
||||
stop_mining
|
||||
sweep_all
|
||||
sweep_unmixable
|
||||
transfer
|
||||
transfer_original
|
||||
verify
|
||||
viewkey
|
||||
19
contrib/valgrind/monero.supp
Normal file
19
contrib/valgrind/monero.supp
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
libunwind causes spurious report
|
||||
Memcheck:Param
|
||||
msync(start)
|
||||
...
|
||||
obj:/usr/lib64/libunwind.so.*
|
||||
...
|
||||
fun:_ULx86_64_step
|
||||
...
|
||||
}
|
||||
|
||||
{
|
||||
boost unlocks before signalling cond var
|
||||
Helgrind:Misc
|
||||
...
|
||||
fun:pthread_cond_signal@*
|
||||
fun:maybe_unlock_and_signal_one<boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex> >
|
||||
...
|
||||
}
|
||||
2
external/miniupnpc/minihttptestserver.c
vendored
2
external/miniupnpc/minihttptestserver.c
vendored
@@ -517,7 +517,7 @@ int main(int argc, char * * argv) {
|
||||
fprintf(stderr, "unknown command line switch '%s'\n", argv[i]);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "unkown command line argument '%s'\n", argv[i]);
|
||||
fprintf(stderr, "unknown command line argument '%s'\n", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,13 +34,13 @@ if (WIN32 OR STATIC)
|
||||
add_definitions(-DMINIUPNP_STATICLIB)
|
||||
endif ()
|
||||
|
||||
function (bitmonero_private_headers group)
|
||||
function (monero_private_headers group)
|
||||
source_group("${group}\\Private"
|
||||
FILES
|
||||
${ARGN})
|
||||
endfunction ()
|
||||
|
||||
function (bitmonero_install_headers subdir)
|
||||
function (monero_install_headers subdir)
|
||||
install(
|
||||
FILES ${ARGN}
|
||||
DESTINATION "include/${subdir}"
|
||||
@@ -58,7 +58,7 @@ function (enable_stack_trace target)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function (bitmonero_add_executable name)
|
||||
function (monero_add_executable name)
|
||||
source_group("${name}"
|
||||
FILES
|
||||
${ARGN})
|
||||
@@ -77,7 +77,7 @@ function (bitmonero_add_executable name)
|
||||
enable_stack_trace("${name}")
|
||||
endfunction ()
|
||||
|
||||
function (bitmonero_add_library name)
|
||||
function (monero_add_library name)
|
||||
source_group("${name}"
|
||||
FILES
|
||||
${ARGN})
|
||||
|
||||
@@ -53,9 +53,9 @@ if (BERKELEY_DB)
|
||||
)
|
||||
endif()
|
||||
|
||||
bitmonero_private_headers(blockchain_db
|
||||
monero_private_headers(blockchain_db
|
||||
${crypto_private_headers})
|
||||
bitmonero_add_library(blockchain_db
|
||||
monero_add_library(blockchain_db
|
||||
${blockchain_db_sources}
|
||||
${blockchain_db_headers}
|
||||
${blockchain_db_private_headers})
|
||||
|
||||
@@ -1309,10 +1309,11 @@ public:
|
||||
*
|
||||
* @param amounts optional set of amounts to lookup
|
||||
* @param unlocked whether to restrict count to unlocked outputs
|
||||
* @param recent_cutoff timestamp to determine whether an output is recent
|
||||
*
|
||||
* @return a set of amount/instances
|
||||
*/
|
||||
virtual std::map<uint64_t, uint64_t> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked) const = 0;
|
||||
virtual std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const = 0;
|
||||
|
||||
/**
|
||||
* @brief is BlockchainDB in read-only mode?
|
||||
|
||||
@@ -51,12 +51,15 @@ using epee::string_tools::pod_to_hex;
|
||||
namespace
|
||||
{
|
||||
|
||||
#pragma pack(push, 1)
|
||||
// This MUST be identical to output_data_t, without the extra rct data at the end
|
||||
struct pre_rct_output_data_t
|
||||
{
|
||||
crypto::public_key pubkey; //!< the output's public key (for spend verification)
|
||||
uint64_t unlock_time; //!< the output's unlock time (or height)
|
||||
uint64_t height; //!< the height of the block which created the output
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template <typename T>
|
||||
inline void throw0(const T &e)
|
||||
@@ -877,12 +880,11 @@ void BlockchainLMDB::remove_tx_outputs(const uint64_t tx_id, const transaction&
|
||||
throw0(DB_ERROR("tx has outputs, but no output indices found"));
|
||||
}
|
||||
|
||||
bool is_miner_tx = tx.vin.size() == 1 && tx.vin[0].type() == typeid(txin_gen);
|
||||
for (uint64_t i = tx.vout.size(); i > 0; --i)
|
||||
bool is_pseudo_rct = tx.version >= 2 && tx.vin.size() == 1 && tx.vin[0].type() == typeid(txin_gen);
|
||||
for (size_t i = tx.vout.size(); i-- > 0;)
|
||||
{
|
||||
const tx_out tx_output = tx.vout[i-1];
|
||||
uint64_t amount = is_miner_tx && tx.version >= 2 ? 0 : tx_output.amount;
|
||||
remove_output(amount, amount_output_indices[i-1]);
|
||||
uint64_t amount = is_pseudo_rct ? 0 : tx.vout[i].amount;
|
||||
remove_output(amount, amount_output_indices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -903,12 +905,12 @@ void BlockchainLMDB::remove_output(const uint64_t amount, const uint64_t& out_in
|
||||
else if (result)
|
||||
throw0(DB_ERROR(lmdb_error("DB error attempting to get an output", result).c_str()));
|
||||
|
||||
outkey *ok = (outkey *)v.mv_data;
|
||||
const pre_rct_outkey *ok = (const pre_rct_outkey *)v.mv_data;
|
||||
MDB_val_set(otxk, ok->output_id);
|
||||
result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &otxk, MDB_GET_BOTH);
|
||||
if (result == MDB_NOTFOUND)
|
||||
{
|
||||
LOG_PRINT_L0("Unexpected: global output index not found in m_output_txs");
|
||||
throw0(DB_ERROR("Unexpected: global output index not found in m_output_txs"));
|
||||
}
|
||||
else if (result)
|
||||
{
|
||||
@@ -1081,7 +1083,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
|
||||
|
||||
if (need_resize())
|
||||
{
|
||||
LOG_PRINT_L0("LMDB memory map needs resized, doing that now.");
|
||||
LOG_PRINT_L0("LMDB memory map needs to be resized, doing that now.");
|
||||
do_resize();
|
||||
}
|
||||
|
||||
@@ -1132,7 +1134,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
|
||||
if (!(mdb_flags & MDB_RDONLY))
|
||||
{
|
||||
result = mdb_drop(txn, m_hf_starting_heights, 1);
|
||||
if (result)
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_hf_starting_heights: ", result).c_str()));
|
||||
}
|
||||
|
||||
@@ -2041,9 +2043,10 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const uint64_
|
||||
else if (result)
|
||||
throw0(DB_ERROR(lmdb_error("DB error attempting to get data for tx_outputs[tx_index]", result).c_str()));
|
||||
|
||||
uint64_t* indices = (uint64_t*)v.mv_data;
|
||||
const uint64_t* indices = (const uint64_t*)v.mv_data;
|
||||
int num_outputs = v.mv_size / sizeof(uint64_t);
|
||||
|
||||
amount_output_indices.reserve(num_outputs);
|
||||
for (int i = 0; i < num_outputs; ++i)
|
||||
{
|
||||
// LOG_PRINT_L0("amount output index[" << 2*i << "]" << ": " << paired_indices[2*i] << " global output index: " << paired_indices[2*i+1]);
|
||||
@@ -2500,7 +2503,7 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c
|
||||
// for batch mode, DB resize check is done at start of batch transaction
|
||||
if (! m_batch_active && need_resize())
|
||||
{
|
||||
LOG_PRINT_L0("LMDB memory map needs resized, doing that now.");
|
||||
LOG_PRINT_L0("LMDB memory map needs to be resized, doing that now.");
|
||||
do_resize();
|
||||
}
|
||||
}
|
||||
@@ -2597,7 +2600,7 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
|
||||
|
||||
auto get_result = mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_GET_BOTH);
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
throw1(OUTPUT_DNE("Attempting to get output pubkey by global index, but key does not exist"));
|
||||
throw1(OUTPUT_DNE((std::string("Attempting to get output pubkey by global index (amount ") + boost::lexical_cast<std::string>(amount) + ", index " + boost::lexical_cast<std::string>(index) + ", count " + boost::lexical_cast<std::string>(get_num_outputs(amount)) + "), but key does not exist").c_str()));
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve an output pubkey from the db", get_result).c_str()));
|
||||
|
||||
@@ -2644,7 +2647,7 @@ void BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const std::
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve an output from the db", get_result).c_str()));
|
||||
|
||||
outkey *okp = (outkey *)v.mv_data;
|
||||
const outkey *okp = (const outkey *)v.mv_data;
|
||||
tx_indices.push_back(okp->output_id);
|
||||
}
|
||||
|
||||
@@ -2657,7 +2660,7 @@ void BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const std::
|
||||
LOG_PRINT_L3("db3: " << db3);
|
||||
}
|
||||
|
||||
std::map<uint64_t, uint64_t> BlockchainLMDB::get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked) const
|
||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> BlockchainLMDB::get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
@@ -2665,7 +2668,7 @@ std::map<uint64_t, uint64_t> BlockchainLMDB::get_output_histogram(const std::vec
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(output_amounts);
|
||||
|
||||
std::map<uint64_t, uint64_t> histogram;
|
||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
|
||||
MDB_val k;
|
||||
MDB_val v;
|
||||
|
||||
@@ -2683,7 +2686,7 @@ std::map<uint64_t, uint64_t> BlockchainLMDB::get_output_histogram(const std::vec
|
||||
mdb_size_t num_elems = 0;
|
||||
mdb_cursor_count(m_cur_output_amounts, &num_elems);
|
||||
uint64_t amount = *(const uint64_t*)k.mv_data;
|
||||
histogram[amount] = num_elems;
|
||||
histogram[amount] = std::make_tuple(num_elems, 0, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2694,13 +2697,13 @@ std::map<uint64_t, uint64_t> BlockchainLMDB::get_output_histogram(const std::vec
|
||||
int ret = mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_SET);
|
||||
if (ret == MDB_NOTFOUND)
|
||||
{
|
||||
histogram[amount] = 0;
|
||||
histogram[amount] = std::make_tuple(0, 0, 0);
|
||||
}
|
||||
else if (ret == MDB_SUCCESS)
|
||||
{
|
||||
mdb_size_t num_elems = 0;
|
||||
mdb_cursor_count(m_cur_output_amounts, &num_elems);
|
||||
histogram[amount] = num_elems;
|
||||
histogram[amount] = std::make_tuple(num_elems, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2709,11 +2712,11 @@ std::map<uint64_t, uint64_t> BlockchainLMDB::get_output_histogram(const std::vec
|
||||
}
|
||||
}
|
||||
|
||||
if (unlocked) {
|
||||
if (unlocked || recent_cutoff > 0) {
|
||||
const uint64_t blockchain_height = height();
|
||||
for (auto i: histogram) {
|
||||
uint64_t amount = i.first;
|
||||
uint64_t num_elems = i.second;
|
||||
for (std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>>::iterator i = histogram.begin(); i != histogram.end(); ++i) {
|
||||
uint64_t amount = i->first;
|
||||
uint64_t num_elems = std::get<0>(i->second);
|
||||
while (num_elems > 0) {
|
||||
const tx_out_index toi = get_output_tx_and_index(amount, num_elems - 1);
|
||||
const uint64_t height = get_tx_block_height(toi.first);
|
||||
@@ -2722,7 +2725,23 @@ std::map<uint64_t, uint64_t> BlockchainLMDB::get_output_histogram(const std::vec
|
||||
--num_elems;
|
||||
}
|
||||
// modifying second does not invalidate the iterator
|
||||
i.second = num_elems;
|
||||
std::get<1>(i->second) = num_elems;
|
||||
|
||||
if (recent_cutoff > 0)
|
||||
{
|
||||
uint64_t recent = 0;
|
||||
while (num_elems > 0) {
|
||||
const tx_out_index toi = get_output_tx_and_index(amount, num_elems - 1);
|
||||
const uint64_t height = get_tx_block_height(toi.first);
|
||||
const uint64_t ts = get_block_timestamp(height);
|
||||
if (ts < recent_cutoff)
|
||||
break;
|
||||
--num_elems;
|
||||
++recent;
|
||||
}
|
||||
// modifying second does not invalidate the iterator
|
||||
std::get<2>(i->second) = recent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -265,10 +265,11 @@ public:
|
||||
*
|
||||
* @param amounts optional set of amounts to lookup
|
||||
* @param unlocked whether to restrict count to unlocked outputs
|
||||
* @param recent_cutoff timestamp to determine which outputs are recent
|
||||
*
|
||||
* @return a set of amount/instances
|
||||
*/
|
||||
std::map<uint64_t, uint64_t> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked) const;
|
||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const;
|
||||
|
||||
private:
|
||||
void do_resize(uint64_t size_increase=0);
|
||||
|
||||
@@ -39,7 +39,7 @@ set(blockchain_import_private_headers
|
||||
bootstrap_serialization.h
|
||||
)
|
||||
|
||||
bitmonero_private_headers(blockchain_import
|
||||
monero_private_headers(blockchain_import
|
||||
${blockchain_import_private_headers})
|
||||
|
||||
set(blockchain_export_sources
|
||||
@@ -54,11 +54,16 @@ set(blockchain_export_private_headers
|
||||
bootstrap_serialization.h
|
||||
)
|
||||
|
||||
bitmonero_private_headers(blockchain_export
|
||||
monero_private_headers(blockchain_export
|
||||
${blockchain_export_private_headers})
|
||||
|
||||
|
||||
bitmonero_add_executable(blockchain_import
|
||||
set(cn_deserialize_sources
|
||||
cn_deserialize.cpp
|
||||
)
|
||||
|
||||
|
||||
monero_add_executable(blockchain_import
|
||||
${blockchain_import_sources}
|
||||
${blockchain_import_private_headers})
|
||||
|
||||
@@ -84,7 +89,7 @@ set_property(TARGET blockchain_import
|
||||
PROPERTY
|
||||
OUTPUT_NAME "monero-blockchain-import")
|
||||
|
||||
bitmonero_add_executable(blockchain_export
|
||||
monero_add_executable(blockchain_export
|
||||
${blockchain_export_sources}
|
||||
${blockchain_export_private_headers})
|
||||
|
||||
@@ -104,3 +109,20 @@ add_dependencies(blockchain_export
|
||||
set_property(TARGET blockchain_export
|
||||
PROPERTY
|
||||
OUTPUT_NAME "monero-blockchain-export")
|
||||
|
||||
monero_add_executable(cn_deserialize
|
||||
${cn_deserialize_sources}
|
||||
${cn_deserialize_private_headers})
|
||||
|
||||
target_link_libraries(cn_deserialize
|
||||
LINK_PRIVATE
|
||||
cryptonote_core
|
||||
p2p
|
||||
${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
add_dependencies(cn_deserialize
|
||||
version)
|
||||
set_property(TARGET cn_deserialize
|
||||
PROPERTY
|
||||
OUTPUT_NAME "monero-utils-deserialize")
|
||||
|
||||
|
||||
190
src/blockchain_utilities/cn_deserialize.cpp
Normal file
190
src/blockchain_utilities/cn_deserialize.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "cryptonote_core/tx_extra.h"
|
||||
#include "cryptonote_core/blockchain.h"
|
||||
#include "blockchain_utilities.h"
|
||||
#include "common/command_line.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace epee; // log_space
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
uint32_t log_level = 0;
|
||||
std::string input;
|
||||
|
||||
tools::sanitize_locale();
|
||||
|
||||
boost::filesystem::path output_file_path;
|
||||
|
||||
po::options_description desc_cmd_only("Command line options");
|
||||
po::options_description desc_cmd_sett("Command line options and settings options");
|
||||
const command_line::arg_descriptor<std::string> arg_output_file = {"output-file", "Specify output file", "", true};
|
||||
const command_line::arg_descriptor<uint32_t> arg_log_level = {"log-level", "", log_level};
|
||||
const command_line::arg_descriptor<std::string> arg_input = {"input", "Specify input has a hexadecimal string", ""};
|
||||
|
||||
command_line::add_arg(desc_cmd_sett, arg_output_file);
|
||||
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
||||
command_line::add_arg(desc_cmd_sett, arg_input);
|
||||
|
||||
command_line::add_arg(desc_cmd_only, command_line::arg_help);
|
||||
|
||||
po::options_description desc_options("Allowed options");
|
||||
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
|
||||
|
||||
po::variables_map vm;
|
||||
bool r = command_line::handle_error_helper(desc_options, [&]()
|
||||
{
|
||||
po::store(po::parse_command_line(argc, argv, desc_options), vm);
|
||||
po::notify(vm);
|
||||
return true;
|
||||
});
|
||||
if (! r)
|
||||
return 1;
|
||||
|
||||
if (command_line::get_arg(vm, command_line::arg_help))
|
||||
{
|
||||
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
|
||||
std::cout << desc_options << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_level = command_line::get_arg(vm, arg_log_level);
|
||||
input = command_line::get_arg(vm, arg_input);
|
||||
if (input.empty())
|
||||
{
|
||||
std::cerr << "--input is mandatory" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_space::get_set_log_detalisation_level(true, log_level);
|
||||
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
|
||||
|
||||
std::string m_config_folder;
|
||||
|
||||
std::ostream *output;
|
||||
std::ofstream *raw_data_file = NULL;
|
||||
if (command_line::has_arg(vm, arg_output_file))
|
||||
{
|
||||
output_file_path = boost::filesystem::path(command_line::get_arg(vm, arg_output_file));
|
||||
|
||||
const boost::filesystem::path dir_path = output_file_path.parent_path();
|
||||
if (!dir_path.empty())
|
||||
{
|
||||
if (boost::filesystem::exists(dir_path))
|
||||
{
|
||||
if (!boost::filesystem::is_directory(dir_path))
|
||||
{
|
||||
std::cerr << "output directory path is a file: " << dir_path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!boost::filesystem::create_directory(dir_path))
|
||||
{
|
||||
std::cerr << "Failed to create directory " << dir_path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raw_data_file = new std::ofstream();
|
||||
raw_data_file->open(output_file_path.string(), std::ios_base::out | std::ios::trunc);
|
||||
if (raw_data_file->fail())
|
||||
return 1;
|
||||
output = raw_data_file;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_file_path = "";
|
||||
output = &std::cout;
|
||||
}
|
||||
|
||||
cryptonote::blobdata blob;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(input, blob))
|
||||
{
|
||||
std::cerr << "Invalid hex input" << std::endl;
|
||||
std::cerr << "Invalid hex input: " << input << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
cryptonote::block block;
|
||||
cryptonote::transaction tx;
|
||||
std::vector<cryptonote::tx_extra_field> fields;
|
||||
if (cryptonote::parse_and_validate_block_from_blob(blob, block))
|
||||
{
|
||||
std::cout << "Parsed block:" << std::endl;
|
||||
std::cout << cryptonote::obj_to_json_str(block) << std::endl;
|
||||
}
|
||||
else if (cryptonote::parse_and_validate_tx_from_blob(blob, tx))
|
||||
{
|
||||
std::cout << "Parsed transaction:" << std::endl;
|
||||
std::cout << cryptonote::obj_to_json_str(tx) << std::endl;
|
||||
|
||||
if (cryptonote::parse_tx_extra(tx.extra, fields))
|
||||
{
|
||||
std::cout << "tx_extra has " << fields.size() << " field(s)" << std::endl;
|
||||
for (size_t n = 0; n < fields.size(); ++n)
|
||||
{
|
||||
std::cout << "field " << n << ": ";
|
||||
if (typeid(cryptonote::tx_extra_padding) == fields[n].type()) std::cout << "extra padding: " << boost::get<cryptonote::tx_extra_padding>(fields[n]).size << " bytes";
|
||||
else if (typeid(cryptonote::tx_extra_pub_key) == fields[n].type()) std::cout << "extra pub key: " << boost::get<cryptonote::tx_extra_pub_key>(fields[n]).pub_key;
|
||||
else if (typeid(cryptonote::tx_extra_nonce) == fields[n].type()) std::cout << "extra nonce: " << epee::string_tools::buff_to_hex_nodelimer(boost::get<cryptonote::tx_extra_nonce>(fields[n]).nonce);
|
||||
else if (typeid(cryptonote::tx_extra_merge_mining_tag) == fields[n].type()) std::cout << "extra merge mining tag: depth " << boost::get<cryptonote::tx_extra_merge_mining_tag>(fields[n]).depth << ", merkle root " << boost::get<cryptonote::tx_extra_merge_mining_tag>(fields[n]).merkle_root;
|
||||
else if (typeid(cryptonote::tx_extra_mysterious_minergate) == fields[n].type()) std::cout << "extra minergate custom: " << epee::string_tools::buff_to_hex_nodelimer(boost::get<cryptonote::tx_extra_mysterious_minergate>(fields[n]).data);
|
||||
else std::cout << "unknown";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Failed to parse tx_extra" << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Not a recognized CN type" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (output->fail())
|
||||
return 1;
|
||||
output->flush();
|
||||
if (raw_data_file)
|
||||
delete raw_data_file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -31,7 +31,10 @@ set(common_sources
|
||||
command_line.cpp
|
||||
dns_utils.cpp
|
||||
util.cpp
|
||||
i18n.cpp)
|
||||
i18n.cpp
|
||||
perf_timer.cpp
|
||||
task_region.cpp
|
||||
thread_group.cpp)
|
||||
|
||||
if (STACK_TRACE)
|
||||
list(APPEND common_sources stack_trace.cpp)
|
||||
@@ -53,11 +56,14 @@ set(common_private_headers
|
||||
util.h
|
||||
varint.h
|
||||
i18n.h
|
||||
stack_trace.h)
|
||||
perf_timer.h
|
||||
stack_trace.h
|
||||
task_region.h
|
||||
thread_group.h)
|
||||
|
||||
bitmonero_private_headers(common
|
||||
monero_private_headers(common
|
||||
${common_private_headers})
|
||||
bitmonero_add_library(common
|
||||
monero_add_library(common
|
||||
${common_sources}
|
||||
${common_headers}
|
||||
${common_private_headers})
|
||||
@@ -73,5 +79,5 @@ target_link_libraries(common
|
||||
PRIVATE
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
#bitmonero_install_headers(common
|
||||
#monero_install_headers(common
|
||||
# ${common_headers})
|
||||
|
||||
@@ -29,10 +29,22 @@
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "command_line.h"
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "common/i18n.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "string_tools.h"
|
||||
|
||||
namespace command_line
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const char* tr(const char* str)
|
||||
{
|
||||
return i18n_translate(str, "command_line");
|
||||
}
|
||||
}
|
||||
|
||||
std::string input_line(const std::string& prompt)
|
||||
{
|
||||
std::cout << prompt;
|
||||
@@ -44,6 +56,20 @@ namespace command_line
|
||||
|
||||
}
|
||||
|
||||
bool is_yes(const std::string& str)
|
||||
{
|
||||
if (str == "y" || str == "Y")
|
||||
return true;
|
||||
|
||||
boost::algorithm::is_iequal ignore_case{};
|
||||
if (boost::algorithm::equals("yes", str, ignore_case))
|
||||
return true;
|
||||
if (boost::algorithm::equals(command_line::tr("yes"), str, ignore_case))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const arg_descriptor<bool> arg_help = {"help", "Produce help message"};
|
||||
const arg_descriptor<bool> arg_version = {"version", "Output version information"};
|
||||
const arg_descriptor<std::string> arg_data_dir = {"data-dir", "Specify data directory"};
|
||||
@@ -92,4 +118,9 @@ namespace command_line
|
||||
, "Show time-stats when processing blocks/txs and disk synchronization."
|
||||
, 0
|
||||
};
|
||||
const command_line::arg_descriptor<size_t> arg_block_sync_size = {
|
||||
"block-sync-size"
|
||||
, "How many blocks to sync at once during chain synchronization."
|
||||
, BLOCKS_SYNCHRONIZING_DEFAULT_COUNT
|
||||
};
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace command_line
|
||||
|
||||
std::string input_line(const std::string& prompt);
|
||||
|
||||
//! \return True if `str` is `is_iequal("y" || "yes" || `tr("yes"))`.
|
||||
bool is_yes(const std::string& str);
|
||||
|
||||
template<typename T, bool required = false>
|
||||
struct arg_descriptor;
|
||||
|
||||
@@ -216,4 +219,5 @@ namespace command_line
|
||||
extern const arg_descriptor<uint64_t> arg_prep_blocks_threads;
|
||||
extern const arg_descriptor<uint64_t> arg_db_auto_remove_logs;
|
||||
extern const arg_descriptor<uint64_t> arg_show_time_stats;
|
||||
extern const arg_descriptor<size_t> arg_block_sync_size;
|
||||
}
|
||||
|
||||
47
src/common/perf_timer.cpp
Normal file
47
src/common/perf_timer.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "perf_timer.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
int performance_timer_log_level = 2;
|
||||
__thread std::vector<PerformanceTimer*> *performance_timers = NULL;
|
||||
|
||||
void set_performance_timer_log_level(int level)
|
||||
{
|
||||
if (level < LOG_LEVEL_MIN || level > LOG_LEVEL_MAX)
|
||||
{
|
||||
LOG_PRINT_L0("Wrong log level: " << level << ", using 2");
|
||||
level = 2;
|
||||
}
|
||||
performance_timer_log_level = level;
|
||||
}
|
||||
|
||||
}
|
||||
92
src/common/perf_timer.h
Normal file
92
src/common/perf_timer.h
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
class PerformanceTimer;
|
||||
|
||||
extern int performance_timer_log_level;
|
||||
extern __thread std::vector<PerformanceTimer*> *performance_timers;
|
||||
|
||||
class PerformanceTimer
|
||||
{
|
||||
public:
|
||||
PerformanceTimer(const std::string &s, int l = LOG_LEVEL_2): name(s), level(l), started(false)
|
||||
{
|
||||
ticks = epee::misc_utils::get_tick_count();
|
||||
if (!performance_timers)
|
||||
{
|
||||
LOG_PRINT("PERF ----------", level);
|
||||
performance_timers = new std::vector<PerformanceTimer*>();
|
||||
}
|
||||
else
|
||||
{
|
||||
PerformanceTimer *pt = performance_timers->back();
|
||||
if (!pt->started)
|
||||
{
|
||||
LOG_PRINT("PERF " << std::string((performance_timers->size()-1) * 2, ' ') << " " << pt->name, pt->level);
|
||||
pt->started = true;
|
||||
}
|
||||
}
|
||||
performance_timers->push_back(this);
|
||||
}
|
||||
|
||||
~PerformanceTimer()
|
||||
{
|
||||
performance_timers->pop_back();
|
||||
ticks = epee::misc_utils::get_tick_count() - ticks;
|
||||
char s[12];
|
||||
snprintf(s, sizeof(s), "%8llu ", (unsigned long long)ticks);
|
||||
LOG_PRINT("PERF " << s << std::string(performance_timers->size() * 2, ' ') << " " << name, level);
|
||||
if (performance_timers->empty())
|
||||
{
|
||||
delete performance_timers;
|
||||
performance_timers = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
int level;
|
||||
uint64_t ticks;
|
||||
bool started;
|
||||
};
|
||||
|
||||
void set_performance_timer_log_level(int level);
|
||||
|
||||
#define PERF_TIMER(name) tools::PerformanceTimer pt_##name(#name, tools::performance_timer_log_level)
|
||||
#define PERF_TIMER_L(name, l) tools::PerformanceTimer pt_##name(#name, l)
|
||||
|
||||
}
|
||||
@@ -104,7 +104,7 @@ void log_stack_trace(const char *msg)
|
||||
|
||||
if (msg)
|
||||
LOG_PRINT2(log, msg, LOG_LEVEL_0);
|
||||
LOG_PRINT2(log, "Unwinded call stack:", LOG_LEVEL_0);
|
||||
LOG_PRINT2(log, "Unwound call stack:", LOG_LEVEL_0);
|
||||
if (unw_getcontext(&ctx) < 0) {
|
||||
LOG_PRINT2(log, "Failed to create unwind context", LOG_LEVEL_0);
|
||||
return;
|
||||
|
||||
94
src/common/task_region.cpp
Normal file
94
src/common/task_region.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "common/task_region.h"
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <cassert>
|
||||
|
||||
/* `mark_completed` and `wait` can throw in the lock call, but its difficult to
|
||||
recover from either. An exception in `wait` means the post condition of joining
|
||||
all threads cannot be achieved, and an exception in `mark_completed` means
|
||||
certain deadlock. `noexcept` qualifier will force a call to `std::terminate` if
|
||||
locking throws an exception, which should only happen if a recursive lock
|
||||
attempt is made (which is not possible since no external function is called
|
||||
while holding the lock). */
|
||||
|
||||
namespace tools
|
||||
{
|
||||
void task_region_handle::state::mark_completed(id task_id) noexcept {
|
||||
assert(task_id != 0 && (task_id & (task_id - 1)) == 0); // power of 2 check
|
||||
if (pending.fetch_and(~task_id) == task_id) {
|
||||
// synchronize with wait call, but do not need to hold
|
||||
boost::unique_lock<boost::mutex>{sync_on_complete};
|
||||
all_complete.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void task_region_handle::state::abort() noexcept {
|
||||
state* current = this;
|
||||
while (current) {
|
||||
current->ready = 0;
|
||||
current = current->next.get();
|
||||
}
|
||||
}
|
||||
|
||||
void task_region_handle::state::wait() noexcept {
|
||||
state* current = this;
|
||||
while (current) {
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock{current->sync_on_complete};
|
||||
current->all_complete.wait(lock, [current] { return current->pending == 0; });
|
||||
}
|
||||
current = current->next.get();
|
||||
}
|
||||
}
|
||||
|
||||
void task_region_handle::state::wait(thread_group& threads) noexcept {
|
||||
state* current = this;
|
||||
while (current) {
|
||||
while (current->pending != 0) {
|
||||
if (!threads.try_run_one()) {
|
||||
current->wait();
|
||||
return;
|
||||
}
|
||||
}
|
||||
current = current->next.get();
|
||||
}
|
||||
}
|
||||
|
||||
void task_region_handle::create_state() {
|
||||
st = std::make_shared<state>(std::move(st));
|
||||
next_id = 1;
|
||||
}
|
||||
|
||||
void task_region_handle::do_wait() noexcept {
|
||||
assert(st);
|
||||
const std::shared_ptr<state> temp = std::move(st);
|
||||
temp->wait(threads);
|
||||
}
|
||||
}
|
||||
223
src/common/task_region.h
Normal file
223
src/common/task_region.h
Normal file
@@ -0,0 +1,223 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "common/thread_group.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
/*! A model of the fork-join concept. `run(...)` "forks" (i.e. spawns new
|
||||
tasks), and `~task_region_handle()` or `wait()` "joins" the spawned tasks.
|
||||
`wait` will block until all tasks have completed, while `~task_region_handle()`
|
||||
blocks until all tasks have completed or aborted.
|
||||
|
||||
Do _NOT_ give this object to separate thread of execution (which includes
|
||||
`task_region_handle::run(...)`) because joining on a different thread is
|
||||
undesireable (potential deadlock).
|
||||
|
||||
This class cannot be constructed directly, use the function
|
||||
`task_region(...)` instead.
|
||||
*/
|
||||
class task_region_handle
|
||||
{
|
||||
struct state
|
||||
{
|
||||
using id = unsigned;
|
||||
|
||||
explicit state(std::shared_ptr<state> next_src) noexcept
|
||||
: next(std::move(next_src))
|
||||
, ready(0)
|
||||
, pending(0)
|
||||
, sync_on_complete()
|
||||
, all_complete() {
|
||||
}
|
||||
|
||||
state(const state&) = default;
|
||||
state(state&&) = default;
|
||||
~state() = default;
|
||||
state& operator=(const state&) = default;
|
||||
state& operator=(state&&) = default;
|
||||
|
||||
void track_id(id task_id) noexcept {
|
||||
pending |= task_id;
|
||||
ready |= task_id;
|
||||
}
|
||||
|
||||
//! \return True only once whether a given id can execute
|
||||
bool can_run(id task_id) noexcept {
|
||||
return (ready.fetch_and(~task_id) & task_id);
|
||||
}
|
||||
|
||||
//! Mark id as completed, and synchronize with waiting threads
|
||||
void mark_completed(id task_id) noexcept;
|
||||
|
||||
//! Tell all unstarted functions in region to return immediately
|
||||
void abort() noexcept;
|
||||
|
||||
//! Blocks until all functions in region have aborted or completed.
|
||||
void wait() noexcept;
|
||||
|
||||
//! Same as `wait()`, except `this_thread` runs tasks while waiting.
|
||||
void wait(thread_group& threads) noexcept;
|
||||
|
||||
private:
|
||||
/* This implementation is a bit pessimistic, it ensures that all copies
|
||||
of a wrapped task can only be executed once. `thread_group` should never
|
||||
do this, but some variable needs to track whether an abort should be done
|
||||
anyway... */
|
||||
std::shared_ptr<state> next;
|
||||
std::atomic<id> ready; //!< Tracks whether a task has been invoked
|
||||
std::atomic<id> pending; //!< Tracks when a task has completed or aborted
|
||||
boost::mutex sync_on_complete;
|
||||
boost::condition_variable all_complete;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct wrapper
|
||||
{
|
||||
wrapper(state::id id_src, std::shared_ptr<state> st_src, F f_src)
|
||||
: task_id(id_src), st(std::move(st_src)), f(std::move(f_src)) {
|
||||
}
|
||||
|
||||
wrapper(const wrapper&) = default;
|
||||
wrapper(wrapper&&) = default;
|
||||
wrapper& operator=(const wrapper&) = default;
|
||||
wrapper& operator=(wrapper&&) = default;
|
||||
|
||||
void operator()() {
|
||||
if (st) {
|
||||
if (st->can_run(task_id)) {
|
||||
f();
|
||||
}
|
||||
st->mark_completed(task_id);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const state::id task_id;
|
||||
std::shared_ptr<state> st;
|
||||
F f;
|
||||
};
|
||||
|
||||
public:
|
||||
friend struct task_region_;
|
||||
|
||||
task_region_handle() = delete;
|
||||
task_region_handle(const task_region_handle&) = delete;
|
||||
task_region_handle(task_region_handle&&) = delete;
|
||||
|
||||
//! Cancels unstarted pending tasks, and waits for them to respond.
|
||||
~task_region_handle() noexcept {
|
||||
if (st) {
|
||||
st->abort();
|
||||
st->wait(threads);
|
||||
}
|
||||
}
|
||||
|
||||
task_region_handle& operator=(const task_region_handle&) = delete;
|
||||
task_region_handle& operator=(task_region_handle&&) = delete;
|
||||
|
||||
/*! If the group has no threads, `f` is immediately run before returning.
|
||||
Otherwise, `f` is dispatched to the thread_group associated with `this`
|
||||
region. If `f` is dispatched to another thread, and it throws, the process
|
||||
will immediately terminate. See std::packaged_task for getting exceptions on
|
||||
functions executed on other threads. */
|
||||
template<typename F>
|
||||
void run(F&& f) {
|
||||
if (threads.count() == 0) {
|
||||
f();
|
||||
} else {
|
||||
if (!st || next_id == 0) {
|
||||
create_state();
|
||||
}
|
||||
const state::id this_id = next_id;
|
||||
next_id <<= 1;
|
||||
|
||||
st->track_id(this_id);
|
||||
threads.dispatch(wrapper<F>{this_id, st, std::move(f)});
|
||||
}
|
||||
}
|
||||
|
||||
//! Wait until all functions provided to `run` have completed.
|
||||
void wait() noexcept {
|
||||
if (st) {
|
||||
do_wait();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
explicit task_region_handle(thread_group& threads_src)
|
||||
: st(nullptr), threads(threads_src), next_id(0) {
|
||||
}
|
||||
|
||||
void create_state();
|
||||
void do_wait() noexcept;
|
||||
|
||||
std::shared_ptr<state> st;
|
||||
thread_group& threads;
|
||||
state::id next_id;
|
||||
};
|
||||
|
||||
/*! Function for creating a `task_region_handle`, which automatically calls
|
||||
`task_region_handle::wait()` before returning. If a `thread_group` is not
|
||||
provided, one is created with an optimal number of threads. The callback `f`
|
||||
must have the signature `void(task_region_handle&)`. */
|
||||
struct task_region_ {
|
||||
template<typename F>
|
||||
void operator()(thread_group& threads, F&& f) const {
|
||||
static_assert(
|
||||
std::is_same<void, typename std::result_of<F(task_region_handle&)>::type>::value,
|
||||
"f cannot have a return value"
|
||||
);
|
||||
task_region_handle region{threads};
|
||||
f(region);
|
||||
region.wait();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void operator()(thread_group&& threads, F&& f) const {
|
||||
(*this)(threads, std::forward<F>(f));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void operator()(F&& f) const {
|
||||
thread_group threads;
|
||||
(*this)(threads, std::forward<F>(f));
|
||||
}
|
||||
};
|
||||
|
||||
constexpr const task_region_ task_region{};
|
||||
}
|
||||
150
src/common/thread_group.cpp
Normal file
150
src/common/thread_group.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "common/thread_group.h"
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
std::size_t thread_group::optimal() {
|
||||
static_assert(
|
||||
std::numeric_limits<unsigned>::max() <= std::numeric_limits<std::size_t>::max(),
|
||||
"unexpected truncation"
|
||||
);
|
||||
const std::size_t hardware = get_max_concurrency();
|
||||
return hardware ? (hardware - 1) : 0;
|
||||
}
|
||||
|
||||
std::size_t thread_group::optimal_with_max(std::size_t count) {
|
||||
return count ? std::min(count - 1, optimal()) : 0;
|
||||
}
|
||||
|
||||
thread_group::thread_group(std::size_t count) : internal() {
|
||||
if (count) {
|
||||
internal.emplace(count);
|
||||
}
|
||||
}
|
||||
|
||||
thread_group::data::data(std::size_t count)
|
||||
: threads()
|
||||
, head{nullptr}
|
||||
, last(std::addressof(head))
|
||||
, mutex()
|
||||
, has_work()
|
||||
, stop(false) {
|
||||
threads.reserve(count);
|
||||
while (count--) {
|
||||
threads.push_back(boost::thread(&thread_group::data::run, this));
|
||||
}
|
||||
}
|
||||
|
||||
thread_group::data::~data() noexcept {
|
||||
{
|
||||
const boost::unique_lock<boost::mutex> lock(mutex);
|
||||
stop = true;
|
||||
}
|
||||
has_work.notify_all();
|
||||
for (auto& worker : threads) {
|
||||
try {
|
||||
worker.join();
|
||||
}
|
||||
catch(...) {}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<thread_group::data::work> thread_group::data::get_next() noexcept {
|
||||
std::unique_ptr<work> rc = std::move(head.ptr);
|
||||
if (rc != nullptr) {
|
||||
head.ptr = std::move(rc->next.ptr);
|
||||
if (head.ptr == nullptr) {
|
||||
last = std::addressof(head);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool thread_group::data::try_run_one() noexcept {
|
||||
/* This function and `run()` can both throw when acquiring the lock, or in
|
||||
dispatched function. It is tough to recover from either, particularly the
|
||||
lock case. These functions are marked as noexcept so that if either call
|
||||
throws, the entire process is terminated. Users of the `dispatch` call are
|
||||
expected to make their functions noexcept, or use std::packaged_task to copy
|
||||
exceptions so that the process will continue in all but the most pessimistic
|
||||
cases (std::bad_alloc). This was the existing behavior;
|
||||
`asio::io_service::run` propogates errors from dispatched calls, and uncaught
|
||||
exceptions on threads result in process termination. */
|
||||
std::unique_ptr<work> next = nullptr;
|
||||
{
|
||||
const boost::unique_lock<boost::mutex> lock(mutex);
|
||||
next = get_next();
|
||||
}
|
||||
if (next) {
|
||||
assert(next->f);
|
||||
next->f();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void thread_group::data::run() noexcept {
|
||||
// see `try_run_one()` source for additional information
|
||||
while (true) {
|
||||
std::unique_ptr<work> next = nullptr;
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
has_work.wait(lock, [this] { return head.ptr != nullptr || stop; });
|
||||
if (stop) {
|
||||
return;
|
||||
}
|
||||
next = get_next();
|
||||
}
|
||||
assert(next != nullptr);
|
||||
assert(next->f);
|
||||
next->f();
|
||||
}
|
||||
}
|
||||
|
||||
void thread_group::data::dispatch(std::function<void()> f) {
|
||||
std::unique_ptr<work> latest(new work{std::move(f), node{nullptr}});
|
||||
node* const latest_node = std::addressof(latest->next);
|
||||
{
|
||||
const boost::unique_lock<boost::mutex> lock(mutex);
|
||||
assert(last != nullptr);
|
||||
assert(last->ptr == nullptr);
|
||||
|
||||
last->ptr = std::move(latest);
|
||||
last = latest_node;
|
||||
}
|
||||
has_work.notify_one();
|
||||
}
|
||||
}
|
||||
143
src/common/thread_group.h
Normal file
143
src/common/thread_group.h
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#pragma once
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
//! Manages zero or more threads for work dispatching.
|
||||
class thread_group
|
||||
{
|
||||
public:
|
||||
|
||||
//! \return `get_max_concurrency() ? get_max_concurrency() - 1 : 0`
|
||||
static std::size_t optimal();
|
||||
|
||||
//! \return `count ? min(count - 1, optimal()) : 0`
|
||||
static std::size_t optimal_with_max(std::size_t count);
|
||||
|
||||
//! Create an optimal number of threads.
|
||||
explicit thread_group() : thread_group(optimal()) {}
|
||||
|
||||
//! Create exactly `count` threads.
|
||||
explicit thread_group(std::size_t count);
|
||||
|
||||
thread_group(thread_group const&) = delete;
|
||||
thread_group(thread_group&&) = delete;
|
||||
|
||||
//! Joins threads, but does not necessarily run all dispatched functions.
|
||||
~thread_group() = default;
|
||||
|
||||
thread_group& operator=(thread_group const&) = delete;
|
||||
thread_group& operator=(thread_group&&) = delete;
|
||||
|
||||
//! \return Number of threads owned by `this` group.
|
||||
std::size_t count() const noexcept {
|
||||
if (internal) {
|
||||
return internal->count();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! \return True iff a function was available and executed (on `this_thread`).
|
||||
bool try_run_one() noexcept {
|
||||
if (internal) {
|
||||
return internal->try_run_one();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! `f` is invoked immediately if `count() == 0`, otherwise execution of `f`
|
||||
is queued for next available thread. If `f` is queued, any exception leaving
|
||||
that function will result in process termination. Use std::packaged_task if
|
||||
exceptions need to be handled. */
|
||||
template<typename F>
|
||||
void dispatch(F&& f) {
|
||||
if (internal) {
|
||||
internal->dispatch(std::forward<F>(f));
|
||||
}
|
||||
else {
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class data {
|
||||
public:
|
||||
data(std::size_t count);
|
||||
~data() noexcept;
|
||||
|
||||
std::size_t count() const noexcept {
|
||||
return threads.size();
|
||||
}
|
||||
|
||||
bool try_run_one() noexcept;
|
||||
void dispatch(std::function<void()> f);
|
||||
|
||||
private:
|
||||
struct work;
|
||||
|
||||
struct node {
|
||||
std::unique_ptr<work> ptr;
|
||||
};
|
||||
|
||||
struct work {
|
||||
std::function<void()> f;
|
||||
node next;
|
||||
};
|
||||
|
||||
//! Requires lock on `mutex`.
|
||||
std::unique_ptr<work> get_next() noexcept;
|
||||
|
||||
//! Blocks until destructor is invoked, only call from thread.
|
||||
void run() noexcept;
|
||||
|
||||
private:
|
||||
std::vector<boost::thread> threads;
|
||||
node head;
|
||||
node* last;
|
||||
boost::condition_variable has_work;
|
||||
boost::mutex mutex;
|
||||
bool stop;
|
||||
};
|
||||
|
||||
private:
|
||||
// optionally construct elements, without separate heap allocation
|
||||
boost::optional<data> internal;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -68,9 +68,9 @@ set(crypto_private_headers
|
||||
skein.h
|
||||
skein_port.h)
|
||||
|
||||
bitmonero_private_headers(crypto
|
||||
monero_private_headers(crypto
|
||||
${crypto_private_headers})
|
||||
bitmonero_add_library(crypto
|
||||
monero_add_library(crypto
|
||||
${crypto_sources}
|
||||
${crypto_headers}
|
||||
${crypto_private_headers})
|
||||
|
||||
@@ -236,6 +236,6 @@ namespace crypto {
|
||||
}
|
||||
}
|
||||
|
||||
CRYPTO_MAKE_COMPARABLE(public_key)
|
||||
CRYPTO_MAKE_HASHABLE(public_key)
|
||||
CRYPTO_MAKE_HASHABLE(key_image)
|
||||
CRYPTO_MAKE_COMPARABLE(signature)
|
||||
|
||||
@@ -639,7 +639,10 @@ static OAES_RET oaes_key_gen( OAES_CTX * ctx, size_t key_size )
|
||||
_key->data = (uint8_t *) calloc( key_size, sizeof( uint8_t ));
|
||||
|
||||
if( NULL == _key->data )
|
||||
{
|
||||
free( _key );
|
||||
return OAES_RET_MEM;
|
||||
}
|
||||
|
||||
for( _i = 0; _i < key_size; _i++ )
|
||||
#ifdef OAES_HAVE_ISAAC
|
||||
|
||||
@@ -77,7 +77,7 @@ typedef struct /* 1024-bit Skein hash context stru
|
||||
} Skein1024_Ctxt_t;
|
||||
|
||||
/* Skein APIs for (incremental) "straight hashing" */
|
||||
#if SKEIN_256_NIST_MAX_HASH_BITS
|
||||
#if SKEIN_256_NIST_MAX_HASHBITS
|
||||
static int Skein_256_Init (Skein_256_Ctxt_t *ctx, size_t hashBitLen);
|
||||
#endif
|
||||
static int Skein_512_Init (Skein_512_Ctxt_t *ctx, size_t hashBitLen);
|
||||
@@ -1941,7 +1941,7 @@ static HashReturn Final (hashState *state, BitSequence *hashval);
|
||||
/* select the context size and init the context */
|
||||
static HashReturn Init(hashState *state, int hashbitlen)
|
||||
{
|
||||
#if SKEIN_256_NIST_MAX_HASH_BITS
|
||||
#if SKEIN_256_NIST_MAX_HASHBITS
|
||||
if (hashbitlen <= SKEIN_256_NIST_MAX_HASHBITS)
|
||||
{
|
||||
Skein_Assert(hashbitlen > 0,BAD_HASHLEN);
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
|
||||
#define FEE_PER_KB_OLD ((uint64_t)10000000000) // pow(10, 10)
|
||||
#define FEE_PER_KB ((uint64_t)2000000000) // 2 * pow(10, 9)
|
||||
#define DYNAMIC_FEE_PER_KB_BASE_FEE ((uint64_t)2000000000) // 2 * pow(10,9)
|
||||
#define DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD ((uint64_t)10000000000000) // 10 * pow(10,12)
|
||||
|
||||
#define ORPHANED_BLOCKS_MAX_COUNT 100
|
||||
|
||||
@@ -111,6 +113,9 @@
|
||||
#define P2P_IP_FAILS_BEFORE_BLOCK 10
|
||||
#define P2P_IDLE_CONNECTION_KILL_INTERVAL (5*60) //5 minutes
|
||||
|
||||
#define P2P_SUPPORT_FLAG_FLUFFY_BLOCKS 0x01
|
||||
#define P2P_SUPPORT_FLAGS P2P_SUPPORT_FLAG_FLUFFY_BLOCKS
|
||||
|
||||
#define ALLOW_DEBUG_COMMANDS
|
||||
|
||||
#define CRYPTONOTE_NAME "bitmonero"
|
||||
@@ -122,12 +127,14 @@
|
||||
|
||||
#define THREAD_STACK_SIZE 5 * 1024 * 1024
|
||||
|
||||
#define HF_VERSION_DYNAMIC_FEE 4
|
||||
|
||||
// New constants are intended to go here
|
||||
namespace config
|
||||
{
|
||||
uint64_t const DEFAULT_FEE_ATOMIC_XMR_PER_KB = 500; // Just a placeholder! Change me!
|
||||
uint8_t const FEE_CALCULATION_MAX_RETRIES = 10;
|
||||
uint64_t const DEFAULT_DUST_THRESHOLD = ((uint64_t)10000000000); // pow(10, 10)
|
||||
uint64_t const DEFAULT_DUST_THRESHOLD = ((uint64_t)2000000000); // 2 * pow(10, 9)
|
||||
uint64_t const BASE_REWARD_CLAMP_THRESHOLD = ((uint64_t)100000000); // pow(10, 8)
|
||||
std::string const P2P_REMOTE_DEBUG_TRUSTED_PUB_KEY = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ else()
|
||||
set(Blocks "")
|
||||
endif()
|
||||
|
||||
bitmonero_private_headers(cryptonote_core
|
||||
monero_private_headers(cryptonote_core
|
||||
${crypto_private_headers})
|
||||
bitmonero_add_library(cryptonote_core
|
||||
monero_add_library(cryptonote_core
|
||||
${cryptonote_core_sources}
|
||||
${cryptonote_core_headers}
|
||||
${cryptonote_core_private_headers})
|
||||
|
||||
@@ -46,12 +46,14 @@
|
||||
#include "misc_language.h"
|
||||
#include "profile_tools.h"
|
||||
#include "file_io_utils.h"
|
||||
#include "common/int-util.h"
|
||||
#include "common/boost_serialization_helper.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core/checkpoints.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "ringct/rctSigs.h"
|
||||
#include "common/perf_timer.h"
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
#include "blocks/blocks.h"
|
||||
#endif
|
||||
@@ -71,6 +73,9 @@ extern "C" void slow_hash_free_state();
|
||||
|
||||
DISABLE_VS_WARNINGS(4267)
|
||||
|
||||
// used to overestimate the block reward when estimating a per kB to use
|
||||
#define BLOCK_REWARD_OVERESTIMATE (10 * 1000000000000)
|
||||
|
||||
static const struct {
|
||||
uint8_t version;
|
||||
uint64_t height;
|
||||
@@ -86,8 +91,8 @@ static const struct {
|
||||
// version 3 starts from block 1141317, which is on or around the 24th of September, 2016. Fork time finalised on 2016-03-21.
|
||||
{ 3, 1141317, 0, 1458558528 },
|
||||
|
||||
// version 4 starts from block 1220517, which is on or around the 5th of January, 2017. Fork time finalised on 2016-09-18.
|
||||
{ 4, 1220517, 0, 1483574400 },
|
||||
// version 4 starts from block 1220516, which is on or around the 5th of January, 2017. Fork time finalised on 2016-09-18.
|
||||
{ 4, 1220516, 0, 1483574400 },
|
||||
|
||||
// version 5 starts from block 1406997, which is on or around the 20th of September, 2017. Fork time finalised on 2016-09-18.
|
||||
{ 5, 1406997, 0, 1505865600 },
|
||||
@@ -108,7 +113,7 @@ static const struct {
|
||||
|
||||
// versions 3-5 were passed in rapid succession from September 18th, 2016
|
||||
{ 3, 800500, 0, 1472415034 },
|
||||
{ 4, 801220, 0, 1472415035 },
|
||||
{ 4, 801219, 0, 1472415035 },
|
||||
{ 5, 802660, 0, 1472415036 },
|
||||
};
|
||||
static const uint64_t testnet_hard_fork_version_1_till = 624633;
|
||||
@@ -116,7 +121,7 @@ static const uint64_t testnet_hard_fork_version_1_till = 624633;
|
||||
//------------------------------------------------------------------
|
||||
Blockchain::Blockchain(tx_memory_pool& tx_pool) :
|
||||
m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false),
|
||||
m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0)
|
||||
m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
}
|
||||
@@ -387,7 +392,7 @@ bool Blockchain::init(BlockchainDB* db, HardFork*& hf, const bool testnet)
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::store_blockchain()
|
||||
{
|
||||
LOG_PRINT_YELLOW("Blockchain::" << __func__, LOG_LEVEL_3);
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
// lock because the rpc_thread command handler also calls this
|
||||
CRITICAL_REGION_LOCAL(m_db->m_synchronization_lock);
|
||||
|
||||
@@ -419,9 +424,10 @@ bool Blockchain::deinit()
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
LOG_PRINT_L0("Closing IO Service.");
|
||||
// stop async service
|
||||
m_async_work_idle.reset();
|
||||
LOG_PRINT_L1("Stopping blockchain read/write activity");
|
||||
|
||||
// stop async service
|
||||
m_async_work_idle.reset();
|
||||
m_async_pool.join_all();
|
||||
m_async_service.stop();
|
||||
|
||||
@@ -436,14 +442,15 @@ bool Blockchain::deinit()
|
||||
try
|
||||
{
|
||||
m_db->close();
|
||||
LOG_PRINT_L1("Local blockchain read/write activity stopped successfully");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_PRINT_L0(std::string("Error closing blockchain db: ") + e.what());
|
||||
LOG_ERROR(std::string("Error closing blockchain db: ") + e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_PRINT_L0("There was an issue closing/storing the blockchain, shutting down now to prevent issues!");
|
||||
LOG_ERROR("There was an issue closing/storing the blockchain, shutting down now to prevent issues!");
|
||||
}
|
||||
|
||||
delete m_hardfork;
|
||||
@@ -752,6 +759,9 @@ bool Blockchain::rollback_blockchain_switching(std::list<block>& original_chain,
|
||||
pop_block_from_blockchain();
|
||||
}
|
||||
|
||||
// make sure the hard fork object updates its current version
|
||||
m_hardfork->reorganize_from_chain_height(rollback_height);
|
||||
|
||||
//return back original chain
|
||||
for (auto& bl : original_chain)
|
||||
{
|
||||
@@ -825,12 +835,12 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
|
||||
// looking into.
|
||||
add_block_as_invalid(ch_ent->second, get_block_hash(ch_ent->second.bl));
|
||||
LOG_PRINT_L1("The block was inserted as invalid while connecting new alternative chain, block_id: " << get_block_hash(ch_ent->second.bl));
|
||||
m_alternative_chains.erase(ch_ent);
|
||||
m_alternative_chains.erase(*alt_ch_iter++);
|
||||
|
||||
for(auto alt_ch_to_orph_iter = ++alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); alt_ch_to_orph_iter++)
|
||||
for(auto alt_ch_to_orph_iter = alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); )
|
||||
{
|
||||
add_block_as_invalid((*alt_ch_iter)->second, (*alt_ch_iter)->first);
|
||||
m_alternative_chains.erase(*alt_ch_to_orph_iter);
|
||||
add_block_as_invalid((*alt_ch_to_orph_iter)->second, (*alt_ch_to_orph_iter)->first);
|
||||
m_alternative_chains.erase(*alt_ch_to_orph_iter++);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1142,7 +1152,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
|
||||
uint8_t hf_version = m_hardfork->get_current_version();
|
||||
size_t max_outs = hf_version >= 4 ? 1 : 11;
|
||||
bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance");
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance");
|
||||
size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx);
|
||||
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
|
||||
LOG_PRINT_L1("Creating block template: miner tx size " << get_object_blobsize(b.miner_tx) <<
|
||||
@@ -1152,7 +1162,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
|
||||
{
|
||||
r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version);
|
||||
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance");
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance");
|
||||
size_t coinbase_blob_size = get_object_blobsize(b.miner_tx);
|
||||
if (coinbase_blob_size > cumulative_size - txs_size)
|
||||
{
|
||||
@@ -1754,7 +1764,7 @@ bool Blockchain::get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::r
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res) const
|
||||
bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
@@ -1764,7 +1774,7 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_R
|
||||
for (const auto &i: req.outputs)
|
||||
{
|
||||
// get tx_hash, tx_out_index from DB
|
||||
const output_data_t &od = m_db->get_output_key(i.amount, i.index);
|
||||
const output_data_t od = m_db->get_output_key(i.amount, i.index);
|
||||
tx_out_index toi = m_db->get_output_tx_and_index(i.amount, i.index);
|
||||
bool unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
|
||||
|
||||
@@ -1795,7 +1805,7 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
|
||||
auto gen_hash = m_db->get_block_hash_from_height(0);
|
||||
if(qblock_ids.back() != gen_hash)
|
||||
{
|
||||
LOG_PRINT_L1("Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block missmatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection");
|
||||
LOG_PRINT_L1("Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block mismatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection");
|
||||
m_db->block_txn_abort();
|
||||
return false;
|
||||
}
|
||||
@@ -1828,14 +1838,6 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
|
||||
return false;
|
||||
}
|
||||
|
||||
// if split_height remains 0, we didn't have any but the genesis block in common
|
||||
// which is only fine if the blocks just have the genesis block
|
||||
if(split_height == 0 && qblock_ids.size() > 1)
|
||||
{
|
||||
LOG_ERROR("Ours and foreign blockchain have only genesis block in common... o.O");
|
||||
return false;
|
||||
}
|
||||
|
||||
//we start to put block ids INCLUDING last known id, just to make other side be sure
|
||||
starter_offset = split_height;
|
||||
return true;
|
||||
@@ -2235,6 +2237,19 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
}
|
||||
|
||||
// from v4, forbid invalid pubkeys
|
||||
if (m_hardfork->get_current_version() >= 4) {
|
||||
for (const auto &o: tx.vout) {
|
||||
if (o.target.type() == typeid(txout_to_key)) {
|
||||
const txout_to_key& out_to_key = boost::get<txout_to_key>(o.target);
|
||||
if (!crypto::check_key(out_to_key.key)) {
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
@@ -2251,6 +2266,7 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const
|
||||
}
|
||||
bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys)
|
||||
{
|
||||
PERF_TIMER(expand_transaction_2);
|
||||
CHECK_AND_ASSERT_MES(tx.version == 2, false, "Transaction version is not 2");
|
||||
|
||||
rct::rctSig &rv = tx.rct_signatures;
|
||||
@@ -2327,6 +2343,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
// using threads, etc.)
|
||||
bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, uint64_t* pmax_used_block_height)
|
||||
{
|
||||
PERF_TIMER(check_tx_inputs);
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
size_t sig_index = 0;
|
||||
if(pmax_used_block_height)
|
||||
@@ -2711,6 +2728,90 @@ void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const
|
||||
result = crypto::check_ring_signature(tx_prefix_hash, key_image, p_output_keys, sig.data()) ? 1 : 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
uint64_t Blockchain::get_dynamic_per_kb_fee(uint64_t block_reward, size_t median_block_size)
|
||||
{
|
||||
if (median_block_size < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2)
|
||||
median_block_size = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2;
|
||||
|
||||
uint64_t unscaled_fee_per_kb = (DYNAMIC_FEE_PER_KB_BASE_FEE * CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / median_block_size);
|
||||
uint64_t hi, lo = mul128(unscaled_fee_per_kb, block_reward, &hi);
|
||||
static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD % 1000000 == 0, "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD must be divisible by 1000000");
|
||||
static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000 <= std::numeric_limits<uint32_t>::max(), "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD is too large");
|
||||
// divide in two steps, since the divisor must be 32 bits, but DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD isn't
|
||||
div128_32(hi, lo, DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000, &hi, &lo);
|
||||
div128_32(hi, lo, 1000000, &hi, &lo);
|
||||
assert(hi == 0);
|
||||
|
||||
return lo;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const
|
||||
{
|
||||
const uint8_t version = get_current_hard_fork_version();
|
||||
|
||||
uint64_t fee_per_kb;
|
||||
if (version < HF_VERSION_DYNAMIC_FEE)
|
||||
{
|
||||
fee_per_kb = FEE_PER_KB;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t median = m_current_block_cumul_sz_limit / 2;
|
||||
uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0;
|
||||
uint64_t base_reward;
|
||||
if (!get_block_reward(median, 1, already_generated_coins, base_reward, version))
|
||||
return false;
|
||||
fee_per_kb = get_dynamic_per_kb_fee(base_reward, median);
|
||||
}
|
||||
LOG_PRINT_L2("Using " << print_money(fee) << "/kB fee");
|
||||
|
||||
uint64_t needed_fee = blob_size / 1024;
|
||||
needed_fee += (blob_size % 1024) ? 1 : 0;
|
||||
needed_fee *= fee_per_kb;
|
||||
|
||||
if (fee < needed_fee)
|
||||
{
|
||||
LOG_PRINT_L1("transaction fee is not enough: " << print_money(fee) << ", minimum fee: " << print_money(needed_fee));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
uint64_t Blockchain::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) const
|
||||
{
|
||||
const uint8_t version = get_current_hard_fork_version();
|
||||
|
||||
if (version < HF_VERSION_DYNAMIC_FEE)
|
||||
return FEE_PER_KB;
|
||||
|
||||
if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW)
|
||||
grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1;
|
||||
|
||||
std::vector<size_t> sz;
|
||||
get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks);
|
||||
for (size_t i = 0; i < grace_blocks; ++i)
|
||||
sz.push_back(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2);
|
||||
|
||||
uint64_t median = epee::misc_utils::median(sz);
|
||||
if(median <= CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2)
|
||||
median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2;
|
||||
|
||||
uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0;
|
||||
uint64_t base_reward;
|
||||
if (!get_block_reward(median, 1, already_generated_coins, base_reward, version))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to determine block reward, using placeholder " << print_money(BLOCK_REWARD_OVERESTIMATE) << " as a high bound");
|
||||
base_reward = BLOCK_REWARD_OVERESTIMATE;
|
||||
}
|
||||
|
||||
uint64_t fee = get_dynamic_per_kb_fee(base_reward, median);
|
||||
LOG_PRINT_L2("Estimating " << grace_blocks << "-block fee at " << print_money(fee) << "/kB");
|
||||
return fee;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// This function checks to see if a tx is unlocked. unlock_time is either
|
||||
// a block index or a unix time.
|
||||
@@ -3357,6 +3458,8 @@ void Blockchain::block_longhash_worker(const uint64_t height, const std::vector<
|
||||
// the height of the block passed to it
|
||||
for (const auto & block : blocks)
|
||||
{
|
||||
if (m_cancel)
|
||||
return;
|
||||
crypto::hash id = get_block_hash(block);
|
||||
crypto::hash pow = get_block_longhash(block, height);
|
||||
map.emplace(id, pow);
|
||||
@@ -3532,6 +3635,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
|
||||
|
||||
thread_list.clear();
|
||||
|
||||
if (m_cancel)
|
||||
return false;
|
||||
|
||||
for (const auto & map : maps)
|
||||
{
|
||||
m_blocks_longhash_table.insert(map.begin(), map.end());
|
||||
@@ -3539,6 +3645,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cancel)
|
||||
return false;
|
||||
|
||||
if (blocks_exist)
|
||||
{
|
||||
LOG_PRINT_L0("Skipping prepare blocks. Blocks exist.");
|
||||
@@ -3576,6 +3685,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
|
||||
// generate sorted tables for all amounts and absolute offsets
|
||||
for (const auto &entry : blocks_entry)
|
||||
{
|
||||
if (m_cancel)
|
||||
return false;
|
||||
|
||||
for (const auto &tx_blob : entry.txs)
|
||||
{
|
||||
crypto::hash tx_hash = null_hash;
|
||||
@@ -3684,6 +3796,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
|
||||
// now generate a table for each tx_prefix and k_image hashes
|
||||
for (const auto &entry : blocks_entry)
|
||||
{
|
||||
if (m_cancel)
|
||||
return false;
|
||||
|
||||
for (const auto &tx_blob : entry.txs)
|
||||
{
|
||||
crypto::hash tx_hash = null_hash;
|
||||
@@ -3760,9 +3875,14 @@ bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, ui
|
||||
return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting);
|
||||
}
|
||||
|
||||
std::map<uint64_t, uint64_t> Blockchain:: get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked) const
|
||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const
|
||||
{
|
||||
return m_db->get_output_histogram(amounts, unlocked);
|
||||
return m_db->get_output_histogram(amounts, unlocked, recent_cutoff);
|
||||
}
|
||||
|
||||
void Blockchain::cancel()
|
||||
{
|
||||
m_cancel = true;
|
||||
}
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
|
||||
@@ -452,7 +452,7 @@ namespace cryptonote
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
bool get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res) const;
|
||||
bool get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res) const;
|
||||
|
||||
/**
|
||||
* @brief gets random ringct outputs to mix with
|
||||
@@ -512,6 +512,47 @@ namespace cryptonote
|
||||
*/
|
||||
bool check_tx_inputs(transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false);
|
||||
|
||||
/**
|
||||
* @brief get dynamic per kB fee for a given block size
|
||||
*
|
||||
* The dynamic fee is based on the block size in a past window, and
|
||||
* the current block reward. It is expressed by kB.
|
||||
*
|
||||
* @param block_reward the current block reward
|
||||
* @param median_block_size the median blob's size in the past window
|
||||
*
|
||||
* @return the per kB fee
|
||||
*/
|
||||
static uint64_t get_dynamic_per_kb_fee(uint64_t block_reward, size_t median_block_size);
|
||||
|
||||
/**
|
||||
* @brief get dynamic per kB fee estimate for the next few blocks
|
||||
*
|
||||
* The dynamic fee is based on the block size in a past window, and
|
||||
* the current block reward. It is expressed by kB. This function
|
||||
* calculates an estimate for a dynamic fee which will be valid for
|
||||
* the next grace_blocks
|
||||
*
|
||||
* @param grace_blocks number of blocks we want the fee to be valid for
|
||||
*
|
||||
* @return the per kB fee estimate
|
||||
*/
|
||||
uint64_t get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) const;
|
||||
|
||||
/**
|
||||
* @brief validate a transaction's fee
|
||||
*
|
||||
* This function validates the fee is enough for the transaction.
|
||||
* This is based on the size of the transaction blob, and, after a
|
||||
* height threshold, on the average size of transaction in a past window
|
||||
*
|
||||
* @param blob_size the transaction blob's size
|
||||
* @param fee the fee
|
||||
*
|
||||
* @return true if the fee is enough, false otherwise
|
||||
*/
|
||||
bool check_fee(size_t blob_size, uint64_t fee) const;
|
||||
|
||||
/**
|
||||
* @brief check that a transaction's outputs conform to current standards
|
||||
*
|
||||
@@ -729,10 +770,11 @@ namespace cryptonote
|
||||
*
|
||||
* @param amounts optional set of amounts to lookup
|
||||
* @param unlocked whether to restrict instances to unlocked ones
|
||||
* @param recent_cutoff timestamp to consider outputs as recent
|
||||
*
|
||||
* @return a set of amount/instances
|
||||
*/
|
||||
std::map<uint64_t, uint64_t> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked) const;
|
||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const;
|
||||
|
||||
/**
|
||||
* @brief perform a check on all key images in the blockchain
|
||||
@@ -801,6 +843,9 @@ namespace cryptonote
|
||||
*/
|
||||
void block_longhash_worker(const uint64_t height, const std::vector<block> &blocks,
|
||||
std::unordered_map<crypto::hash, crypto::hash> &map) const;
|
||||
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
|
||||
// TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage
|
||||
@@ -870,6 +915,8 @@ namespace cryptonote
|
||||
|
||||
bool m_testnet;
|
||||
|
||||
std::atomic<bool> m_cancel;
|
||||
|
||||
/**
|
||||
* @brief collects the keys for all outputs being "spent" as an input
|
||||
*
|
||||
|
||||
@@ -186,6 +186,9 @@ namespace cryptonote
|
||||
ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f");
|
||||
ADD_CHECKPOINT(1000000, "a886ef5149902d8342475fee9bb296341b891ac67c4842f47a833f23c00ed721");
|
||||
ADD_CHECKPOINT(1100000, "3fd720c5c8b3072fc1ccda922dec1ef25f9ed88a1e6ad4103d0fe00b180a5903");
|
||||
ADD_CHECKPOINT(1150000, "1dd16f626d18e1e988490dfd06de5920e22629c972c58b4d8daddea0038627b2");
|
||||
ADD_CHECKPOINT(1200000, "fa7d13a90850882060479d100141ff84286599ae39c3277c8ea784393f882d1f");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace cryptonote {
|
||||
uint64_t prefix;
|
||||
if (!tools::base58::decode_addr(str, prefix, data))
|
||||
{
|
||||
LOG_PRINT_L1("Invalid address format");
|
||||
LOG_PRINT_L2("Invalid address format");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -207,11 +207,11 @@ namespace boost
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, rct::asnlSig &x, const boost::serialization::version_type ver)
|
||||
inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.L1;
|
||||
a & x.s2;
|
||||
a & x.s;
|
||||
a & x.s0;
|
||||
a & x.s1;
|
||||
a & x.ee;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace cryptonote
|
||||
//-----------------------------------------------------------------------------------
|
||||
void core::stop()
|
||||
{
|
||||
graceful_exit();
|
||||
m_blockchain_storage.cancel();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
void core::init_options(boost::program_options::options_description& desc)
|
||||
@@ -142,6 +142,7 @@ namespace cryptonote
|
||||
command_line::add_arg(desc, command_line::arg_db_sync_mode);
|
||||
command_line::add_arg(desc, command_line::arg_show_time_stats);
|
||||
command_line::add_arg(desc, command_line::arg_db_auto_remove_logs);
|
||||
command_line::add_arg(desc, command_line::arg_block_sync_size);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_command_line(const boost::program_options::variables_map& vm)
|
||||
@@ -227,14 +228,14 @@ namespace cryptonote
|
||||
LOG_PRINT_L1("Locking " << lock_path.string());
|
||||
if (!db_lock.try_lock())
|
||||
{
|
||||
LOG_PRINT_L0("Failed to lock " << lock_path.string());
|
||||
LOG_ERROR("Failed to lock " << lock_path.string());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
LOG_PRINT_L0("Error trying to lock " << lock_path.string() << ": " << e.what());
|
||||
LOG_ERROR("Error trying to lock " << lock_path.string() << ": " << e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -243,6 +244,7 @@ namespace cryptonote
|
||||
{
|
||||
db_lock.unlock();
|
||||
db_lock = boost::interprocess::file_lock();
|
||||
LOG_PRINT_L1("Blockchain directory successfully unlocked");
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
@@ -313,7 +315,7 @@ namespace cryptonote
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Attempted to use non-existant database type");
|
||||
LOG_ERROR("Attempted to use non-existent database type");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -386,7 +388,7 @@ namespace cryptonote
|
||||
}
|
||||
catch (const DB_ERROR& e)
|
||||
{
|
||||
LOG_PRINT_L0("Error opening database: " << e.what());
|
||||
LOG_ERROR("Error opening database: " << e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -403,6 +405,10 @@ namespace cryptonote
|
||||
m_blockchain_storage.set_show_time_stats(show_time_stats);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
|
||||
|
||||
block_sync_size = command_line::get_arg(vm, command_line::arg_block_sync_size);
|
||||
if (block_sync_size == 0)
|
||||
block_sync_size = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT;
|
||||
|
||||
// load json & DNS checkpoints, and verify them
|
||||
// with respect to what blocks we already have
|
||||
CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
|
||||
@@ -428,23 +434,10 @@ namespace cryptonote
|
||||
{
|
||||
m_miner.stop();
|
||||
m_mempool.deinit();
|
||||
if (!m_fast_exit)
|
||||
{
|
||||
m_blockchain_storage.deinit();
|
||||
}
|
||||
m_blockchain_storage.deinit();
|
||||
unlock_db_directory();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::set_fast_exit()
|
||||
{
|
||||
m_fast_exit = true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_fast_exit()
|
||||
{
|
||||
return m_fast_exit;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::test_drop_download()
|
||||
{
|
||||
@@ -623,6 +616,34 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
std::pair<uint64_t, uint64_t> core::get_coinbase_tx_sum(const uint64_t start_offset, const size_t count)
|
||||
{
|
||||
std::list<block> blocks;
|
||||
std::list<transaction> txs;
|
||||
std::list<crypto::hash> missed_txs;
|
||||
uint64_t coinbase_amount = 0;
|
||||
uint64_t emission_amount = 0;
|
||||
uint64_t total_fee_amount = 0;
|
||||
uint64_t tx_fee_amount = 0;
|
||||
this->get_blocks(start_offset, count, blocks);
|
||||
BOOST_FOREACH(auto& b, blocks)
|
||||
{
|
||||
coinbase_amount = get_outs_money_amount(b.miner_tx);
|
||||
this->get_transactions(b.tx_hashes, txs, missed_txs);
|
||||
BOOST_FOREACH(const auto& tx, txs)
|
||||
{
|
||||
tx_fee_amount += get_tx_fee(tx);
|
||||
}
|
||||
|
||||
emission_amount += coinbase_amount - tx_fee_amount;
|
||||
total_fee_amount += tx_fee_amount;
|
||||
coinbase_amount = 0;
|
||||
tx_fee_amount = 0;
|
||||
}
|
||||
|
||||
return std::pair<uint64_t, uint64_t>(emission_amount, total_fee_amount);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_inputs_keyimages_diff(const transaction& tx) const
|
||||
{
|
||||
std::unordered_set<crypto::key_image> ki;
|
||||
@@ -688,6 +709,20 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::on_transaction_relayed(const cryptonote::blobdata& tx_blob)
|
||||
{
|
||||
std::list<std::pair<crypto::hash, cryptonote::transaction>> txs;
|
||||
cryptonote::transaction tx;
|
||||
crypto::hash tx_hash, tx_prefix_hash;
|
||||
if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash, tx_prefix_hash))
|
||||
{
|
||||
LOG_ERROR("Failed to parse relayed transaction");
|
||||
return;
|
||||
}
|
||||
txs.push_back(std::make_pair(tx_hash, std::move(tx)));
|
||||
m_mempool.set_relayed(txs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(b, adr, diffic, height, ex_nonce);
|
||||
@@ -723,7 +758,7 @@ namespace cryptonote
|
||||
return m_blockchain_storage.get_random_outs_for_amounts(req, res);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res) const
|
||||
bool core::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res) const
|
||||
{
|
||||
return m_blockchain_storage.get_outs(req, res);
|
||||
}
|
||||
@@ -880,6 +915,11 @@ namespace cryptonote
|
||||
m_mempool.get_transactions(txs);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_pool_transaction(const crypto::hash &id, transaction& tx) const
|
||||
{
|
||||
return m_mempool.get_transaction(id, tx);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const
|
||||
{
|
||||
@@ -965,10 +1005,7 @@ namespace cryptonote
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::set_target_blockchain_height(uint64_t target_blockchain_height)
|
||||
{
|
||||
if (target_blockchain_height > m_target_blockchain_height)
|
||||
{
|
||||
m_target_blockchain_height = target_blockchain_height;
|
||||
}
|
||||
m_target_blockchain_height = target_blockchain_height;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint64_t core::get_target_blockchain_height() const
|
||||
@@ -980,6 +1017,4 @@ namespace cryptonote
|
||||
{
|
||||
raise(SIGTERM);
|
||||
}
|
||||
|
||||
std::atomic<bool> core::m_fast_exit(false);
|
||||
}
|
||||
|
||||
@@ -180,6 +180,11 @@ namespace cryptonote
|
||||
*/
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce);
|
||||
|
||||
/**
|
||||
* @brief called when a transaction is relayed
|
||||
*/
|
||||
virtual void on_transaction_relayed(const cryptonote::blobdata& tx);
|
||||
|
||||
|
||||
/**
|
||||
* @brief gets the miner instance
|
||||
@@ -230,28 +235,10 @@ namespace cryptonote
|
||||
*
|
||||
* Uninitializes the miner instance, transaction pool, and Blockchain
|
||||
*
|
||||
* if m_fast_exit is set, the call to Blockchain::deinit() is not made.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
bool deinit();
|
||||
|
||||
/**
|
||||
* @brief sets fast exit flag
|
||||
*
|
||||
* @note see deinit()
|
||||
*/
|
||||
static void set_fast_exit();
|
||||
|
||||
/**
|
||||
* @brief gets the current state of the fast exit flag
|
||||
*
|
||||
* @return the fast exit flag
|
||||
*
|
||||
* @note see deinit()
|
||||
*/
|
||||
static bool get_fast_exit();
|
||||
|
||||
/**
|
||||
* @brief sets to drop blocks downloaded (for testing)
|
||||
*/
|
||||
@@ -392,6 +379,13 @@ namespace cryptonote
|
||||
* @note see tx_memory_pool::get_transactions
|
||||
*/
|
||||
bool get_pool_transactions(std::list<transaction>& txs) const;
|
||||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_transaction
|
||||
*
|
||||
* @note see tx_memory_pool::get_transaction
|
||||
*/
|
||||
bool get_pool_transaction(const crypto::hash& id, transaction& tx) const;
|
||||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info
|
||||
@@ -477,7 +471,7 @@ namespace cryptonote
|
||||
*
|
||||
* @note see Blockchain::get_outs
|
||||
*/
|
||||
bool get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res) const;
|
||||
bool get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res) const;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -611,6 +605,27 @@ namespace cryptonote
|
||||
*/
|
||||
bool are_key_images_spent(const std::vector<crypto::key_image>& key_im, std::vector<bool> &spent) const;
|
||||
|
||||
/**
|
||||
* @brief get the number of blocks to sync in one go
|
||||
*
|
||||
* @return the number of blocks to sync in one go
|
||||
*/
|
||||
size_t get_block_sync_size() const { return block_sync_size; }
|
||||
|
||||
/**
|
||||
* @brief get the sum of coinbase tx amounts between blocks
|
||||
*
|
||||
* @return the number of blocks to sync in one go
|
||||
*/
|
||||
std::pair<uint64_t, uint64_t> get_coinbase_tx_sum(const uint64_t start_offset, const size_t count);
|
||||
|
||||
/**
|
||||
* @brief get whether we're on testnet or not
|
||||
*
|
||||
* @return are we on testnet?
|
||||
*/
|
||||
bool get_testnet() const { return m_testnet; };
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -757,8 +772,6 @@ namespace cryptonote
|
||||
*/
|
||||
bool unlock_db_directory();
|
||||
|
||||
static std::atomic<bool> m_fast_exit; //!< whether or not to deinit Blockchain on exit
|
||||
|
||||
bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing)
|
||||
|
||||
uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so
|
||||
@@ -798,6 +811,8 @@ namespace cryptonote
|
||||
std::atomic_flag m_checkpoints_updating; //!< set if checkpoints are currently updating to avoid multiple threads attempting to update at once
|
||||
|
||||
boost::interprocess::file_lock db_lock; //!< a lock object for a file lock in the db directory
|
||||
|
||||
size_t block_sync_size;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -320,26 +320,26 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra)
|
||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index)
|
||||
{
|
||||
std::vector<tx_extra_field> tx_extra_fields;
|
||||
parse_tx_extra(tx_extra, tx_extra_fields);
|
||||
|
||||
tx_extra_pub_key pub_key_field;
|
||||
if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field))
|
||||
if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index))
|
||||
return null_pkey;
|
||||
|
||||
return pub_key_field.pub_key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx_prefix)
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx_prefix, size_t pk_index)
|
||||
{
|
||||
return get_tx_pub_key_from_extra(tx_prefix.extra);
|
||||
return get_tx_pub_key_from_extra(tx_prefix.extra, pk_index);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx)
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index)
|
||||
{
|
||||
return get_tx_pub_key_from_extra(tx.extra);
|
||||
return get_tx_pub_key_from_extra(tx.extra, pk_index);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key)
|
||||
@@ -366,7 +366,7 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool remove_extra_nonce_tx_extra(std::vector<uint8_t>& tx_extra)
|
||||
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type)
|
||||
{
|
||||
std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
|
||||
std::istringstream iss(extra_str);
|
||||
@@ -380,7 +380,7 @@ namespace cryptonote
|
||||
tx_extra_field field;
|
||||
bool r = ::do_serialize(ar, field);
|
||||
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
|
||||
if (field.type() != typeid(tx_extra_nonce))
|
||||
if (field.type() != type)
|
||||
::do_serialize(newar, field);
|
||||
|
||||
std::ios_base::iostate state = iss.rdstate();
|
||||
@@ -472,10 +472,7 @@ namespace cryptonote
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct)
|
||||
{
|
||||
std::vector<rct::key> amount_keys;
|
||||
tx.vin.clear();
|
||||
tx.vout.clear();
|
||||
tx.signatures.clear();
|
||||
tx.rct_signatures.type = rct::RCTTypeNull;
|
||||
tx.set_null();
|
||||
amount_keys.clear();
|
||||
|
||||
tx.version = rct ? 2 : 1;
|
||||
@@ -483,6 +480,7 @@ namespace cryptonote
|
||||
|
||||
tx.extra = extra;
|
||||
keypair txkey = keypair::generate();
|
||||
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_pub_key));
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
tx_key = txkey.sec;
|
||||
|
||||
@@ -512,7 +510,7 @@ namespace cryptonote
|
||||
|
||||
std::string extra_nonce;
|
||||
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
|
||||
remove_extra_nonce_tx_extra(tx.extra);
|
||||
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_nonce));
|
||||
if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
|
||||
{
|
||||
LOG_ERROR("Failed to add encrypted payment id to tx extra");
|
||||
@@ -536,8 +534,10 @@ namespace cryptonote
|
||||
|
||||
uint64_t summary_inputs_money = 0;
|
||||
//fill inputs
|
||||
int idx = -1;
|
||||
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
||||
{
|
||||
++idx;
|
||||
if(src_entr.real_output >= src_entr.outputs.size())
|
||||
{
|
||||
LOG_ERROR("real_output index (" << src_entr.real_output << ")bigger than output_keys.size()=" << src_entr.outputs.size());
|
||||
@@ -555,9 +555,11 @@ namespace cryptonote
|
||||
//check that derivated key is equal with real output key
|
||||
if( !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) )
|
||||
{
|
||||
LOG_ERROR("derived public key missmatch with output public key! "<< ENDL << "derived_key:"
|
||||
LOG_ERROR("derived public key mismatch with output public key at index " << idx << ", real out " << src_entr.real_output << "! "<< ENDL << "derived_key:"
|
||||
<< string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:"
|
||||
<< string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second) );
|
||||
LOG_ERROR("amount " << src_entr.amount << ", rct " << src_entr.rct);
|
||||
LOG_ERROR("tx pubkey " << src_entr.real_out_tx_key << ", real_output_in_tx_index " << src_entr.real_output_in_tx_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -615,6 +617,14 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for watch only wallet
|
||||
bool zero_secret_key = true;
|
||||
for (size_t i = 0; i < sizeof(sender_account_keys.m_spend_secret_key); ++i)
|
||||
zero_secret_key &= (sender_account_keys.m_spend_secret_key.data[i] == 0);
|
||||
if (zero_secret_key)
|
||||
{
|
||||
LOG_PRINT_L1("Null secret key, skipping signatures");
|
||||
}
|
||||
|
||||
if (tx.version == 1)
|
||||
{
|
||||
@@ -641,7 +651,8 @@ namespace cryptonote
|
||||
tx.signatures.push_back(std::vector<crypto::signature>());
|
||||
std::vector<crypto::signature>& sigs = tx.signatures.back();
|
||||
sigs.resize(src_entr.outputs.size());
|
||||
crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
if (!zero_secret_key)
|
||||
crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
ss_ring_s << "signatures:" << ENDL;
|
||||
std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;});
|
||||
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output;
|
||||
@@ -652,10 +663,7 @@ namespace cryptonote
|
||||
}
|
||||
else
|
||||
{
|
||||
bool all_rct_inputs = true;
|
||||
size_t n_total_outs = sources[0].outputs.size(); // only for non-simple rct
|
||||
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
||||
all_rct_inputs &= !(src_entr.mask == rct::identity());
|
||||
|
||||
// the non-simple version is slightly smaller, but assumes all real inputs
|
||||
// are on the same index, so can only be used if there just one ring.
|
||||
@@ -873,6 +881,13 @@ namespace cryptonote
|
||||
return pk == out_key.key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_out_to_acc_precomp(const crypto::public_key& spend_public_key, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index)
|
||||
{
|
||||
crypto::public_key pk;
|
||||
derive_public_key(derivation, output_index, spend_public_key, pk);
|
||||
return pk == out_key.key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
{
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
|
||||
|
||||
@@ -62,6 +62,16 @@ namespace cryptonote
|
||||
rct::key mask; //ringct amount mask
|
||||
|
||||
void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(outputs)
|
||||
VARINT_FIELD(real_output)
|
||||
FIELD(real_out_tx_key)
|
||||
VARINT_FIELD(real_output_in_tx_index)
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(rct)
|
||||
FIELD(mask)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_destination_entry
|
||||
@@ -71,6 +81,11 @@ namespace cryptonote
|
||||
|
||||
tx_destination_entry() : amount(0), addr(AUTO_VAL_INIT(addr)) { }
|
||||
tx_destination_entry(uint64_t a, const account_public_address &ad) : amount(a), addr(ad) { }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(addr)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------
|
||||
@@ -78,9 +93,9 @@ namespace cryptonote
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct = false);
|
||||
|
||||
template<typename T>
|
||||
bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field)
|
||||
bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field, size_t index = 0)
|
||||
{
|
||||
auto it = std::find_if(tx_extra_fields.begin(), tx_extra_fields.end(), [](const tx_extra_field& f) { return typeid(T) == f.type(); });
|
||||
auto it = std::find_if(tx_extra_fields.begin(), tx_extra_fields.end(), [&index](const tx_extra_field& f) { return typeid(T) == f.type() && !index--; });
|
||||
if(tx_extra_fields.end() == it)
|
||||
return false;
|
||||
|
||||
@@ -89,17 +104,18 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index = 0);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx, size_t pk_index = 0);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index = 0);
|
||||
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key);
|
||||
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
|
||||
bool remove_extra_nonce_tx_extra(std::vector<uint8_t>& tx_extra);
|
||||
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type);
|
||||
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
|
||||
void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id);
|
||||
bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id);
|
||||
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id);
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index);
|
||||
bool is_out_to_acc_precomp(const crypto::public_key& spend_public_key, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool get_tx_fee(const transaction& tx, uint64_t & fee);
|
||||
|
||||
@@ -278,8 +278,13 @@ namespace cryptonote
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::stop()
|
||||
{
|
||||
LOG_PRINT_L1("Miner has received stop signal");
|
||||
|
||||
if (!is_mining())
|
||||
{
|
||||
LOG_PRINT_L1("Not mining - nothing to stop" );
|
||||
return true;
|
||||
}
|
||||
|
||||
send_stop_signal();
|
||||
CRITICAL_REGION_LOCAL(m_threads_lock);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "common/int-util.h"
|
||||
#include "misc_language.h"
|
||||
#include "warnings.h"
|
||||
#include "common/perf_timer.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated
|
||||
@@ -78,6 +79,7 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_tx(const transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, uint8_t version)
|
||||
{
|
||||
PERF_TIMER(add_tx);
|
||||
if (tx.version == 0)
|
||||
{
|
||||
// v0 never accepted
|
||||
@@ -131,12 +133,8 @@ namespace cryptonote
|
||||
fee = tx.rct_signatures.txnFee;
|
||||
}
|
||||
|
||||
uint64_t needed_fee = blob_size / 1024;
|
||||
needed_fee += (blob_size % 1024) ? 1 : 0;
|
||||
needed_fee *= FEE_PER_KB;
|
||||
if (!kept_by_block && fee < needed_fee)
|
||||
if (!kept_by_block && !m_blockchain.check_fee(blob_size, fee))
|
||||
{
|
||||
LOG_PRINT_L1("transaction fee is not enough: " << print_money(fee) << ", minimum fee: " << print_money(needed_fee));
|
||||
tvc.m_verifivation_failed = true;
|
||||
tvc.m_fee_too_low = true;
|
||||
return false;
|
||||
@@ -207,7 +205,7 @@ namespace cryptonote
|
||||
{
|
||||
//update transactions container
|
||||
auto txd_p = m_transactions.insert(transactions_container::value_type(id, txd));
|
||||
CHECK_AND_ASSERT_MES(txd_p.second, false, "intrnal error: transaction already exists at inserting in memorypool");
|
||||
CHECK_AND_ASSERT_MES(txd_p.second, false, "internal error: transaction already exists at inserting in memorypool");
|
||||
txd_p.first->second.blob_size = blob_size;
|
||||
txd_p.first->second.kept_by_block = kept_by_block;
|
||||
txd_p.first->second.fee = fee;
|
||||
@@ -385,7 +383,10 @@ namespace cryptonote
|
||||
{
|
||||
auto i = m_transactions.find(it->first);
|
||||
if (i != m_transactions.end())
|
||||
{
|
||||
i->second.relayed = true;
|
||||
i->second.last_relayed_time = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
@@ -420,6 +421,8 @@ namespace cryptonote
|
||||
txi.last_failed_height = txd.last_failed_height;
|
||||
txi.last_failed_id_hash = epee::string_tools::pod_to_hex(txd.last_failed_id);
|
||||
txi.receive_time = txd.receive_time;
|
||||
txi.relayed = txd.relayed;
|
||||
txi.last_relayed_time = txd.last_relayed_time;
|
||||
tx_infos.push_back(txi);
|
||||
}
|
||||
|
||||
@@ -689,7 +692,7 @@ namespace cryptonote
|
||||
bool res = tools::unserialize_obj_from_file(*this, state_file_path);
|
||||
if(!res)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to load memory pool from file " << state_file_path);
|
||||
LOG_ERROR("Failed to load memory pool from file " << state_file_path);
|
||||
|
||||
m_transactions.clear();
|
||||
m_txs_by_fee.clear();
|
||||
@@ -710,12 +713,17 @@ namespace cryptonote
|
||||
//TODO: investigate whether only ever returning true is correct
|
||||
bool tx_memory_pool::deinit()
|
||||
{
|
||||
LOG_PRINT_L1("Received signal to deactivate memory pool store");
|
||||
|
||||
if (m_config_folder.empty())
|
||||
{
|
||||
LOG_PRINT_L1("Memory pool store already empty");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!tools::create_directories_if_necessary(m_config_folder))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to create data directory: " << m_config_folder);
|
||||
LOG_ERROR("Failed to create memory pool data directory: " << m_config_folder);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -723,8 +731,14 @@ namespace cryptonote
|
||||
bool res = tools::serialize_obj_to_file(*this, state_file_path);
|
||||
if(!res)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to serialize memory pool to file " << state_file_path);
|
||||
LOG_ERROR("Failed to serialize memory pool to file " << state_file_path);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L1("Memory pool store deactivated successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (bitmonero CXX)
|
||||
project (monero CXX)
|
||||
|
||||
file(GLOB CRYPTONOTE_PROTOCOL *)
|
||||
source_group(cryptonote_protocol FILES ${CRYPTONOTE_PROTOCOL})
|
||||
|
||||
#bitmonero_private_headers(cryptonote_protocol ${CRYPTONOTE_PROTOCOL})
|
||||
bitmonero_add_library(cryptonote_protocol ${CRYPTONOTE_PROTOCOL})
|
||||
#monero_private_headers(cryptonote_protocol ${CRYPTONOTE_PROTOCOL})
|
||||
monero_add_library(cryptonote_protocol ${CRYPTONOTE_PROTOCOL})
|
||||
target_link_libraries(cryptonote_protocol
|
||||
PRIVATE
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
@@ -69,6 +69,8 @@ namespace cryptonote
|
||||
|
||||
uint64_t avg_upload;
|
||||
uint64_t current_upload;
|
||||
|
||||
uint32_t support_flags;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(incoming)
|
||||
@@ -87,6 +89,7 @@ namespace cryptonote
|
||||
KV_SERIALIZE(current_download)
|
||||
KV_SERIALIZE(avg_upload)
|
||||
KV_SERIALIZE(current_upload)
|
||||
KV_SERIALIZE(support_flags)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
@@ -223,5 +226,49 @@ namespace cryptonote
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct NOTIFY_NEW_FLUFFY_BLOCK
|
||||
{
|
||||
const static int ID = BC_COMMANDS_POOL_BASE + 8;
|
||||
|
||||
struct request
|
||||
{
|
||||
block_complete_entry b;
|
||||
uint64_t current_blockchain_height;
|
||||
uint32_t hop;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(b)
|
||||
KV_SERIALIZE(current_blockchain_height)
|
||||
KV_SERIALIZE(hop)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct NOTIFY_REQUEST_FLUFFY_MISSING_TX
|
||||
{
|
||||
const static int ID = BC_COMMANDS_POOL_BASE + 9;
|
||||
|
||||
struct request
|
||||
{
|
||||
block_complete_entry b;
|
||||
uint64_t current_blockchain_height;
|
||||
std::vector<size_t> missing_tx_indices;
|
||||
uint32_t hop;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(b)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missing_tx_indices)
|
||||
KV_SERIALIZE(hop)
|
||||
KV_SERIALIZE(current_blockchain_height)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ namespace cryptonote
|
||||
HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_GET_OBJECTS, &cryptonote_protocol_handler::handle_response_get_objects)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_REQUEST_CHAIN, &cryptonote_protocol_handler::handle_request_chain)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_CHAIN_ENTRY, &cryptonote_protocol_handler::handle_response_chain_entry)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_NEW_FLUFFY_BLOCK, &cryptonote_protocol_handler::handle_notify_new_fluffy_block)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_REQUEST_FLUFFY_MISSING_TX, &cryptonote_protocol_handler::handle_request_fluffy_missing_tx)
|
||||
END_INVOKE_MAP2()
|
||||
|
||||
bool on_idle();
|
||||
@@ -107,6 +109,7 @@ namespace cryptonote
|
||||
bool is_synchronized(){return m_synchronized;}
|
||||
void log_connections();
|
||||
std::list<connection_info> get_connections();
|
||||
void stop();
|
||||
private:
|
||||
//----------------- commands handlers ----------------------------------------------
|
||||
int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context);
|
||||
@@ -115,8 +118,9 @@ namespace cryptonote
|
||||
int handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context);
|
||||
int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context);
|
||||
int handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context);
|
||||
|
||||
|
||||
int handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context);
|
||||
int handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context);
|
||||
|
||||
//----------------- i_bc_protocol_layout ---------------------------------------
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context);
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context);
|
||||
@@ -132,29 +136,30 @@ namespace cryptonote
|
||||
std::atomic<uint32_t> m_syncronized_connections_count;
|
||||
std::atomic<bool> m_synchronized;
|
||||
bool m_one_request = true;
|
||||
std::atomic<bool> m_stopping;
|
||||
|
||||
// static std::ofstream m_logreq;
|
||||
boost::mutex m_buffer_mutex;
|
||||
double get_avg_block_size();
|
||||
boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10);
|
||||
|
||||
template<class t_parametr>
|
||||
bool post_notify(typename t_parametr::request& arg, cryptonote_connection_context& context)
|
||||
template<class t_parameter>
|
||||
bool post_notify(typename t_parameter::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(context) << "] post " << typeid(t_parametr).name() << " -->");
|
||||
LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(context) << "] post " << typeid(t_parameter).name() << " -->");
|
||||
std::string blob;
|
||||
epee::serialization::store_t_to_binary(arg, blob);
|
||||
//handler_response_blocks_now(blob.size()); // XXX
|
||||
return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context);
|
||||
return m_p2p->invoke_notify_to_peer(t_parameter::ID, blob, context);
|
||||
}
|
||||
|
||||
template<class t_parametr>
|
||||
bool relay_post_notify(typename t_parametr::request& arg, cryptonote_connection_context& exlude_context)
|
||||
template<class t_parameter>
|
||||
bool relay_post_notify(typename t_parameter::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(exlude_context) << "] post relay " << typeid(t_parametr).name() << " -->");
|
||||
LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(exclude_context) << "] post relay " << typeid(t_parameter).name() << " -->");
|
||||
std::string arg_buff;
|
||||
epee::serialization::store_t_to_binary(arg, arg_buff);
|
||||
return m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context);
|
||||
return m_p2p->relay_notify_to_all(t_parameter::ID, arg_buff, exclude_context);
|
||||
}
|
||||
|
||||
virtual std::ofstream& get_logreq() const ;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
#include "profile_tools.h"
|
||||
@@ -59,7 +60,8 @@ namespace cryptonote
|
||||
t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore),
|
||||
m_p2p(p_net_layout),
|
||||
m_syncronized_connections_count(0),
|
||||
m_synchronized(false)
|
||||
m_synchronized(false),
|
||||
m_stopping(false)
|
||||
|
||||
{
|
||||
if(!m_p2p)
|
||||
@@ -75,8 +77,6 @@ namespace cryptonote
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::deinit()
|
||||
{
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -126,6 +126,7 @@ namespace cryptonote
|
||||
|
||||
ss << std::setw(30) << std::left << "Remote Host"
|
||||
<< std::setw(20) << "Peer id"
|
||||
<< std::setw(20) << "Support Flags"
|
||||
<< std::setw(30) << "Recv/Sent (inactive,sec)"
|
||||
<< std::setw(25) << "State"
|
||||
<< std::setw(20) << "Livetime(sec)"
|
||||
@@ -136,7 +137,7 @@ namespace cryptonote
|
||||
<< ENDL;
|
||||
|
||||
uint32_t ip;
|
||||
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
|
||||
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
|
||||
{
|
||||
bool local_ip = false;
|
||||
ip = ntohl(cntxt.m_remote_ip);
|
||||
@@ -147,6 +148,7 @@ namespace cryptonote
|
||||
ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
|
||||
epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
|
||||
<< std::setw(20) << std::hex << peer_id
|
||||
<< std::setw(20) << std::hex << support_flags
|
||||
<< std::setw(30) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
|
||||
<< std::setw(25) << get_protocol_state_string(cntxt.m_state)
|
||||
<< std::setw(20) << std::to_string(time(NULL) - cntxt.m_started)
|
||||
@@ -186,7 +188,7 @@ namespace cryptonote
|
||||
{
|
||||
std::list<connection_info> connections;
|
||||
|
||||
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
|
||||
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
|
||||
{
|
||||
connection_info cnx;
|
||||
auto timestamp = time(NULL);
|
||||
@@ -199,6 +201,8 @@ namespace cryptonote
|
||||
std::stringstream peer_id_str;
|
||||
peer_id_str << std::hex << peer_id;
|
||||
peer_id_str >> cnx.peer_id;
|
||||
|
||||
cnx.support_flags = support_flags;
|
||||
|
||||
cnx.recv_count = cntxt.m_recv_cnt;
|
||||
cnx.recv_idle_time = timestamp - cntxt.m_last_recv;
|
||||
@@ -263,7 +267,7 @@ namespace cryptonote
|
||||
if(context.m_state == cryptonote_connection_context::state_synchronizing)
|
||||
return true;
|
||||
|
||||
if(m_core.have_block(hshd.top_id) && !(hshd.current_height < m_core.get_target_blockchain_height()))
|
||||
if(m_core.have_block(hshd.top_id))
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
if(is_inital)
|
||||
@@ -280,8 +284,8 @@ namespace cryptonote
|
||||
int64_t max_block_height = max(static_cast<int64_t>(hshd.current_height),static_cast<int64_t>(m_core.get_current_blockchain_height()));
|
||||
int64_t last_block_v1 = 1009826;
|
||||
int64_t diff_v2 = max_block_height > last_block_v1 ? min(abs(diff), max_block_height - last_block_v1) : 0;
|
||||
LOG_PRINT_CCONTEXT_YELLOW("Sync data returned unknown top block: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height
|
||||
<< " [" << std::abs(diff) << " blocks (" << ((abs(diff) - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V2)) << " days) "
|
||||
LOG_PRINT_CCONTEXT_YELLOW("Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height
|
||||
<< " [Your node is " << std::abs(diff) << " blocks (" << ((abs(diff) - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V2)) << " days) "
|
||||
<< (0 <= diff ? std::string("behind") : std::string("ahead"))
|
||||
<< "] " << ENDL << "SYNCHRONIZATION started", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1));
|
||||
LOG_PRINT_L1("Remote blockchain height: " << hshd.current_height << ", id: " << hshd.top_id);
|
||||
@@ -363,6 +367,312 @@ namespace cryptonote
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_FLUFFY_BLOCK (hop " << arg.hop << ")");
|
||||
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||
return 1;
|
||||
|
||||
m_core.pause_mine();
|
||||
|
||||
block new_block;
|
||||
transaction miner_tx;
|
||||
if(parse_and_validate_block_from_blob(arg.b.block, new_block))
|
||||
{
|
||||
// This is a seccond notification, we must have asked for some missing tx
|
||||
if(!context.m_requested_objects.empty())
|
||||
{
|
||||
// What we asked for != to what we received ..
|
||||
if(context.m_requested_objects.size() != arg.b.txs.size())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT
|
||||
(
|
||||
"NOTIFY_NEW_FLUFFY_BLOCK -> request/response mismatch, "
|
||||
<< "block = " << epee::string_tools::pod_to_hex(get_blob_hash(arg.b.block))
|
||||
<< ", requested = " << context.m_requested_objects.size()
|
||||
<< ", received = " << new_block.tx_hashes.size()
|
||||
<< ", dropping connection"
|
||||
);
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
m_core.resume_mine();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::list<blobdata> have_tx;
|
||||
|
||||
// Instead of requesting missing transactions by hash like BTC,
|
||||
// we do it by index (thanks to a suggestion from moneromooo) because
|
||||
// we're way cooler .. and also because they're smaller than hashes.
|
||||
//
|
||||
// Also, remember to pepper some whitespace changes around to bother
|
||||
// moneromooo ... only because I <3 him.
|
||||
std::vector<size_t> need_tx_indices;
|
||||
|
||||
transaction tx;
|
||||
crypto::hash tx_hash;
|
||||
|
||||
BOOST_FOREACH(auto& tx_blob, arg.b.txs)
|
||||
{
|
||||
if(parse_and_validate_tx_from_blob(tx_blob, tx))
|
||||
{
|
||||
try
|
||||
{
|
||||
if(!get_transaction_hash(tx, tx_hash))
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1
|
||||
(
|
||||
"NOTIFY_NEW_FLUFFY_BLOCK: get_transaction_hash failed"
|
||||
<< ", dropping connection"
|
||||
);
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
m_core.resume_mine();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1
|
||||
(
|
||||
"NOTIFY_NEW_FLUFFY_BLOCK: get_transaction_hash failed"
|
||||
<< ", exception thrown"
|
||||
<< ", dropping connection"
|
||||
);
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
m_core.resume_mine();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// hijacking m_requested objects in connection context to patch up
|
||||
// a possible DOS vector pointed out by @monero-moo where peers keep
|
||||
// sending (0...n-1) transactions.
|
||||
// If requested objects is not empty, then we must have asked for
|
||||
// some missing transacionts, make sure that they're all there.
|
||||
//
|
||||
// Can I safely re-use this field? I think so, but someone check me!
|
||||
if(!context.m_requested_objects.empty())
|
||||
{
|
||||
auto req_tx_it = context.m_requested_objects.find(tx_hash);
|
||||
if(req_tx_it == context.m_requested_objects.end())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT
|
||||
(
|
||||
"Peer sent wrong transaction (NOTIFY_NEW_FLUFFY_BLOCK): "
|
||||
<< "transaction with id = " << tx_hash << " wasn't requested, "
|
||||
<< "dropping connection"
|
||||
);
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
m_core.resume_mine();
|
||||
return 1;
|
||||
}
|
||||
|
||||
context.m_requested_objects.erase(req_tx_it);
|
||||
}
|
||||
|
||||
// we might already have the tx that the peer
|
||||
// sent in our pool, so don't verify again..
|
||||
if(!m_core.get_pool_transaction(tx_hash, tx))
|
||||
{
|
||||
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true) || tvc.m_verifivation_failed)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
m_core.resume_mine();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// future todo:
|
||||
// tx should only not be added to pool if verification failed, but
|
||||
// maybe in the future could not be added for other reasons
|
||||
// according to monero-moo so keep track of these separately ..
|
||||
//
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR_CCONTEXT
|
||||
(
|
||||
"sent wrong tx: failed to parse and validate transaction: \r\n"
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(tx_blob)
|
||||
<< "\r\n dropping connection"
|
||||
);
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
m_core.resume_mine();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// The initial size equality check could have been fooled if the sender
|
||||
// gave us the number of transactions we asked for, but not the right
|
||||
// ones. This check make sure the transactions we asked for were the
|
||||
// ones we received.
|
||||
if(context.m_requested_objects.size())
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_RED
|
||||
(
|
||||
"NOTIFY_NEW_FLUFFY_BLOCK: peer sent the number of transaction requested"
|
||||
<< ", but not the actual transactions requested"
|
||||
<< ", context.m_requested_objects.size() = " << context.m_requested_objects.size()
|
||||
<< ", dropping connection", LOG_LEVEL_0
|
||||
);
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
m_core.resume_mine();
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t tx_idx = 0;
|
||||
BOOST_FOREACH(auto& tx_hash, new_block.tx_hashes)
|
||||
{
|
||||
if(m_core.get_pool_transaction(tx_hash, tx))
|
||||
{
|
||||
have_tx.push_back(tx_to_blob(tx));
|
||||
}
|
||||
else
|
||||
{
|
||||
need_tx_indices.push_back(tx_idx);
|
||||
}
|
||||
|
||||
++tx_idx;
|
||||
}
|
||||
|
||||
if(!need_tx_indices.empty()) // drats, we don't have everything..
|
||||
{
|
||||
// request non-mempool txs
|
||||
NOTIFY_REQUEST_FLUFFY_MISSING_TX::request missing_tx_req;
|
||||
missing_tx_req.b = arg.b;
|
||||
missing_tx_req.hop = arg.hop;
|
||||
missing_tx_req.current_blockchain_height = arg.current_blockchain_height;
|
||||
missing_tx_req.missing_tx_indices = std::move(need_tx_indices);
|
||||
|
||||
m_core.resume_mine();
|
||||
post_notify<NOTIFY_REQUEST_FLUFFY_MISSING_TX>(missing_tx_req, context);
|
||||
}
|
||||
else // whoo-hoo we've got em all ..
|
||||
{
|
||||
block_complete_entry b;
|
||||
b.block = arg.b.block;
|
||||
b.txs = have_tx;
|
||||
|
||||
std::list<block_complete_entry> blocks;
|
||||
blocks.push_back(b);
|
||||
m_core.prepare_handle_incoming_blocks(blocks);
|
||||
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block
|
||||
m_core.cleanup_handle_incoming_blocks(true);
|
||||
m_core.resume_mine();
|
||||
|
||||
if( bvc.m_verifivation_failed )
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
if( bvc.m_added_to_main_chain )
|
||||
{
|
||||
++arg.hop;
|
||||
//TODO: Add here announce protocol usage
|
||||
NOTIFY_NEW_BLOCK::request reg_arg = AUTO_VAL_INIT(reg_arg);
|
||||
reg_arg.hop = arg.hop;
|
||||
reg_arg.current_blockchain_height = arg.current_blockchain_height;
|
||||
reg_arg.b.block = b.block;
|
||||
relay_block(reg_arg, context);
|
||||
}
|
||||
else if( bvc.m_marked_as_orphaned )
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_synchronizing;
|
||||
NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized<NOTIFY_REQUEST_CHAIN::request>();
|
||||
m_core.get_short_chain_history(r.block_ids);
|
||||
LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR_CCONTEXT
|
||||
(
|
||||
"sent wrong block: failed to parse and validate block: \r\n"
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(arg.b.block)
|
||||
<< "\r\n dropping connection"
|
||||
);
|
||||
|
||||
m_core.resume_mine();
|
||||
m_p2p->drop_connection(context);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_FLUFFY_MISSING_TX");
|
||||
|
||||
std::list<block> local_blocks;
|
||||
std::list<transaction> local_txs;
|
||||
if(!m_core.get_blocks(arg.current_blockchain_height - 1, 1, local_blocks, local_txs))
|
||||
{
|
||||
|
||||
LOG_ERROR_CCONTEXT
|
||||
(
|
||||
"Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
|
||||
<< ", get_blocks( start_offset = " << (arg.current_blockchain_height - 1) << " ) failed"
|
||||
<< ", dropping connection"
|
||||
);
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
|
||||
fluffy_response.b = arg.b;
|
||||
fluffy_response.current_blockchain_height = m_core.get_current_blockchain_height();
|
||||
fluffy_response.hop = arg.hop;
|
||||
size_t local_txs_count = local_txs.size();
|
||||
BOOST_FOREACH(auto& tx_idx, arg.missing_tx_indices)
|
||||
{
|
||||
if(tx_idx < local_txs_count)
|
||||
{
|
||||
fluffy_response.b.txs.push_back(t_serializable_object_to_blob( *(std::next(local_txs.begin(), tx_idx)) ));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR_CCONTEXT
|
||||
(
|
||||
"Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
|
||||
<< ", request is asking for a tx whose index is out of bounds "
|
||||
<< ", tx index = " << tx_idx << ", block_height = " << arg.current_blockchain_height
|
||||
<< ", dropping connection"
|
||||
);
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_PRINT_CCONTEXT_L2
|
||||
(
|
||||
"-->>NOTIFY_RESPONSE_FLUFFY_MISSING_TX: "
|
||||
<< ", txs.size()=" << fluffy_response.b.txs.size()
|
||||
<< ", rsp.current_blockchain_height=" << fluffy_response.current_blockchain_height
|
||||
);
|
||||
|
||||
post_notify<NOTIFY_NEW_FLUFFY_BLOCK>(fluffy_response, context);
|
||||
return 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_TRANSACTIONS");
|
||||
@@ -484,6 +794,11 @@ namespace cryptonote
|
||||
size_t count = 0;
|
||||
BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
|
||||
{
|
||||
if (m_stopping)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
++count;
|
||||
block b;
|
||||
if(!parse_and_validate_block_from_blob(block_entry.block, b))
|
||||
@@ -548,6 +863,12 @@ namespace cryptonote
|
||||
m_core.prepare_handle_incoming_blocks(arg.blocks);
|
||||
BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
|
||||
{
|
||||
if (m_stopping)
|
||||
{
|
||||
m_core.cleanup_handle_incoming_blocks();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// process transactions
|
||||
TIME_MEASURE_START(transactions_process_time);
|
||||
BOOST_FOREACH(auto& tx_blob, block_entry.txs)
|
||||
@@ -624,6 +945,7 @@ namespace cryptonote
|
||||
if(!m_core.find_blockchain_supplement(arg.block_ids, r))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
|
||||
@@ -650,9 +972,9 @@ namespace cryptonote
|
||||
size_t count = 0;
|
||||
auto it = context.m_needed_objects.begin();
|
||||
|
||||
size_t count_limit = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT;
|
||||
const size_t count_limit = m_core.get_block_sync_size();
|
||||
_note_c("net/req-calc" , "Setting count_limit: " << count_limit);
|
||||
while(it != context.m_needed_objects.end() && count < BLOCKS_SYNCHRONIZING_DEFAULT_COUNT)
|
||||
while(it != context.m_needed_objects.end() && count < count_limit)
|
||||
{
|
||||
if( !(check_having_blocks && m_core.have_block(*it)))
|
||||
{
|
||||
@@ -776,12 +1098,51 @@ namespace cryptonote
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
return relay_post_notify<NOTIFY_NEW_BLOCK>(arg, exclude_context);
|
||||
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_arg = AUTO_VAL_INIT(fluffy_arg);
|
||||
fluffy_arg.hop = arg.hop;
|
||||
fluffy_arg.current_blockchain_height = arg.current_blockchain_height;
|
||||
std::list<blobdata> fluffy_txs;
|
||||
fluffy_arg.b = arg.b;
|
||||
fluffy_arg.b.txs = fluffy_txs;
|
||||
|
||||
// pre-serialize them
|
||||
std::string fullBlob, fluffyBlob;
|
||||
epee::serialization::store_t_to_binary(arg, fullBlob);
|
||||
epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob);
|
||||
|
||||
// sort peers between fluffy ones and others
|
||||
std::list<boost::uuids::uuid> fullConnections, fluffyConnections;
|
||||
m_p2p->for_each_connection([this, &arg, &fluffy_arg, &exclude_context, &fullConnections, &fluffyConnections](connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)
|
||||
{
|
||||
if (peer_id && exclude_context.m_connection_id != context.m_connection_id)
|
||||
{
|
||||
if(m_core.get_testnet() && (support_flags & P2P_SUPPORT_FLAG_FLUFFY_BLOCKS))
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_YELLOW("PEER SUPPORTS FLUFFY BLOCKS - RELAYING THIN/COMPACT WHATEVER BLOCK", LOG_LEVEL_1);
|
||||
fluffyConnections.push_back(context.m_connection_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_YELLOW("PEER DOESN'T SUPPORT FLUFFY BLOCKS - RELAYING FULL BLOCK", LOG_LEVEL_1);
|
||||
fullConnections.push_back(context.m_connection_id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// send fluffy ones first, we want to encourage people to run that
|
||||
m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, fluffyBlob, fluffyConnections);
|
||||
m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, fullBlob, fullConnections);
|
||||
|
||||
return 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
// no check for success, so tell core they're relayed unconditionally
|
||||
for(auto tx_blob_it = arg.txs.begin(); tx_blob_it!=arg.txs.end(); ++tx_blob_it)
|
||||
m_core.on_transaction_relayed(*tx_blob_it);
|
||||
return relay_post_notify<NOTIFY_NEW_TRANSACTIONS>(arg, exclude_context);
|
||||
}
|
||||
|
||||
@@ -797,5 +1158,11 @@ namespace cryptonote
|
||||
(*logreq) << "log used" << std::endl;
|
||||
return *logreq;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::stop()
|
||||
{
|
||||
m_stopping = true;
|
||||
m_core.stop();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -74,9 +74,9 @@ set(daemon_private_headers
|
||||
../p2p/p2p_protocol_defs.h
|
||||
../p2p/stdafx.h)
|
||||
|
||||
bitmonero_private_headers(daemon
|
||||
monero_private_headers(daemon
|
||||
${daemon_private_headers})
|
||||
bitmonero_add_executable(daemon
|
||||
monero_add_executable(daemon
|
||||
${daemon_sources}
|
||||
${daemon_headers}
|
||||
${daemon_private_headers}
|
||||
|
||||
@@ -222,6 +222,13 @@ bool t_command_parser_executor::print_transaction_pool_short(const std::vector<s
|
||||
return m_executor.print_transaction_pool_short();
|
||||
}
|
||||
|
||||
bool t_command_parser_executor::print_transaction_pool_stats(const std::vector<std::string>& args)
|
||||
{
|
||||
if (!args.empty()) return false;
|
||||
|
||||
return m_executor.print_transaction_pool_stats();
|
||||
}
|
||||
|
||||
bool t_command_parser_executor::start_mining(const std::vector<std::string>& args)
|
||||
{
|
||||
if(!args.size())
|
||||
@@ -336,12 +343,6 @@ bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& a
|
||||
return m_executor.set_limit_down(limit);
|
||||
}
|
||||
|
||||
bool t_command_parser_executor::fast_exit(const std::vector<std::string>& args)
|
||||
{
|
||||
if (!args.empty()) return false;
|
||||
return m_executor.fast_exit();
|
||||
}
|
||||
|
||||
bool t_command_parser_executor::out_peers(const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty()) return false;
|
||||
@@ -458,5 +459,27 @@ bool t_command_parser_executor::output_histogram(const std::vector<std::string>&
|
||||
return m_executor.output_histogram(min_count, max_count);
|
||||
}
|
||||
|
||||
bool t_command_parser_executor::print_coinbase_tx_sum(const std::vector<std::string>& args)
|
||||
{
|
||||
if(!args.size())
|
||||
{
|
||||
std::cout << "need block height parameter" << std::endl;
|
||||
return false;
|
||||
}
|
||||
uint64_t height = 0;
|
||||
uint64_t count = 0;
|
||||
if(!epee::string_tools::get_xtype_from_string(height, args[0]))
|
||||
{
|
||||
std::cout << "wrong starter block height parameter" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(args.size() >1 && !epee::string_tools::get_xtype_from_string(count, args[1]))
|
||||
{
|
||||
std::cout << "wrong count parameter" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_executor.print_coinbase_tx_sum(height, count);
|
||||
}
|
||||
|
||||
} // namespace daemonize
|
||||
|
||||
@@ -84,6 +84,8 @@ public:
|
||||
|
||||
bool print_transaction_pool_short(const std::vector<std::string>& args);
|
||||
|
||||
bool print_transaction_pool_stats(const std::vector<std::string>& args);
|
||||
|
||||
bool start_mining(const std::vector<std::string>& args);
|
||||
|
||||
bool stop_mining(const std::vector<std::string>& args);
|
||||
@@ -98,8 +100,6 @@ public:
|
||||
|
||||
bool set_limit_down(const std::vector<std::string>& args);
|
||||
|
||||
bool fast_exit(const std::vector<std::string>& args);
|
||||
|
||||
bool out_peers(const std::vector<std::string>& args);
|
||||
|
||||
bool start_save_graph(const std::vector<std::string>& args);
|
||||
@@ -117,6 +117,8 @@ public:
|
||||
bool flush_txpool(const std::vector<std::string>& args);
|
||||
|
||||
bool output_histogram(const std::vector<std::string>& args);
|
||||
|
||||
bool print_coinbase_tx_sum(const std::vector<std::string>& args);
|
||||
};
|
||||
|
||||
} // namespace daemonize
|
||||
|
||||
@@ -110,6 +110,11 @@ t_command_server::t_command_server(
|
||||
, std::bind(&t_command_parser_executor::print_transaction_pool_short, &m_parser, p::_1)
|
||||
, "Print transaction pool (short format)"
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"print_pool_stats"
|
||||
, std::bind(&t_command_parser_executor::print_transaction_pool_stats, &m_parser, p::_1)
|
||||
, "Print transaction pool statistics"
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"show_hr"
|
||||
, std::bind(&t_command_parser_executor::show_hash_rate, &m_parser, p::_1)
|
||||
@@ -170,11 +175,6 @@ t_command_server::t_command_server(
|
||||
, std::bind(&t_command_parser_executor::set_limit_down, &m_parser, p::_1)
|
||||
, "limit <kB/s> - Set download limit"
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"fast_exit"
|
||||
, std::bind(&t_command_parser_executor::fast_exit, &m_parser, p::_1)
|
||||
, "Exit"
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"out_peers"
|
||||
, std::bind(&t_command_parser_executor::out_peers, &m_parser, p::_1)
|
||||
@@ -220,6 +220,11 @@ t_command_server::t_command_server(
|
||||
, std::bind(&t_command_parser_executor::output_histogram, &m_parser, p::_1)
|
||||
, "Print output histogram (amount, instances)"
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"print_coinbase_tx_sum"
|
||||
, std::bind(&t_command_parser_executor::print_coinbase_tx_sum, &m_parser, p::_1)
|
||||
, "Print sum of coinbase transactions (start height, block count)"
|
||||
);
|
||||
}
|
||||
|
||||
bool t_command_server::process_command_str(const std::string& cmd)
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace daemonize
|
||||
boost::program_options::variables_map const & vm
|
||||
)
|
||||
{
|
||||
LOG_PRINT_L0("Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL);
|
||||
LOG_PRINT_L0("Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ") Daemonised");
|
||||
return t_daemon{vm};
|
||||
}
|
||||
|
||||
|
||||
@@ -69,12 +69,13 @@ public:
|
||||
|
||||
~t_protocol()
|
||||
{
|
||||
LOG_PRINT_L0("Deinitializing cryptonote_protocol...");
|
||||
LOG_PRINT_L0("Stopping cryptonote protocol...");
|
||||
try {
|
||||
m_protocol.deinit();
|
||||
m_protocol.set_p2p_endpoint(nullptr);
|
||||
LOG_PRINT_L0("Cryptonote protocol stopped successfully");
|
||||
} catch (...) {
|
||||
LOG_PRINT_L0("Failed to deinitialize protocol...");
|
||||
LOG_ERROR("Failed to stop cryptonote protocol!");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace {
|
||||
tools::msg_writer() << boost::format("%-10s %-25s %-25s %s") % prefix % id_str % addr_str % elapsed;
|
||||
}
|
||||
|
||||
void print_block_header(cryptonote::block_header_responce const & header)
|
||||
void print_block_header(cryptonote::block_header_response const & header)
|
||||
{
|
||||
tools::success_msg_writer()
|
||||
<< "timestamp: " << boost::lexical_cast<std::string>(header.timestamp) << std::endl
|
||||
@@ -296,6 +296,16 @@ static std::string get_fork_extra_info(uint64_t t, uint64_t now, uint64_t block_
|
||||
return "";
|
||||
}
|
||||
|
||||
static float get_sync_percentage(const cryptonote::COMMAND_RPC_GET_INFO::response &ires)
|
||||
{
|
||||
uint64_t height = ires.height;
|
||||
uint64_t target_height = ires.target_height ? ires.target_height < ires.height ? ires.height : ires.target_height : ires.height;
|
||||
float pc = 100.0f * height / target_height;
|
||||
if (height < target_height && pc > 99.9f)
|
||||
return 99.9f; // to avoid 100% when not fully synced
|
||||
return pc;
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::show_status() {
|
||||
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
|
||||
cryptonote::COMMAND_RPC_GET_INFO::response ires;
|
||||
@@ -356,7 +366,7 @@ bool t_rpc_command_executor::show_status() {
|
||||
tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s, %s, net hash %s, v%u%s, %s, %u+%u connections")
|
||||
% (unsigned long long)ires.height
|
||||
% (unsigned long long)(ires.target_height >= ires.height ? ires.target_height : ires.height)
|
||||
% (100.0f * ires.height / (ires.target_height ? ires.target_height < ires.height ? ires.height : ires.target_height : ires.height))
|
||||
% get_sync_percentage(ires)
|
||||
% (ires.testnet ? "testnet" : "mainnet")
|
||||
% (mining_busy ? "syncing" : mres.active ? "mining at " + get_mining_speed(mres.speed) : "not mining")
|
||||
% get_mining_speed(ires.difficulty / ires.target)
|
||||
@@ -394,6 +404,7 @@ bool t_rpc_command_executor::print_connections() {
|
||||
|
||||
tools::msg_writer() << std::setw(30) << std::left << "Remote Host"
|
||||
<< std::setw(20) << "Peer id"
|
||||
<< std::setw(20) << "Support Flags"
|
||||
<< std::setw(30) << "Recv/Sent (inactive,sec)"
|
||||
<< std::setw(25) << "State"
|
||||
<< std::setw(20) << "Livetime(sec)"
|
||||
@@ -412,6 +423,7 @@ bool t_rpc_command_executor::print_connections() {
|
||||
//<< std::setw(30) << std::left << in_out
|
||||
<< std::setw(30) << std::left << address
|
||||
<< std::setw(20) << info.peer_id
|
||||
<< std::setw(20) << info.support_flags
|
||||
<< std::setw(30) << std::to_string(info.recv_count) + "(" + std::to_string(info.recv_idle_time) + ")/" + std::to_string(info.send_count) + "(" + std::to_string(info.send_idle_time) + ")"
|
||||
<< std::setw(25) << info.state
|
||||
<< std::setw(20) << info.live_time
|
||||
@@ -430,11 +442,6 @@ bool t_rpc_command_executor::print_connections() {
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, uint64_t end_block_index) {
|
||||
|
||||
// this function appears to not exist in the json rpc api, and so is commented
|
||||
// until such a time as it does.
|
||||
|
||||
/*
|
||||
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request req;
|
||||
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response res;
|
||||
epee::json_rpc::error error_resp;
|
||||
@@ -453,25 +460,26 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_rpc_server->on_getblockheadersrange(req, res, error_resp) || res.status != CORE_RPC_STATUS_OK)
|
||||
if (!m_rpc_server->on_get_block_headers_range(req, res, error_resp) || res.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
tools::fail_msg_writer() << fail_message.c_str();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
for (auto & header : res.headers)
|
||||
{
|
||||
if (!first)
|
||||
std::cout << std::endl;
|
||||
std::cout
|
||||
<< "major version: " << header.major_version << std::endl
|
||||
<< "minor version: " << header.minor_version << std::endl
|
||||
<< "major version: " << (unsigned)header.major_version << ", minor version: " << (unsigned)header.minor_version << std::endl
|
||||
<< "height: " << header.height << ", timestamp: " << header.timestamp << ", difficulty: " << header.difficulty << std::endl
|
||||
<< "block id: " << header.hash << std::endl
|
||||
<< "previous block id: " << header.prev_hash << std::endl
|
||||
<< "difficulty: " << header.difficulty << ", nonce " << header.nonce << std::endl;
|
||||
<< "block id: " << header.hash << ", previous block id: " << header.prev_hash << std::endl
|
||||
<< "difficulty: " << header.difficulty << ", nonce " << header.nonce << ", reward " << cryptonote::print_money(header.reward) << std::endl;
|
||||
first = false;
|
||||
}
|
||||
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -728,6 +736,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() {
|
||||
<< "blob_size: " << tx_info.blob_size << std::endl
|
||||
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
|
||||
<< "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl
|
||||
<< "relayed: " << [&](const cryptonote::tx_info &tx_info)->std::string { if (!tx_info.relayed) return "no"; return boost::lexical_cast<std::string>(tx_info.last_relayed_time) + " (" + get_human_time_ago(tx_info.last_relayed_time, now) + ")"; } (tx_info) << std::endl
|
||||
<< "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl
|
||||
<< "max_used_block_height: " << tx_info.max_used_block_height << std::endl
|
||||
<< "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl
|
||||
@@ -807,6 +816,7 @@ bool t_rpc_command_executor::print_transaction_pool_short() {
|
||||
<< "blob_size: " << tx_info.blob_size << std::endl
|
||||
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
|
||||
<< "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl
|
||||
<< "relayed: " << [&](const cryptonote::tx_info &tx_info)->std::string { if (!tx_info.relayed) return "no"; return boost::lexical_cast<std::string>(tx_info.last_relayed_time) + " (" + get_human_time_ago(tx_info.last_relayed_time, now) + ")"; } (tx_info) << std::endl
|
||||
<< "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl
|
||||
<< "max_used_block_height: " << tx_info.max_used_block_height << std::endl
|
||||
<< "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl
|
||||
@@ -818,6 +828,62 @@ bool t_rpc_command_executor::print_transaction_pool_short() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::print_transaction_pool_stats() {
|
||||
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::request req;
|
||||
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::response res;
|
||||
|
||||
std::string fail_message = "Problem fetching transaction pool";
|
||||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->rpc_request(req, res, "/get_transaction_pool", fail_message.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_rpc_server->on_get_transaction_pool(req, res) || res.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
tools::fail_msg_writer() << fail_message.c_str();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t n_transactions = res.transactions.size();
|
||||
size_t bytes = 0, min_bytes = 0, max_bytes = 0;
|
||||
size_t n_not_relayed = 0;
|
||||
uint64_t fee = 0;
|
||||
uint64_t oldest = 0;
|
||||
size_t n_10m = 0;
|
||||
size_t n_failing = 0;
|
||||
const uint64_t now = time(NULL);
|
||||
for (const auto &tx_info: res.transactions)
|
||||
{
|
||||
bytes += tx_info.blob_size;
|
||||
if (min_bytes == 0 || tx_info.blob_size < min_bytes)
|
||||
min_bytes = tx_info.blob_size;
|
||||
if (tx_info.blob_size > max_bytes)
|
||||
max_bytes = tx_info.blob_size;
|
||||
if (!tx_info.relayed)
|
||||
n_not_relayed++;
|
||||
fee += tx_info.fee;
|
||||
if (oldest == 0 || tx_info.receive_time < oldest)
|
||||
oldest = tx_info.receive_time;
|
||||
if (tx_info.receive_time < now - 600)
|
||||
n_10m++;
|
||||
if (tx_info.last_failed_height)
|
||||
++n_failing;
|
||||
}
|
||||
size_t avg_bytes = n_transactions ? bytes / n_transactions : 0;
|
||||
|
||||
tools::msg_writer() << n_transactions << " tx(es), " << bytes << " bytes total (min " << min_bytes << ", max " << max_bytes << ", avg " << avg_bytes << ")" << std::endl
|
||||
<< "fees " << cryptonote::print_money(fee) << " (avg " << cryptonote::print_money(n_transactions ? fee / n_transactions : 0) << " per tx)" << std::endl
|
||||
<< n_not_relayed << " not relayed, " << n_failing << " failing, " << n_10m << " older than 10 minutes (oldest " << (oldest == 0 ? "-" : get_human_time_ago(oldest, now)) << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet) {
|
||||
cryptonote::COMMAND_RPC_START_MINING::request req;
|
||||
cryptonote::COMMAND_RPC_START_MINING::response res;
|
||||
@@ -979,34 +1045,6 @@ bool t_rpc_command_executor::set_limit_down(int limit)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::fast_exit()
|
||||
{
|
||||
cryptonote::COMMAND_RPC_FAST_EXIT::request req;
|
||||
cryptonote::COMMAND_RPC_FAST_EXIT::response res;
|
||||
|
||||
std::string fail_message = "Daemon did not stop";
|
||||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->rpc_request(req, res, "/fast_exit", fail_message.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!m_rpc_server->on_fast_exit(req, res) || res.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
tools::fail_msg_writer() << fail_message.c_str();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
tools::success_msg_writer() << "Daemon stopped";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::out_peers(uint64_t limit)
|
||||
{
|
||||
cryptonote::COMMAND_RPC_OUT_PEERS::request req;
|
||||
@@ -1265,6 +1303,8 @@ bool t_rpc_command_executor::output_histogram(uint64_t min_count, uint64_t max_c
|
||||
|
||||
req.min_count = min_count;
|
||||
req.max_count = max_count;
|
||||
req.unlocked = false;
|
||||
req.recent_cutoff = 0;
|
||||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
@@ -1283,14 +1323,49 @@ bool t_rpc_command_executor::output_histogram(uint64_t min_count, uint64_t max_c
|
||||
}
|
||||
|
||||
std::sort(res.histogram.begin(), res.histogram.end(),
|
||||
[](const cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry &e1, const cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry &e2)->bool { return e1.instances < e2.instances; });
|
||||
[](const cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry &e1, const cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry &e2)->bool { return e1.total_instances < e2.total_instances; });
|
||||
for (const auto &e: res.histogram)
|
||||
{
|
||||
tools::msg_writer() << e.instances << " " << cryptonote::print_money(e.amount);
|
||||
tools::msg_writer() << e.total_instances << " " << cryptonote::print_money(e.amount);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::print_coinbase_tx_sum(uint64_t height, uint64_t count)
|
||||
{
|
||||
cryptonote::COMMAND_RPC_GET_COINBASE_TX_SUM::request req;
|
||||
cryptonote::COMMAND_RPC_GET_COINBASE_TX_SUM::response res;
|
||||
epee::json_rpc::error error_resp;
|
||||
|
||||
req.height = height;
|
||||
req.count = count;
|
||||
|
||||
std::string fail_message = "Unsuccessful";
|
||||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->json_rpc_request(req, res, "get_coinbase_tx_sum", fail_message.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_rpc_server->on_get_coinbase_tx_sum(req, res, error_resp))
|
||||
{
|
||||
tools::fail_msg_writer() << fail_message.c_str();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
tools::msg_writer() << "Sum of coinbase transactions between block heights ["
|
||||
<< height << ", " << (height + count) << ") is "
|
||||
<< cryptonote::print_money(res.emission_amount + res.fee_amount) << " "
|
||||
<< "consisting of " << cryptonote::print_money(res.emission_amount)
|
||||
<< " in emissions, and " << cryptonote::print_money(res.fee_amount) << " in fees";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}// namespace daemonize
|
||||
|
||||
@@ -96,6 +96,8 @@ public:
|
||||
|
||||
bool print_transaction_pool_short();
|
||||
|
||||
bool print_transaction_pool_stats();
|
||||
|
||||
bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, bool testnet);
|
||||
|
||||
bool stop_mining();
|
||||
@@ -116,8 +118,6 @@ public:
|
||||
|
||||
bool set_limit_down(int limit);
|
||||
|
||||
bool fast_exit();
|
||||
|
||||
bool out_peers(uint64_t limit);
|
||||
|
||||
bool start_save_graph();
|
||||
@@ -135,6 +135,8 @@ public:
|
||||
bool flush_txpool(const std::string &txid);
|
||||
|
||||
bool output_histogram(uint64_t min_count, uint64_t max_count);
|
||||
|
||||
bool print_coinbase_tx_sum(uint64_t height, uint64_t count);
|
||||
};
|
||||
|
||||
} // namespace daemonize
|
||||
|
||||
@@ -54,9 +54,9 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
bitmonero_private_headers(daemonizer
|
||||
monero_private_headers(daemonizer
|
||||
${daemonizer_private_headers})
|
||||
bitmonero_add_library(daemonizer
|
||||
monero_add_library(daemonizer
|
||||
${daemonizer_sources}
|
||||
${daemonizer_headers}
|
||||
${daemonizer_private_headers})
|
||||
|
||||
@@ -44,9 +44,9 @@ set(mnemonics_private_headers
|
||||
singleton.h
|
||||
spanish.h)
|
||||
|
||||
bitmonero_private_headers(mnemonics
|
||||
monero_private_headers(mnemonics
|
||||
${mnemonics_private_headers})
|
||||
bitmonero_add_library(mnemonics
|
||||
monero_add_library(mnemonics
|
||||
${mnemonics_sources}
|
||||
${mnemonics_headers}
|
||||
${mnemonics_private_headers})
|
||||
|
||||
@@ -106,6 +106,12 @@ namespace Language
|
||||
trimmed_word_map = new std::unordered_map<std::string, uint32_t>;
|
||||
unique_prefix_length = 4;
|
||||
}
|
||||
virtual ~Base()
|
||||
{
|
||||
delete word_list;
|
||||
delete word_map;
|
||||
delete trimmed_word_map;
|
||||
}
|
||||
/*!
|
||||
* \brief Returns a pointer to the word list.
|
||||
* \return A pointer to the word list.
|
||||
|
||||
@@ -27,15 +27,15 @@
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (bitmonero CXX)
|
||||
project (monero CXX)
|
||||
|
||||
file(GLOB P2P *)
|
||||
source_group(p2p FILES ${P2P})
|
||||
|
||||
#add_library(p2p ${P2P})
|
||||
|
||||
#bitmonero_private_headers(p2p ${P2P})
|
||||
bitmonero_add_library(p2p ${P2P})
|
||||
#monero_private_headers(p2p ${P2P})
|
||||
monero_add_library(p2p ${P2P})
|
||||
target_link_libraries(p2p
|
||||
PUBLIC
|
||||
${UPNP_LIBRARIES}
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace nodetool
|
||||
struct p2p_connection_context_t: base_type //t_payload_net_handler::connection_context //public net_utils::connection_context_base
|
||||
{
|
||||
peerid_type peer_id;
|
||||
uint32_t support_flags;
|
||||
};
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
@@ -146,6 +147,7 @@ namespace nodetool
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
|
||||
#endif
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_SUPPORT_FLAGS, &node_server::handle_get_support_flags)
|
||||
CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&)
|
||||
END_INVOKE_MAP2()
|
||||
|
||||
@@ -158,6 +160,7 @@ namespace nodetool
|
||||
int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context);
|
||||
int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context);
|
||||
#endif
|
||||
int handle_get_support_flags(int command, COMMAND_REQUEST_SUPPORT_FLAGS::request& arg, COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context);
|
||||
bool init_config();
|
||||
bool make_default_config();
|
||||
bool store_config();
|
||||
@@ -169,12 +172,13 @@ namespace nodetool
|
||||
virtual void on_connection_close(p2p_connection_context& context);
|
||||
virtual void callback(p2p_connection_context& context);
|
||||
//----------------- i_p2p_endpoint -------------------------------------------------------------
|
||||
virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid> &connections);
|
||||
virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context);
|
||||
virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
|
||||
virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context);
|
||||
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
|
||||
virtual void request_callback(const epee::net_utils::connection_context_base& context);
|
||||
virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f);
|
||||
virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f);
|
||||
virtual bool add_ip_fail(uint32_t address);
|
||||
//----------------- i_connection_filter --------------------------------------------------------
|
||||
virtual bool is_remote_ip_allowed(uint32_t adress);
|
||||
@@ -204,6 +208,7 @@ namespace nodetool
|
||||
bool is_addr_connected(const net_address& peer);
|
||||
template<class t_callback>
|
||||
bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb);
|
||||
bool try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f);
|
||||
bool make_expected_connections_count(bool white_list, size_t expected_connections);
|
||||
void cache_connect_fail_info(const net_address& addr);
|
||||
bool is_addr_recently_failed(const net_address& addr);
|
||||
@@ -240,10 +245,12 @@ namespace nodetool
|
||||
{
|
||||
network_config m_net_config;
|
||||
uint64_t m_peer_id;
|
||||
uint32_t m_support_flags;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_net_config)
|
||||
KV_SERIALIZE(m_peer_id)
|
||||
KV_SERIALIZE(m_support_flags)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
@@ -158,6 +158,7 @@ namespace nodetool
|
||||
m_config.m_net_config.connection_timeout = P2P_DEFAULT_CONNECTION_TIMEOUT;
|
||||
m_config.m_net_config.ping_connection_timeout = P2P_DEFAULT_PING_CONNECTION_TIMEOUT;
|
||||
m_config.m_net_config.send_peerlist_sz = P2P_DEFAULT_PEERS_IN_HANDSHAKE;
|
||||
m_config.m_support_flags = P2P_SUPPORT_FLAGS;
|
||||
|
||||
m_first_connection_maker_call = true;
|
||||
CATCH_ENTRY_L0("node_server::init_config", false);
|
||||
@@ -165,10 +166,10 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f)
|
||||
void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f)
|
||||
{
|
||||
m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){
|
||||
return f(cntx, cntx.peer_id);
|
||||
return f(cntx, cntx.peer_id, cntx.support_flags);
|
||||
});
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
@@ -200,6 +201,20 @@ namespace nodetool
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
|
||||
m_blocked_ips[addr] = time(nullptr) + seconds;
|
||||
|
||||
// drop any connection to that IP
|
||||
std::list<boost::uuids::uuid> conns;
|
||||
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
|
||||
{
|
||||
if (cntxt.m_remote_ip == addr)
|
||||
{
|
||||
conns.push_back(cntxt.m_connection_id);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
for (const auto &c: conns)
|
||||
m_net_server.get_config_object().close(c);
|
||||
|
||||
LOG_PRINT_CYAN("IP " << epee::string_tools::get_ip_string_from_int32(addr) << " blocked.", LOG_LEVEL_0);
|
||||
return true;
|
||||
}
|
||||
@@ -326,7 +341,7 @@ namespace nodetool
|
||||
|
||||
io_service io_srv;
|
||||
ip::tcp::resolver resolver(io_srv);
|
||||
ip::tcp::resolver::query query(host, port);
|
||||
ip::tcp::resolver::query query(host, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::system::error_code ec;
|
||||
ip::tcp::resolver::iterator i = resolver.resolve(query, ec);
|
||||
CHECK_AND_ASSERT_MES_NO_RET(!ec, "Failed to resolve host name '" << host << "': " << ec.message() << ':' << ec.value());
|
||||
@@ -528,7 +543,7 @@ namespace nodetool
|
||||
} else if (result == 2) {
|
||||
LOG_PRINT_L0("IGD was found but reported as not connected.");
|
||||
} else if (result == 3) {
|
||||
LOG_PRINT_L0("UPnP device was found but not recoginzed as IGD.");
|
||||
LOG_PRINT_L0("UPnP device was found but not recognized as IGD.");
|
||||
} else {
|
||||
LOG_ERROR("UPNP_GetValidIGD returned an unknown result code.");
|
||||
}
|
||||
@@ -641,6 +656,7 @@ namespace nodetool
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::send_stop_signal()
|
||||
{
|
||||
m_payload_handler.stop();
|
||||
m_net_server.send_stop_signal();
|
||||
LOG_PRINT_L0("[node] Stop signal sent");
|
||||
return true;
|
||||
@@ -718,6 +734,13 @@ namespace nodetool
|
||||
LOG_PRINT_CC_L1(context_, "COMMAND_HANDSHAKE Failed");
|
||||
m_net_server.get_config_object().close(context_.m_connection_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
try_get_support_flags(context_, [](p2p_connection_context& flags_context, const uint32_t& support_flags)
|
||||
{
|
||||
flags_context.support_flags = support_flags;
|
||||
});
|
||||
}
|
||||
|
||||
return hsh_result;
|
||||
}
|
||||
@@ -1207,6 +1230,13 @@ namespace nodetool
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_get_support_flags(int command, COMMAND_REQUEST_SUPPORT_FLAGS::request& arg, COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
rsp.support_flags = m_config.m_support_flags;
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::request_callback(const epee::net_utils::connection_context_base& context)
|
||||
@@ -1215,6 +1245,16 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid> &connections)
|
||||
{
|
||||
BOOST_FOREACH(const auto& c_id, connections)
|
||||
{
|
||||
m_net_server.get_config_object().notify(command, data_buff, c_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)
|
||||
{
|
||||
std::list<boost::uuids::uuid> connections;
|
||||
@@ -1224,12 +1264,7 @@ namespace nodetool
|
||||
connections.push_back(cntxt.m_connection_id);
|
||||
return true;
|
||||
});
|
||||
|
||||
BOOST_FOREACH(const auto& c_id, connections)
|
||||
{
|
||||
m_net_server.get_config_object().notify(command, data_buff, c_id);
|
||||
}
|
||||
return true;
|
||||
return relay_notify_to_list(command, data_buff, connections);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
@@ -1326,6 +1361,32 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f)
|
||||
{
|
||||
COMMAND_REQUEST_SUPPORT_FLAGS::request support_flags_request;
|
||||
bool r = epee::net_utils::async_invoke_remote_command2<typename COMMAND_REQUEST_SUPPORT_FLAGS::response>
|
||||
(
|
||||
context.m_connection_id,
|
||||
COMMAND_REQUEST_SUPPORT_FLAGS::ID,
|
||||
support_flags_request,
|
||||
m_net_server.get_config_object(),
|
||||
[=](int code, const typename COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context_)
|
||||
{
|
||||
if(code < 0)
|
||||
{
|
||||
LOG_PRINT_CC_RED(context_, "COMMAND_REQUEST_SUPPORT_FLAGS invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")", LOG_LEVEL_1);
|
||||
return;
|
||||
}
|
||||
|
||||
f(context_, rsp.support_flags);
|
||||
},
|
||||
P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT
|
||||
);
|
||||
|
||||
return r;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, false))
|
||||
@@ -1382,7 +1443,7 @@ namespace nodetool
|
||||
if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port)
|
||||
{
|
||||
peerid_type peer_id_l = arg.node_data.peer_id;
|
||||
uint32_t port_l = arg.node_data.my_port;
|
||||
uint32_t port_l = arg.node_data.my_port;
|
||||
//try ping to be sure that we can add this peer to peer_list
|
||||
try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]()
|
||||
{
|
||||
@@ -1398,6 +1459,11 @@ namespace nodetool
|
||||
LOG_PRINT_CCONTEXT_L2("PING SUCCESS " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l);
|
||||
});
|
||||
}
|
||||
|
||||
try_get_support_flags(context, [](p2p_connection_context& flags_context, const uint32_t& support_flags)
|
||||
{
|
||||
flags_context.support_flags = support_flags;
|
||||
});
|
||||
|
||||
//fill response
|
||||
m_peerlist.get_peerlist_head(rsp.local_peerlist);
|
||||
@@ -1419,10 +1485,10 @@ namespace nodetool
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::log_peerlist()
|
||||
{
|
||||
std::list<peerlist_entry> pl_wite;
|
||||
std::list<peerlist_entry> pl_white;
|
||||
std::list<peerlist_entry> pl_gray;
|
||||
m_peerlist.get_peerlist_full(pl_gray, pl_wite);
|
||||
LOG_PRINT_L0(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_wite) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) );
|
||||
m_peerlist.get_peerlist_full(pl_gray, pl_white);
|
||||
LOG_PRINT_L0(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_white) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) );
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
@@ -43,13 +43,14 @@ namespace nodetool
|
||||
template<class t_connection_context>
|
||||
struct i_p2p_endpoint
|
||||
{
|
||||
virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid>& connections)=0;
|
||||
virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual void request_callback(const epee::net_utils::connection_context_base& context)=0;
|
||||
virtual uint64_t get_connections_count()=0;
|
||||
virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type)> f)=0;
|
||||
virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
|
||||
virtual bool block_ip(uint32_t adress, time_t seconds = 0)=0;
|
||||
virtual bool unblock_ip(uint32_t adress)=0;
|
||||
virtual std::map<uint32_t, time_t> get_blocked_ips()=0;
|
||||
@@ -59,6 +60,10 @@ namespace nodetool
|
||||
template<class t_connection_context>
|
||||
struct p2p_endpoint_stub: public i_p2p_endpoint<t_connection_context>
|
||||
{
|
||||
virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid>& connections)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)
|
||||
{
|
||||
return false;
|
||||
@@ -79,7 +84,7 @@ namespace nodetool
|
||||
{
|
||||
|
||||
}
|
||||
virtual void for_each_connection(std::function<bool(t_connection_context&,peerid_type)> f)
|
||||
virtual void for_each_connection(std::function<bool(t_connection_context&,peerid_type,uint32_t)> f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -332,6 +332,29 @@ namespace nodetool
|
||||
};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct COMMAND_REQUEST_SUPPORT_FLAGS
|
||||
{
|
||||
const static int ID = P2P_COMMANDS_POOL_BASE + 7;
|
||||
|
||||
struct request
|
||||
{
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
uint32_t support_flags;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(support_flags)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ set(ringct_private_headers
|
||||
rctSigs.h
|
||||
rctTypes.h)
|
||||
|
||||
bitmonero_private_headers(ringct
|
||||
monero_private_headers(ringct
|
||||
${crypto_private_headers})
|
||||
bitmonero_add_library(ringct
|
||||
monero_add_library(ringct
|
||||
${ringct_sources}
|
||||
${ringct_headers}
|
||||
${ringct_private_headers})
|
||||
|
||||
@@ -37,50 +37,12 @@ namespace rct {
|
||||
|
||||
//Various key initialization functions
|
||||
|
||||
//Creates a zero scalar
|
||||
void zero(key &zero) {
|
||||
memset(&zero, 0, 32);
|
||||
}
|
||||
|
||||
//Creates a zero scalar
|
||||
key zero() {
|
||||
static const key z = { {0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
|
||||
return z;
|
||||
}
|
||||
|
||||
//Creates a zero elliptic curve point
|
||||
void identity(key &Id) {
|
||||
Id[0] = (unsigned char)(0x01);
|
||||
memset(Id.bytes+1, 0, 31);
|
||||
}
|
||||
|
||||
//Creates a zero elliptic curve point
|
||||
key identity() {
|
||||
key Id;
|
||||
Id[0] = (unsigned char)(0x01);
|
||||
memset(Id.bytes+1, 0, 31);
|
||||
return Id;
|
||||
}
|
||||
|
||||
//copies a scalar or point
|
||||
void copy(key &AA, const key &A) {
|
||||
memcpy(&AA, &A, 32);
|
||||
}
|
||||
|
||||
//copies a scalar or point
|
||||
key copy(const key &A) {
|
||||
key AA;
|
||||
memcpy(&AA, &A, 32);
|
||||
return AA;
|
||||
}
|
||||
|
||||
|
||||
//initializes a key matrix;
|
||||
//first parameter is rows,
|
||||
//second is columns
|
||||
keyM keyMInit(int rows, int cols) {
|
||||
keyM keyMInit(size_t rows, size_t cols) {
|
||||
keyM rv(cols);
|
||||
int i = 0;
|
||||
size_t i = 0;
|
||||
for (i = 0 ; i < cols ; i++) {
|
||||
rv[i] = keyV(rows);
|
||||
}
|
||||
@@ -107,11 +69,12 @@ namespace rct {
|
||||
|
||||
//Generates a vector of secret key
|
||||
//Mainly used in testing
|
||||
keyV skvGen(int rows ) {
|
||||
keyV skvGen(size_t rows ) {
|
||||
keyV rv(rows);
|
||||
int i = 0;
|
||||
size_t i = 0;
|
||||
crypto::rand(rows * sizeof(key), (uint8_t*)&rv[0]);
|
||||
for (i = 0 ; i < rows ; i++) {
|
||||
skGen(rv[i]);
|
||||
sc_reduce32(rv[i].bytes);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -155,7 +118,7 @@ namespace rct {
|
||||
|
||||
|
||||
//generates a <secret , public> / Pedersen commitment but takes bH as input
|
||||
tuple<ctkey, ctkey> ctskpkGen(key bH) {
|
||||
tuple<ctkey, ctkey> ctskpkGen(const key &bH) {
|
||||
ctkey sk, pk;
|
||||
skpkGen(sk.dest, pk.dest);
|
||||
skpkGen(sk.mask, pk.mask);
|
||||
@@ -172,12 +135,12 @@ namespace rct {
|
||||
return mask;
|
||||
}
|
||||
|
||||
key commit(xmr_amount amount, key mask) {
|
||||
mask = scalarmultBase(mask);
|
||||
key commit(xmr_amount amount, const key &mask) {
|
||||
key c = scalarmultBase(mask);
|
||||
key am = d2h(amount);
|
||||
key bH = scalarmultH(am);
|
||||
addKeys(mask, mask, bH);
|
||||
return mask;
|
||||
addKeys(c, c, bH);
|
||||
return c;
|
||||
}
|
||||
|
||||
//generates a random uint long long (for testing)
|
||||
@@ -304,7 +267,7 @@ namespace rct {
|
||||
ge_p3_tobytes(AB.bytes, &A2);
|
||||
}
|
||||
|
||||
//checks if A, B are equal as curve points
|
||||
//checks if A, B are equal in terms of bytes (may say no if one is a non-reduced scalar)
|
||||
//without doing curve operations
|
||||
bool equalKeys(const key & a, const key & b) {
|
||||
bool rv = true;
|
||||
@@ -320,7 +283,7 @@ namespace rct {
|
||||
//be careful these are also in crypto namespace
|
||||
//cn_fast_hash for arbitrary multiples of 32 bytes
|
||||
void cn_fast_hash(key &hash, const void * data, const std::size_t l) {
|
||||
keccak((uint8_t *)data, l, hash.bytes, 32);
|
||||
keccak((const uint8_t *)data, l, hash.bytes, 32);
|
||||
}
|
||||
|
||||
void hash_to_scalar(key &hash, const void * data, const std::size_t l) {
|
||||
@@ -330,7 +293,7 @@ namespace rct {
|
||||
|
||||
//cn_fast_hash for a 32 byte key
|
||||
void cn_fast_hash(key & hash, const key & in) {
|
||||
keccak((uint8_t *)in.bytes, 32, hash.bytes, 32);
|
||||
keccak((const uint8_t *)in.bytes, 32, hash.bytes, 32);
|
||||
}
|
||||
|
||||
void hash_to_scalar(key & hash, const key & in) {
|
||||
@@ -341,7 +304,7 @@ namespace rct {
|
||||
//cn_fast_hash for a 32 byte key
|
||||
key cn_fast_hash(const key & in) {
|
||||
key hash;
|
||||
keccak((uint8_t *)in.bytes, 32, hash.bytes, 32);
|
||||
keccak((const uint8_t *)in.bytes, 32, hash.bytes, 32);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -354,7 +317,7 @@ namespace rct {
|
||||
//cn_fast_hash for a 128 byte unsigned char
|
||||
key cn_fast_hash128(const void * in) {
|
||||
key hash;
|
||||
keccak((uint8_t *)in, 128, hash.bytes, 32);
|
||||
keccak((const uint8_t *)in, 128, hash.bytes, 32);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -367,20 +330,13 @@ namespace rct {
|
||||
//cn_fast_hash for multisig purpose
|
||||
//This takes the outputs and commitments
|
||||
//and hashes them into a 32 byte sized key
|
||||
key cn_fast_hash(ctkeyV PC) {
|
||||
key rv = identity();
|
||||
std::size_t l = (std::size_t)PC.size();
|
||||
size_t i = 0, j = 0;
|
||||
vector<char> m(l * 64);
|
||||
for (i = 0 ; i < l ; i++) {
|
||||
memcpy(&m[i * 64], &PC[i].dest, 32);
|
||||
memcpy(&m[i * 64 + 32], &PC[i].mask, 32);
|
||||
}
|
||||
cn_fast_hash(rv, &m[0], 64*l);
|
||||
key cn_fast_hash(const ctkeyV &PC) {
|
||||
key rv;
|
||||
cn_fast_hash(rv, &PC[0], 64*PC.size());
|
||||
return rv;
|
||||
}
|
||||
|
||||
key hash_to_scalar(ctkeyV PC) {
|
||||
key hash_to_scalar(const ctkeyV &PC) {
|
||||
key rv = cn_fast_hash(PC);
|
||||
sc_reduce32(rv.bytes);
|
||||
return rv;
|
||||
@@ -391,14 +347,8 @@ namespace rct {
|
||||
//put them in the key vector and it concatenates them
|
||||
//and then hashes them
|
||||
key cn_fast_hash(const keyV &keys) {
|
||||
size_t l = keys.size();
|
||||
vector<unsigned char> m(l * 32);
|
||||
size_t i;
|
||||
for (i = 0 ; i < l ; i++) {
|
||||
memcpy(&m[i * 32], keys[i].bytes, 32);
|
||||
}
|
||||
key rv;
|
||||
cn_fast_hash(rv, &m[0], 32 * l);
|
||||
cn_fast_hash(rv, &keys[0], keys.size() * sizeof(keys[0]));
|
||||
//dp(rv);
|
||||
return rv;
|
||||
}
|
||||
@@ -409,6 +359,19 @@ namespace rct {
|
||||
return rv;
|
||||
}
|
||||
|
||||
key cn_fast_hash(const key64 keys) {
|
||||
key rv;
|
||||
cn_fast_hash(rv, &keys[0], 64 * sizeof(keys[0]));
|
||||
//dp(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
key hash_to_scalar(const key64 keys) {
|
||||
key rv = cn_fast_hash(keys);
|
||||
sc_reduce32(rv.bytes);
|
||||
return rv;
|
||||
}
|
||||
|
||||
key hashToPointSimple(const key & hh) {
|
||||
key pointk;
|
||||
ge_p1p1 point2;
|
||||
|
||||
@@ -64,19 +64,23 @@ namespace rct {
|
||||
|
||||
//Various key initialization functions
|
||||
|
||||
static const key Z = { {0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
|
||||
static const key I = { {0x01, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
|
||||
|
||||
//Creates a zero scalar
|
||||
key zero();
|
||||
void zero(key &z);
|
||||
inline key zero() { return Z; }
|
||||
inline void zero(key &z) { memset(&z, 0, 32); }
|
||||
//Creates a zero elliptic curve point
|
||||
key identity();
|
||||
void identity(key &Id);
|
||||
inline key identity() { return I; }
|
||||
inline void identity(key &Id) { memcpy(&Id, &I, 32); }
|
||||
//copies a scalar or point
|
||||
void copy(key &AA, const key &A);
|
||||
key copy(const key & AA);
|
||||
inline void copy(key &AA, const key &A) { memcpy(&AA, &A, 32); }
|
||||
inline key copy(const key & A) { key AA; memcpy(&AA, &A, 32); return AA; }
|
||||
|
||||
//initializes a key matrix;
|
||||
//first parameter is rows,
|
||||
//second is columns
|
||||
keyM keyMInit(int, int);
|
||||
keyM keyMInit(size_t rows, size_t cols);
|
||||
|
||||
//Various key generation functions
|
||||
|
||||
@@ -85,7 +89,7 @@ namespace rct {
|
||||
void skGen(key &);
|
||||
|
||||
//generates a vector of secret keys of size "int"
|
||||
keyV skvGen(int );
|
||||
keyV skvGen(size_t rows );
|
||||
|
||||
//generates a random curve point (for testing)
|
||||
key pkGen();
|
||||
@@ -97,9 +101,9 @@ namespace rct {
|
||||
//generates C =aG + bH from b, a is random
|
||||
void genC(key & C, const key & a, xmr_amount amount);
|
||||
//this one is mainly for testing, can take arbitrary amounts..
|
||||
tuple<ctkey, ctkey> ctskpkGen(key bH);
|
||||
tuple<ctkey, ctkey> ctskpkGen(const key &bH);
|
||||
// make a pedersen commitment with given key
|
||||
key commit(xmr_amount amount, key mask);
|
||||
key commit(xmr_amount amount, const key &mask);
|
||||
// make a pedersen commitment with zero key
|
||||
key zeroCommit(xmr_amount amount);
|
||||
//generates a random uint long long
|
||||
@@ -149,11 +153,14 @@ namespace rct {
|
||||
//for mg sigs
|
||||
key cn_fast_hash128(const void * in);
|
||||
key hash_to_scalar128(const void * in);
|
||||
key cn_fast_hash(ctkeyV PC);
|
||||
key hash_to_scalar(ctkeyV PC);
|
||||
key cn_fast_hash(const ctkeyV &PC);
|
||||
key hash_to_scalar(const ctkeyV &PC);
|
||||
//for mg sigs
|
||||
key cn_fast_hash(const keyV &keys);
|
||||
key hash_to_scalar(const keyV &keys);
|
||||
//for ANSL
|
||||
key cn_fast_hash(const key64 keys);
|
||||
key hash_to_scalar(const key64 keys);
|
||||
|
||||
//returns hashToPoint as described in https://github.com/ShenNoether/ge_fromfe_writeup
|
||||
key hashToPointSimple(const key &in);
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "misc_log_ex.h"
|
||||
#include "common/perf_timer.h"
|
||||
#include "common/task_region.h"
|
||||
#include "common/thread_group.h"
|
||||
#include "common/util.h"
|
||||
#include "rctSigs.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
|
||||
@@ -36,94 +40,66 @@ using namespace crypto;
|
||||
using namespace std;
|
||||
|
||||
namespace rct {
|
||||
namespace {
|
||||
struct verRangeWrapper_ {
|
||||
void operator()(const key & C, const rangeSig & as, bool &result) const {
|
||||
result = verRange(C, as);
|
||||
}
|
||||
};
|
||||
constexpr const verRangeWrapper_ verRangeWrapper{};
|
||||
|
||||
struct verRctMGSimpleWrapper_ {
|
||||
void operator()(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C, bool &result) const {
|
||||
result = verRctMGSimple(message, mg, pubs, C);
|
||||
}
|
||||
};
|
||||
constexpr const verRctMGSimpleWrapper_ verRctMGSimpleWrapper{};
|
||||
}
|
||||
|
||||
//Schnorr Non-linkable
|
||||
//Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
|
||||
//Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
|
||||
//These are called in the below ASNL sig generation
|
||||
//Borromean (c.f. gmax/andytoshi's paper)
|
||||
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
|
||||
key64 L[2], alpha;
|
||||
key c;
|
||||
int naught = 0, prime = 0, ii = 0, jj=0;
|
||||
boroSig bb;
|
||||
for (ii = 0 ; ii < 64 ; ii++) {
|
||||
naught = indices[ii]; prime = (indices[ii] + 1) % 2;
|
||||
skGen(alpha[ii]);
|
||||
scalarmultBase(L[naught][ii], alpha[ii]);
|
||||
if (naught == 0) {
|
||||
skGen(bb.s1[ii]);
|
||||
c = hash_to_scalar(L[naught][ii]);
|
||||
addKeys2(L[prime][ii], bb.s1[ii], c, P2[ii]);
|
||||
}
|
||||
}
|
||||
bb.ee = hash_to_scalar(L[1]); //or L[1]..
|
||||
key LL, cc;
|
||||
for (jj = 0 ; jj < 64 ; jj++) {
|
||||
if (!indices[jj]) {
|
||||
sc_mulsub(bb.s0[jj].bytes, x[jj].bytes, bb.ee.bytes, alpha[jj].bytes);
|
||||
} else {
|
||||
skGen(bb.s0[jj]);
|
||||
addKeys2(LL, bb.s0[jj], bb.ee, P1[jj]); //different L0
|
||||
cc = hash_to_scalar(LL);
|
||||
sc_mulsub(bb.s1[jj].bytes, x[jj].bytes, cc.bytes, alpha[jj].bytes);
|
||||
}
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, int index) {
|
||||
key c1, c2, L2;
|
||||
key a = skGen();
|
||||
if (index == 0) {
|
||||
scalarmultBase(L1, a);
|
||||
hash_to_scalar(c2, L1);
|
||||
skGen(s2);
|
||||
addKeys2(L2, s2, c2, P2);
|
||||
hash_to_scalar(c1, L2);
|
||||
//s1 = a - x * c1
|
||||
sc_mulsub(s1.bytes, x.bytes, c1.bytes, a.bytes);
|
||||
}
|
||||
else if (index == 1) {
|
||||
scalarmultBase(L2, a);
|
||||
hash_to_scalar(c1, L2);
|
||||
skGen(s1);
|
||||
addKeys2(L1, s1, c1, P1);
|
||||
hash_to_scalar(c2, L1);
|
||||
sc_mulsub(s2.bytes, x.bytes, c2.bytes, a.bytes);
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("GenSchnorrNonLinkable: invalid index (should be 0 or 1)");
|
||||
//see above.
|
||||
bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2) {
|
||||
key64 Lv1; key chash, LL;
|
||||
int ii = 0;
|
||||
for (ii = 0 ; ii < 64 ; ii++) {
|
||||
addKeys2(LL, bb.s0[ii], bb.ee, P1[ii]);
|
||||
chash = hash_to_scalar(LL);
|
||||
addKeys2(Lv1[ii], bb.s1[ii], chash, P2[ii]);
|
||||
}
|
||||
key eeComputed = hash_to_scalar(Lv1); //hash function fine
|
||||
return equalKeys(eeComputed, bb.ee);
|
||||
}
|
||||
|
||||
//Schnorr Non-linkable
|
||||
//Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
|
||||
//Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
|
||||
//These are called in the below ASNL sig generation
|
||||
bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2) {
|
||||
key c2, L2, c1, L1p;
|
||||
hash_to_scalar(c2, L1);
|
||||
addKeys2(L2, s2, c2, P2);
|
||||
hash_to_scalar(c1, L2);
|
||||
addKeys2(L1p, s1, c1, P1);
|
||||
|
||||
return equalKeys(L1, L1p);
|
||||
}
|
||||
|
||||
//Aggregate Schnorr Non-linkable Ring Signature (ASNL)
|
||||
// c.f. http://eprint.iacr.org/2015/1098 section 5.
|
||||
// These are used in range proofs (alternatively Borromean could be used)
|
||||
// Gen gives a signature which proves the signer knows, for each i,
|
||||
// an x[i] such that x[i]G = one of P1[i] or P2[i]
|
||||
// Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
|
||||
asnlSig GenASNL(key64 x, key64 P1, key64 P2, bits indices) {
|
||||
DP("Generating Aggregate Schnorr Non-linkable Ring Signature\n");
|
||||
key64 s1;
|
||||
int j = 0;
|
||||
asnlSig rv;
|
||||
rv.s = zero();
|
||||
for (j = 0; j < ATOMS; j++) {
|
||||
GenSchnorrNonLinkable(rv.L1[j], s1[j], rv.s2[j], x[j], P1[j], P2[j], (int)indices[j]);
|
||||
sc_add(rv.s.bytes, rv.s.bytes, s1[j].bytes);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//Aggregate Schnorr Non-linkable Ring Signature (ASNL)
|
||||
// c.f. http://eprint.iacr.org/2015/1098 section 5.
|
||||
// These are used in range proofs (alternatively Borromean could be used)
|
||||
// Gen gives a signature which proves the signer knows, for each i,
|
||||
// an x[i] such that x[i]G = one of P1[i] or P2[i]
|
||||
// Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
|
||||
bool VerASNL(const key64 P1, const key64 P2, const asnlSig &as) {
|
||||
DP("Verifying Aggregate Schnorr Non-linkable Ring Signature\n");
|
||||
key LHS = identity();
|
||||
key RHS = scalarmultBase(as.s);
|
||||
key c2, L2, c1;
|
||||
int j = 0;
|
||||
for (j = 0; j < ATOMS; j++) {
|
||||
hash_to_scalar(c2, as.L1[j]);
|
||||
addKeys2(L2, as.s2[j], c2, P2[j]);
|
||||
addKeys(LHS, LHS, as.L1[j]);
|
||||
hash_to_scalar(c1, L2);
|
||||
addKeys(RHS, RHS, scalarmultKey(P1[j], c1));
|
||||
}
|
||||
key cc;
|
||||
sc_sub(cc.bytes, LHS.bytes, RHS.bytes);
|
||||
return sc_isnonzero(cc.bytes) == 0;
|
||||
}
|
||||
|
||||
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
|
||||
//These are aka MG signatutes in earlier drafts of the ring ct paper
|
||||
// c.f. http://eprint.iacr.org/2015/1098 section 2.
|
||||
@@ -150,7 +126,7 @@ namespace rct {
|
||||
// Gen creates a signature which proves that for some column in the keymatrix "pk"
|
||||
// the signer knows a secret key for each row in that column
|
||||
// Ver verifies that the MG sig was created correctly
|
||||
mgSig MLSAG_Gen(key message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows) {
|
||||
mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows) {
|
||||
mgSig rv;
|
||||
size_t cols = pk.size();
|
||||
CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!");
|
||||
@@ -239,7 +215,7 @@ namespace rct {
|
||||
// Gen creates a signature which proves that for some column in the keymatrix "pk"
|
||||
// the signer knows a secret key for each row in that column
|
||||
// Ver verifies that the MG sig was created correctly
|
||||
bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv, size_t dsRows) {
|
||||
bool MLSAG_Ver(const key &message, const keyM & pk, const mgSig & rv, size_t dsRows) {
|
||||
|
||||
size_t cols = pk.size();
|
||||
CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!");
|
||||
@@ -255,6 +231,11 @@ namespace rct {
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Bad dsRows value");
|
||||
|
||||
for (size_t i = 0; i < rv.ss.size(); ++i)
|
||||
for (size_t j = 0; j < rv.ss[i].size(); ++j)
|
||||
CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad ss slot");
|
||||
CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad cc");
|
||||
|
||||
size_t i = 0, j = 0, ii = 0;
|
||||
key c, L, R, Hi;
|
||||
key c_old = copy(rv.cc);
|
||||
@@ -319,7 +300,7 @@ namespace rct {
|
||||
sc_add(mask.bytes, mask.bytes, ai[i].bytes);
|
||||
addKeys(C, C, sig.Ci[i]);
|
||||
}
|
||||
sig.asig = GenASNL(ai, sig.Ci, CiH, b);
|
||||
sig.asig = genBorromean(ai, sig.Ci, CiH, b);
|
||||
return sig;
|
||||
}
|
||||
|
||||
@@ -331,6 +312,9 @@ namespace rct {
|
||||
// mask is a such that C = aG + bH, and b = amount
|
||||
//verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
|
||||
bool verRange(const key & C, const rangeSig & as) {
|
||||
try
|
||||
{
|
||||
PERF_TIMER(verRange);
|
||||
key64 CiH;
|
||||
int i = 0;
|
||||
key Ctmp = identity();
|
||||
@@ -340,14 +324,18 @@ namespace rct {
|
||||
}
|
||||
if (!equalKeys(C, Ctmp))
|
||||
return false;
|
||||
if (!VerASNL(as.Ci, CiH, as.asig))
|
||||
if (!verifyBorromean(as.asig, as.Ci, CiH))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// we can get deep throws from ge_frombytes_vartime if input isn't valid
|
||||
catch (...) { return false; }
|
||||
}
|
||||
|
||||
key get_pre_mlsag_hash(const rctSig &rv)
|
||||
{
|
||||
keyV hashes;
|
||||
hashes.reserve(3);
|
||||
hashes.push_back(rv.message);
|
||||
crypto::hash h;
|
||||
|
||||
@@ -361,13 +349,14 @@ namespace rct {
|
||||
hashes.push_back(hash2rct(h));
|
||||
|
||||
keyV kv;
|
||||
kv.reserve((64*3+1) * rv.p.rangeSigs.size());
|
||||
for (auto r: rv.p.rangeSigs)
|
||||
{
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.L1[n]);
|
||||
kv.push_back(r.asig.s0[n]);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s2[n]);
|
||||
kv.push_back(r.asig.s);
|
||||
kv.push_back(r.asig.s1[n]);
|
||||
kv.push_back(r.asig.ee);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.Ci[n]);
|
||||
}
|
||||
@@ -467,6 +456,7 @@ namespace rct {
|
||||
//Ver:
|
||||
// verifies the above sig is created corretly
|
||||
bool verRctMG(const mgSig &mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &message) {
|
||||
PERF_TIMER(verRctMG);
|
||||
//setup vars
|
||||
size_t cols = pubs.size();
|
||||
CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs");
|
||||
@@ -505,6 +495,9 @@ namespace rct {
|
||||
//This does a simplified version, assuming only post Rct
|
||||
//inputs
|
||||
bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C) {
|
||||
try
|
||||
{
|
||||
PERF_TIMER(verRctMGSimple);
|
||||
//setup vars
|
||||
size_t rows = 1;
|
||||
size_t cols = pubs.size();
|
||||
@@ -519,8 +512,11 @@ namespace rct {
|
||||
}
|
||||
//DP(C);
|
||||
return MLSAG_Ver(message, M, mg, rows);
|
||||
}
|
||||
catch (...) { return false; }
|
||||
}
|
||||
|
||||
|
||||
//These functions get keys from blockchain
|
||||
//replace these when connecting blockchain
|
||||
//getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
|
||||
@@ -583,6 +579,7 @@ namespace rct {
|
||||
// Thus the amounts vector will be "one" longer than the destinations vectort
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk) {
|
||||
CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations");
|
||||
CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
|
||||
CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
|
||||
for (size_t n = 0; n < mixRing.size(); ++n) {
|
||||
CHECK_AND_ASSERT_THROW_MES(mixRing[n].size() == inSk.size(), "Bad mixRing size");
|
||||
@@ -644,6 +641,7 @@ namespace rct {
|
||||
CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts");
|
||||
CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
|
||||
CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
|
||||
CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
|
||||
CHECK_AND_ASSERT_THROW_MES(index.size() == inSk.size(), "Different number of index/inSk");
|
||||
CHECK_AND_ASSERT_THROW_MES(mixRing.size() == inSk.size(), "Different number of mixRing/inSk");
|
||||
for (size_t n = 0; n < mixRing.size(); ++n) {
|
||||
@@ -729,6 +727,7 @@ namespace rct {
|
||||
// uses the attached ecdh info to find the amounts represented by each output commitment
|
||||
// must know the destination private key to find the correct amount, else will return a random number
|
||||
bool verRct(const rctSig & rv) {
|
||||
PERF_TIMER(verRct);
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
|
||||
@@ -737,24 +736,32 @@ namespace rct {
|
||||
// some rct ops can throw
|
||||
try
|
||||
{
|
||||
size_t i = 0;
|
||||
bool tmp;
|
||||
DP("range proofs verified?");
|
||||
for (i = 0; i < rv.outPk.size(); i++) {
|
||||
tmp = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
DP(tmp);
|
||||
if (!tmp) {
|
||||
LOG_ERROR("Range proof verification failed for input " << i);
|
||||
return false;
|
||||
}
|
||||
std::deque<bool> results(rv.outPk.size(), false);
|
||||
tools::thread_group threadpool(tools::thread_group::optimal_with_max(rv.outPk.size()));
|
||||
|
||||
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
||||
DP("range proofs verified?");
|
||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||
region.run([&, i] {
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < rv.outPk.size(); ++i) {
|
||||
if (!results[i]) {
|
||||
LOG_PRINT_L1("Range proof verified failed for output " << i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//compute txn fee
|
||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||
bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
|
||||
DP("mg sig verified?");
|
||||
DP(mgVerd);
|
||||
if (!mgVerd) {
|
||||
LOG_ERROR("MG signature verification failed");
|
||||
LOG_PRINT_L1("MG signature verification failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -769,7 +776,9 @@ namespace rct {
|
||||
//ver RingCT simple
|
||||
//assumes only post-rct style inputs (at least for max anonymity)
|
||||
bool verRctSimple(const rctSig & rv) {
|
||||
size_t i = 0;
|
||||
try
|
||||
{
|
||||
PERF_TIMER(verRctSimple);
|
||||
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
@@ -777,39 +786,71 @@ namespace rct {
|
||||
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
|
||||
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
|
||||
|
||||
const size_t threads = std::max(rv.outPk.size(), rv.mixRing.size());
|
||||
|
||||
std::deque<bool> results(threads);
|
||||
tools::thread_group threadpool(tools::thread_group::optimal_with_max(threads));
|
||||
|
||||
results.clear();
|
||||
results.resize(rv.outPk.size());
|
||||
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||
region.run([&, i] {
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < results.size(); ++i) {
|
||||
if (!results[i]) {
|
||||
LOG_PRINT_L1("Range proof verified failed for output " << i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
key sumOutpks = identity();
|
||||
for (i = 0; i < rv.outPk.size(); i++) {
|
||||
if (!verRange(rv.outPk[i].mask, rv.p.rangeSigs[i])) {
|
||||
LOG_ERROR("Range proof verified failed for input " << i);
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
|
||||
}
|
||||
DP(sumOutpks);
|
||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||
addKeys(sumOutpks, txnFeeKey, sumOutpks);
|
||||
|
||||
bool tmpb = false;
|
||||
key message = get_pre_mlsag_hash(rv);
|
||||
|
||||
results.clear();
|
||||
results.resize(rv.mixRing.size());
|
||||
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
||||
for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
|
||||
region.run([&, i] {
|
||||
results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < results.size(); ++i) {
|
||||
if (!results[i]) {
|
||||
LOG_PRINT_L1("verRctMGSimple failed for input " << i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
key sumPseudoOuts = identity();
|
||||
for (i = 0 ; i < rv.mixRing.size() ; i++) {
|
||||
tmpb = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
|
||||
for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
|
||||
addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
|
||||
DP(tmpb);
|
||||
if (!tmpb) {
|
||||
LOG_ERROR("verRctMGSimple failed for input " << i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DP(sumPseudoOuts);
|
||||
|
||||
//check pseudoOuts vs Outs..
|
||||
if (!equalKeys(sumPseudoOuts, sumOutpks)) {
|
||||
LOG_ERROR("Sum check failed");
|
||||
LOG_PRINT_L1("Sum check failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// we can get deep throws from ge_frombytes_vartime if input isn't valid
|
||||
catch (...) { return false; }
|
||||
}
|
||||
|
||||
//RingCT protocol
|
||||
|
||||
@@ -66,21 +66,8 @@ using namespace crypto;
|
||||
|
||||
namespace rct {
|
||||
|
||||
//Schnorr Non-linkable
|
||||
//Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
|
||||
//Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
|
||||
//These are called in the below ASNL sig generation
|
||||
void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, int index);
|
||||
bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2);
|
||||
|
||||
//Aggregate Schnorr Non-linkable Ring Signature (ASNL)
|
||||
// c.f. http://eprint.iacr.org/2015/1098 section 5.
|
||||
// These are used in range proofs (alternatively Borromean could be used)
|
||||
// Gen gives a signature which proves the signer knows, for each i,
|
||||
// an x[i] such that x[i]G = one of P1[i] or P2[i]
|
||||
// Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
|
||||
asnlSig GenASNL(key64 x, key64 P1, key64 P2, bits indices);
|
||||
bool VerASNL(const key64 P1, const key64 P2, const asnlSig &as);
|
||||
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices);
|
||||
bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2);
|
||||
|
||||
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
|
||||
//These are aka MG signatutes in earlier drafts of the ring ct paper
|
||||
@@ -90,8 +77,8 @@ namespace rct {
|
||||
// the signer knows a secret key for each row in that column
|
||||
// Ver verifies that the MG sig was created correctly
|
||||
keyV keyImageV(const keyV &xx);
|
||||
mgSig MLSAG_Gen(key message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows);
|
||||
bool MLSAG_Ver(key message, const keyM &pk, const mgSig &sig, size_t dsRows);
|
||||
mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows);
|
||||
bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &sig, size_t dsRows);
|
||||
//mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index);
|
||||
|
||||
//proveRange and verRange
|
||||
|
||||
@@ -125,12 +125,10 @@ namespace rct {
|
||||
typedef unsigned int bits[ATOMS];
|
||||
typedef key key64[64];
|
||||
|
||||
//just contains the necessary keys to represent asnlSigs
|
||||
//c.f. http://eprint.iacr.org/2015/1098
|
||||
struct asnlSig {
|
||||
key64 L1;
|
||||
key64 s2;
|
||||
key s;
|
||||
struct boroSig {
|
||||
key64 s0;
|
||||
key64 s1;
|
||||
key ee;
|
||||
};
|
||||
|
||||
//Container for precomp
|
||||
@@ -151,14 +149,14 @@ namespace rct {
|
||||
// FIELD(II) - not serialized, it can be reconstructed
|
||||
END_SERIALIZE()
|
||||
};
|
||||
//contains the data for an asnl sig
|
||||
//contains the data for an Borromean sig
|
||||
// also contains the "Ci" values such that
|
||||
// \sum Ci = C
|
||||
// and the signature proves that each Ci is either
|
||||
// a Pedersen commitment to 0 or to 2^i
|
||||
//thus proving that C is in the range of [0, 2^64]
|
||||
struct rangeSig {
|
||||
asnlSig asig;
|
||||
boroSig asig;
|
||||
key64 Ci;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
@@ -281,6 +279,7 @@ namespace rct {
|
||||
// we save the MGs contents directly, because we want it to save its
|
||||
// arrays and matrices without the size prefixes, and the load can't
|
||||
// know what size to expect if it's not in the data
|
||||
ar.begin_object();
|
||||
ar.tag("ss");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, MGs[i].ss);
|
||||
@@ -296,7 +295,7 @@ namespace rct {
|
||||
for (size_t k = 0; k < mg_ss2_elements; ++k)
|
||||
{
|
||||
FIELDS(MGs[i].ss[j][k])
|
||||
if (mg_ss2_elements - j > 1)
|
||||
if (mg_ss2_elements - k > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
@@ -306,10 +305,13 @@ namespace rct {
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
ar.tag("cc");
|
||||
FIELDS(MGs[i].cc)
|
||||
// MGs[i].II not saved, it can be reconstructed
|
||||
if (mg_elements - i > 1)
|
||||
ar.delimit_array();
|
||||
|
||||
ar.end_object();
|
||||
}
|
||||
ar.end_array();
|
||||
return true;
|
||||
@@ -415,7 +417,7 @@ namespace rct {
|
||||
// then the value in the first 8 bytes is returned
|
||||
xmr_amount h2d(const key &test);
|
||||
//32 byte key to int[64]
|
||||
void h2b(bits amountb2, key & test);
|
||||
void h2b(bits amountb2, const key & test);
|
||||
//int[64] to 32 byte key
|
||||
void b2h(key & amountdh, bits amountb2);
|
||||
//int[64] to uint long long
|
||||
@@ -448,7 +450,7 @@ inline std::ostream &operator <<(std::ostream &o, const rct::key &v) { return pr
|
||||
BLOB_SERIALIZER(rct::key);
|
||||
BLOB_SERIALIZER(rct::key64);
|
||||
BLOB_SERIALIZER(rct::ctkey);
|
||||
BLOB_SERIALIZER(rct::asnlSig);
|
||||
BLOB_SERIALIZER(rct::boroSig);
|
||||
|
||||
VARIANT_TAG(debug_archive, rct::key, "rct::key");
|
||||
VARIANT_TAG(debug_archive, rct::key64, "rct::key64");
|
||||
@@ -460,7 +462,7 @@ VARIANT_TAG(debug_archive, rct::ctkeyM, "rct::ctkeyM");
|
||||
VARIANT_TAG(debug_archive, rct::ecdhTuple, "rct::ecdhTuple");
|
||||
VARIANT_TAG(debug_archive, rct::mgSig, "rct::mgSig");
|
||||
VARIANT_TAG(debug_archive, rct::rangeSig, "rct::rangeSig");
|
||||
VARIANT_TAG(debug_archive, rct::asnlSig, "rct::asnlSig");
|
||||
VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
|
||||
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
|
||||
|
||||
VARIANT_TAG(binary_archive, rct::key, 0x90);
|
||||
@@ -473,7 +475,7 @@ VARIANT_TAG(binary_archive, rct::ctkeyM, 0x96);
|
||||
VARIANT_TAG(binary_archive, rct::ecdhTuple, 0x97);
|
||||
VARIANT_TAG(binary_archive, rct::mgSig, 0x98);
|
||||
VARIANT_TAG(binary_archive, rct::rangeSig, 0x99);
|
||||
VARIANT_TAG(binary_archive, rct::asnlSig, 0x9a);
|
||||
VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
|
||||
VARIANT_TAG(binary_archive, rct::rctSig, 0x9b);
|
||||
|
||||
VARIANT_TAG(json_archive, rct::key, "rct_key");
|
||||
@@ -486,7 +488,7 @@ VARIANT_TAG(json_archive, rct::ctkeyM, "rct_ctkeyM");
|
||||
VARIANT_TAG(json_archive, rct::ecdhTuple, "rct_ecdhTuple");
|
||||
VARIANT_TAG(json_archive, rct::mgSig, "rct_mgSig");
|
||||
VARIANT_TAG(json_archive, rct::rangeSig, "rct_rangeSig");
|
||||
VARIANT_TAG(json_archive, rct::asnlSig, "rct_asnlSig");
|
||||
VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
|
||||
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
|
||||
|
||||
#endif /* RCTTYPES_H */
|
||||
|
||||
@@ -36,9 +36,9 @@ set(rpc_private_headers
|
||||
core_rpc_server_commands_defs.h
|
||||
core_rpc_server_error_codes.h)
|
||||
|
||||
bitmonero_private_headers(rpc
|
||||
monero_private_headers(rpc
|
||||
${rpc_private_headers})
|
||||
bitmonero_add_library(rpc
|
||||
monero_add_library(rpc
|
||||
${rpc_sources}
|
||||
${rpc_headers}
|
||||
${rpc_private_headers})
|
||||
|
||||
@@ -142,6 +142,7 @@ namespace cryptonote
|
||||
res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count();
|
||||
res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count();
|
||||
res.testnet = m_testnet;
|
||||
res.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1);
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
@@ -245,7 +246,7 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res)
|
||||
bool core_rpc_server::on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res)
|
||||
{
|
||||
CHECK_CORE_BUSY();
|
||||
res.status = "Failed";
|
||||
@@ -268,6 +269,42 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res)
|
||||
{
|
||||
CHECK_CORE_BUSY();
|
||||
res.status = "Failed";
|
||||
|
||||
if (m_restricted)
|
||||
{
|
||||
if (req.outputs.size() > MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT)
|
||||
{
|
||||
res.status = "Too many outs requested";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
cryptonote::COMMAND_RPC_GET_OUTPUTS_BIN::request req_bin;
|
||||
req_bin.outputs = req.outputs;
|
||||
cryptonote::COMMAND_RPC_GET_OUTPUTS_BIN::response res_bin;
|
||||
if(!m_core.get_outs(req_bin, res_bin))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// convert to text
|
||||
for (const auto &i: res_bin.outs)
|
||||
{
|
||||
res.outs.push_back(cryptonote::COMMAND_RPC_GET_OUTPUTS::outkey());
|
||||
cryptonote::COMMAND_RPC_GET_OUTPUTS::outkey &outkey = res.outs.back();
|
||||
outkey.key = epee::string_tools::pod_to_hex(i.key);
|
||||
outkey.mask = epee::string_tools::pod_to_hex(i.mask);
|
||||
outkey.unlocked = i.unlocked;
|
||||
}
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res)
|
||||
{
|
||||
CHECK_CORE_BUSY();
|
||||
@@ -387,6 +424,17 @@ namespace cryptonote
|
||||
res.txs_as_hex.push_back(e.as_hex);
|
||||
if (req.decode_as_json)
|
||||
res.txs_as_json.push_back(e.as_json);
|
||||
|
||||
// output indices too if not in pool
|
||||
if (pool_tx_hashes.find(tx_hash) == pool_tx_hashes.end())
|
||||
{
|
||||
bool r = m_core.get_tx_outputs_gindexs(tx_hash, e.output_indices);
|
||||
if (!r)
|
||||
{
|
||||
res.status = "Failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const auto& miss_tx, missed_txs)
|
||||
@@ -830,19 +878,19 @@ namespace cryptonote
|
||||
return reward;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::fill_block_header_responce(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_responce& responce)
|
||||
bool core_rpc_server::fill_block_header_response(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_response& response)
|
||||
{
|
||||
responce.major_version = blk.major_version;
|
||||
responce.minor_version = blk.minor_version;
|
||||
responce.timestamp = blk.timestamp;
|
||||
responce.prev_hash = string_tools::pod_to_hex(blk.prev_id);
|
||||
responce.nonce = blk.nonce;
|
||||
responce.orphan_status = orphan_status;
|
||||
responce.height = height;
|
||||
responce.depth = m_core.get_current_blockchain_height() - height - 1;
|
||||
responce.hash = string_tools::pod_to_hex(hash);
|
||||
responce.difficulty = m_core.get_blockchain_storage().block_difficulty(height);
|
||||
responce.reward = get_block_reward(blk);
|
||||
response.major_version = blk.major_version;
|
||||
response.minor_version = blk.minor_version;
|
||||
response.timestamp = blk.timestamp;
|
||||
response.prev_hash = string_tools::pod_to_hex(blk.prev_id);
|
||||
response.nonce = blk.nonce;
|
||||
response.orphan_status = orphan_status;
|
||||
response.height = height;
|
||||
response.depth = m_core.get_current_blockchain_height() - height - 1;
|
||||
response.hash = string_tools::pod_to_hex(hash);
|
||||
response.difficulty = m_core.get_blockchain_storage().block_difficulty(height);
|
||||
response.reward = get_block_reward(blk);
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -871,8 +919,8 @@ namespace cryptonote
|
||||
error_resp.message = "Internal error: can't get last block.";
|
||||
return false;
|
||||
}
|
||||
bool responce_filled = fill_block_header_responce(last_block, false, last_block_height, last_block_hash, res.block_header);
|
||||
if (!responce_filled)
|
||||
bool response_filled = fill_block_header_response(last_block, false, last_block_height, last_block_hash, res.block_header);
|
||||
if (!response_filled)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: can't produce valid response.";
|
||||
@@ -912,8 +960,8 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
|
||||
bool responce_filled = fill_block_header_responce(blk, false, block_height, block_hash, res.block_header);
|
||||
if (!responce_filled)
|
||||
bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.block_header);
|
||||
if (!response_filled)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: can't produce valid response.";
|
||||
@@ -923,6 +971,57 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_block_headers_range(const COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request& req, COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response& res, epee::json_rpc::error& error_resp){
|
||||
if(!check_core_busy())
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
|
||||
error_resp.message = "Core is busy.";
|
||||
return false;
|
||||
}
|
||||
const uint64_t bc_height = m_core.get_current_blockchain_height();
|
||||
if (req.start_height >= bc_height || req.end_height >= bc_height || req.start_height > req.end_height)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
|
||||
error_resp.message = "Invalid start/end heights.";
|
||||
return false;
|
||||
}
|
||||
for (uint64_t h = req.start_height; h <= req.end_height; ++h)
|
||||
{
|
||||
crypto::hash block_hash = m_core.get_block_id_by_height(h);
|
||||
block blk;
|
||||
bool have_block = m_core.get_block_by_hash(block_hash, blk);
|
||||
if (!have_block)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: can't get block by height. Height = " + boost::lexical_cast<std::string>(h) + ". Hash = " + epee::string_tools::pod_to_hex(block_hash) + '.';
|
||||
return false;
|
||||
}
|
||||
if (blk.miner_tx.vin.front().type() != typeid(txin_gen))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: coinbase transaction in the block has the wrong type";
|
||||
return false;
|
||||
}
|
||||
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
|
||||
if (block_height != h)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: coinbase transaction in the block has the wrong height";
|
||||
return false;
|
||||
}
|
||||
res.headers.push_back(block_header_response());
|
||||
bool responce_filled = fill_block_header_response(blk, false, block_height, block_hash, res.headers.back());
|
||||
if (!responce_filled)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: can't produce valid response.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp){
|
||||
if(!check_core_busy())
|
||||
{
|
||||
@@ -945,8 +1044,8 @@ namespace cryptonote
|
||||
error_resp.message = "Internal error: can't get block by height. Height = " + std::to_string(req.height) + '.';
|
||||
return false;
|
||||
}
|
||||
bool responce_filled = fill_block_header_responce(blk, false, req.height, block_hash, res.block_header);
|
||||
if (!responce_filled)
|
||||
bool response_filled = fill_block_header_response(blk, false, req.height, block_hash, res.block_header);
|
||||
if (!response_filled)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: can't produce valid response.";
|
||||
@@ -999,8 +1098,8 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
|
||||
bool responce_filled = fill_block_header_responce(blk, false, block_height, block_hash, res.block_header);
|
||||
if (!responce_filled)
|
||||
bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.block_header);
|
||||
if (!response_filled)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: can't produce valid response.";
|
||||
@@ -1041,7 +1140,14 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
res.height = m_core.get_current_blockchain_height();
|
||||
crypto::hash top_hash;
|
||||
if (!m_core.get_blockchain_top(res.height, top_hash))
|
||||
{
|
||||
res.status = "Failed";
|
||||
return false;
|
||||
}
|
||||
++res.height; // turn top block height into blockchain height
|
||||
res.top_block_hash = string_tools::pod_to_hex(top_hash);
|
||||
res.target_height = m_core.get_target_blockchain_height();
|
||||
res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block();
|
||||
res.target = m_core.get_blockchain_storage().get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
|
||||
@@ -1054,6 +1160,7 @@ namespace cryptonote
|
||||
res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count();
|
||||
res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count();
|
||||
res.testnet = m_testnet;
|
||||
res.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1);
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
@@ -1185,10 +1292,10 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<uint64_t, uint64_t> histogram;
|
||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
|
||||
try
|
||||
{
|
||||
histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts, req.unlocked);
|
||||
histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts, req.unlocked, req.recent_cutoff);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -1200,8 +1307,8 @@ namespace cryptonote
|
||||
res.histogram.reserve(histogram.size());
|
||||
for (const auto &i: histogram)
|
||||
{
|
||||
if (i.second >= req.min_count && (i.second <= req.max_count || req.max_count == 0))
|
||||
res.histogram.push_back(COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry(i.first, i.second));
|
||||
if (std::get<0>(i.second) >= req.min_count && (std::get<0>(i.second) <= req.max_count || req.max_count == 0))
|
||||
res.histogram.push_back(COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry(i.first, std::get<0>(i.second), std::get<1>(i.second), std::get<2>(i.second)));
|
||||
}
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
@@ -1215,12 +1322,19 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_fast_exit(const COMMAND_RPC_FAST_EXIT::request& req, COMMAND_RPC_FAST_EXIT::response& res)
|
||||
bool core_rpc_server::on_get_coinbase_tx_sum(const COMMAND_RPC_GET_COINBASE_TX_SUM::request& req, COMMAND_RPC_GET_COINBASE_TX_SUM::response& res, epee::json_rpc::error& error_resp)
|
||||
{
|
||||
cryptonote::core::set_fast_exit();
|
||||
m_p2p.deinit();
|
||||
m_core.deinit();
|
||||
return true;
|
||||
std::pair<uint64_t, uint64_t> amounts = m_core.get_coinbase_tx_sum(req.height, req.count);
|
||||
res.emission_amount = amounts.first;
|
||||
res.fee_amount = amounts.second;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_per_kb_fee_estimate(const COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request& req, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response& res, epee::json_rpc::error& error_resp)
|
||||
{
|
||||
res.fee = m_core.get_blockchain_storage().get_dynamic_per_kb_fee_estimate(req.grace_blocks);
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res)
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace cryptonote
|
||||
MAP_URI_AUTO_BIN2("/gethashes.bin", on_get_hashes, COMMAND_RPC_GET_HASHES_FAST)
|
||||
MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES)
|
||||
MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS)
|
||||
MAP_URI_AUTO_BIN2("/get_outs.bin", on_get_outs, COMMAND_RPC_GET_OUTPUTS)
|
||||
MAP_URI_AUTO_BIN2("/get_outs.bin", on_get_outs_bin, COMMAND_RPC_GET_OUTPUTS_BIN)
|
||||
MAP_URI_AUTO_BIN2("/getrandom_rctouts.bin", on_get_random_rct_outs, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS)
|
||||
MAP_URI_AUTO_JON2("/gettransactions", on_get_transactions, COMMAND_RPC_GET_TRANSACTIONS)
|
||||
MAP_URI_AUTO_JON2("/is_key_image_spent", on_is_key_image_spent, COMMAND_RPC_IS_KEY_IMAGE_SPENT)
|
||||
@@ -94,10 +94,10 @@ namespace cryptonote
|
||||
MAP_URI_AUTO_JON2("/get_transaction_pool", on_get_transaction_pool, COMMAND_RPC_GET_TRANSACTION_POOL)
|
||||
MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted)
|
||||
MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO)
|
||||
MAP_URI_AUTO_JON2_IF("/fast_exit", on_fast_exit, COMMAND_RPC_FAST_EXIT, !m_restricted)
|
||||
MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted)
|
||||
MAP_URI_AUTO_JON2_IF("/start_save_graph", on_start_save_graph, COMMAND_RPC_START_SAVE_GRAPH, !m_restricted)
|
||||
MAP_URI_AUTO_JON2_IF("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH, !m_restricted)
|
||||
MAP_URI_AUTO_JON2("/get_outs", on_get_outs, COMMAND_RPC_GET_OUTPUTS)
|
||||
BEGIN_JSON_RPC_MAP("/json_rpc")
|
||||
MAP_JON_RPC("getblockcount", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT)
|
||||
MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH)
|
||||
@@ -106,6 +106,7 @@ namespace cryptonote
|
||||
MAP_JON_RPC_WE("getlastblockheader", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER)
|
||||
MAP_JON_RPC_WE("getblockheaderbyhash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH)
|
||||
MAP_JON_RPC_WE("getblockheaderbyheight", on_get_block_header_by_height, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT)
|
||||
MAP_JON_RPC_WE("getblockheadersrange", on_get_block_headers_range, COMMAND_RPC_GET_BLOCK_HEADERS_RANGE)
|
||||
MAP_JON_RPC_WE("getblock", on_get_block, COMMAND_RPC_GET_BLOCK)
|
||||
MAP_JON_RPC_WE_IF("get_connections", on_get_connections, COMMAND_RPC_GET_CONNECTIONS, !m_restricted)
|
||||
MAP_JON_RPC_WE("get_info", on_get_info_json, COMMAND_RPC_GET_INFO)
|
||||
@@ -115,6 +116,8 @@ namespace cryptonote
|
||||
MAP_JON_RPC_WE_IF("flush_txpool", on_flush_txpool, COMMAND_RPC_FLUSH_TRANSACTION_POOL, !m_restricted)
|
||||
MAP_JON_RPC_WE("get_output_histogram", on_get_output_histogram, COMMAND_RPC_GET_OUTPUT_HISTOGRAM)
|
||||
MAP_JON_RPC_WE("get_version", on_get_version, COMMAND_RPC_GET_VERSION)
|
||||
MAP_JON_RPC_WE("get_coinbase_tx_sum", on_get_coinbase_tx_sum, COMMAND_RPC_GET_COINBASE_TX_SUM)
|
||||
MAP_JON_RPC_WE("get_fee_estimate", on_get_per_kb_fee_estimate, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE)
|
||||
END_JSON_RPC_MAP()
|
||||
END_URI_MAP2()
|
||||
|
||||
@@ -129,6 +132,7 @@ namespace cryptonote
|
||||
bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res);
|
||||
bool on_mining_status(const COMMAND_RPC_MINING_STATUS::request& req, COMMAND_RPC_MINING_STATUS::response& res);
|
||||
bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res);
|
||||
bool on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res);
|
||||
bool on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res);
|
||||
bool on_get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res);
|
||||
bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
|
||||
@@ -138,7 +142,6 @@ namespace cryptonote
|
||||
bool on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res);
|
||||
bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res);
|
||||
bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res);
|
||||
bool on_fast_exit(const COMMAND_RPC_FAST_EXIT::request& req, COMMAND_RPC_FAST_EXIT::response& res);
|
||||
bool on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res);
|
||||
bool on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res);
|
||||
bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res);
|
||||
@@ -151,6 +154,7 @@ namespace cryptonote
|
||||
bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_block_headers_range(const COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request& req, COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_block(const COMMAND_RPC_GET_BLOCK::request& req, COMMAND_RPC_GET_BLOCK::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_connections(const COMMAND_RPC_GET_CONNECTIONS::request& req, COMMAND_RPC_GET_CONNECTIONS::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_info_json(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, epee::json_rpc::error& error_resp);
|
||||
@@ -160,6 +164,8 @@ namespace cryptonote
|
||||
bool on_flush_txpool(const COMMAND_RPC_FLUSH_TRANSACTION_POOL::request& req, COMMAND_RPC_FLUSH_TRANSACTION_POOL::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_output_histogram(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request& req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_version(const COMMAND_RPC_GET_VERSION::request& req, COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_coinbase_tx_sum(const COMMAND_RPC_GET_COINBASE_TX_SUM::request& req, COMMAND_RPC_GET_COINBASE_TX_SUM::response& res, epee::json_rpc::error& error_resp);
|
||||
bool on_get_per_kb_fee_estimate(const COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request& req, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response& res, epee::json_rpc::error& error_resp);
|
||||
//-----------------------
|
||||
|
||||
private:
|
||||
@@ -172,7 +178,7 @@ private:
|
||||
|
||||
//utils
|
||||
uint64_t get_block_reward(const block& blk);
|
||||
bool fill_block_header_responce(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_responce& responce);
|
||||
bool fill_block_header_response(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_response& response);
|
||||
|
||||
core& m_core;
|
||||
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
|
||||
|
||||
@@ -41,7 +41,16 @@ namespace cryptonote
|
||||
#define CORE_RPC_STATUS_BUSY "BUSY"
|
||||
#define CORE_RPC_STATUS_NOT_MINING "NOT MINING"
|
||||
|
||||
#define CORE_RPC_VERSION 3
|
||||
// When making *any* change here, bump minor
|
||||
// If the change is incompatible, then bump major and set minor to 0
|
||||
// This ensures CORE_RPC_VERSION always increases, that every change
|
||||
// has its own version, and that clients can just test major to see
|
||||
// whether they can talk to a given daemon without having to know in
|
||||
// advance which version they will stop working with
|
||||
// Don't go over 32767 for any of these
|
||||
#define CORE_RPC_VERSION_MAJOR 1
|
||||
#define CORE_RPC_VERSION_MINOR 0
|
||||
#define CORE_RPC_VERSION (((CORE_RPC_VERSION_MAJOR)<<16)|(CORE_RPC_VERSION_MINOR))
|
||||
|
||||
struct COMMAND_RPC_GET_HEIGHT
|
||||
{
|
||||
@@ -162,6 +171,7 @@ namespace cryptonote
|
||||
std::string as_json;
|
||||
bool in_pool;
|
||||
uint64_t block_height;
|
||||
std::vector<uint64_t> output_indices;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_hash)
|
||||
@@ -169,6 +179,7 @@ namespace cryptonote
|
||||
KV_SERIALIZE(as_json)
|
||||
KV_SERIALIZE(in_pool)
|
||||
KV_SERIALIZE(block_height)
|
||||
KV_SERIALIZE(output_indices)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
@@ -291,22 +302,22 @@ namespace cryptonote
|
||||
};
|
||||
};
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_GET_OUTPUTS
|
||||
struct get_outputs_out
|
||||
{
|
||||
struct out
|
||||
{
|
||||
uint64_t amount;
|
||||
uint64_t index;
|
||||
uint64_t amount;
|
||||
uint64_t index;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount)
|
||||
KV_SERIALIZE(index)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount)
|
||||
KV_SERIALIZE(index)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_OUTPUTS_BIN
|
||||
{
|
||||
struct request
|
||||
{
|
||||
std::vector<out> outputs;
|
||||
std::vector<get_outputs_out> outputs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(outputs)
|
||||
@@ -337,6 +348,42 @@ namespace cryptonote
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_GET_OUTPUTS
|
||||
{
|
||||
struct request
|
||||
{
|
||||
std::vector<get_outputs_out> outputs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(outputs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct outkey
|
||||
{
|
||||
std::string key;
|
||||
std::string mask;
|
||||
bool unlocked;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(key)
|
||||
KV_SERIALIZE(mask)
|
||||
KV_SERIALIZE(unlocked)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::vector<outkey> outs;
|
||||
std::string status;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(outs)
|
||||
KV_SERIALIZE(status)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS
|
||||
{
|
||||
@@ -464,6 +511,7 @@ namespace cryptonote
|
||||
uint64_t grey_peerlist_size;
|
||||
bool testnet;
|
||||
std::string top_block_hash;
|
||||
uint64_t cumulative_difficulty;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status)
|
||||
@@ -480,6 +528,7 @@ namespace cryptonote
|
||||
KV_SERIALIZE(grey_peerlist_size)
|
||||
KV_SERIALIZE(testnet)
|
||||
KV_SERIALIZE(top_block_hash)
|
||||
KV_SERIALIZE(cumulative_difficulty)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
@@ -631,7 +680,7 @@ namespace cryptonote
|
||||
};
|
||||
};
|
||||
|
||||
struct block_header_responce
|
||||
struct block_header_response
|
||||
{
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
@@ -671,7 +720,7 @@ namespace cryptonote
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
block_header_responce block_header;
|
||||
block_header_response block_header;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(block_header)
|
||||
@@ -695,7 +744,7 @@ namespace cryptonote
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
block_header_responce block_header;
|
||||
block_header_response block_header;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(block_header)
|
||||
@@ -719,7 +768,7 @@ namespace cryptonote
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
block_header_responce block_header;
|
||||
block_header_response block_header;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(block_header)
|
||||
@@ -745,7 +794,7 @@ namespace cryptonote
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
block_header_responce block_header;
|
||||
block_header_response block_header;
|
||||
std::vector<std::string> tx_hashes;
|
||||
std::string blob;
|
||||
std::string json;
|
||||
@@ -855,6 +904,8 @@ namespace cryptonote
|
||||
uint64_t last_failed_height;
|
||||
std::string last_failed_id_hash;
|
||||
uint64_t receive_time;
|
||||
bool relayed;
|
||||
uint64_t last_relayed_time;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(id_hash)
|
||||
@@ -867,6 +918,8 @@ namespace cryptonote
|
||||
KV_SERIALIZE(last_failed_height)
|
||||
KV_SERIALIZE(last_failed_id_hash)
|
||||
KV_SERIALIZE(receive_time)
|
||||
KV_SERIALIZE(relayed)
|
||||
KV_SERIALIZE(last_failed_id_hash)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
@@ -940,7 +993,7 @@ namespace cryptonote
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
std::vector<block_header_responce> headers;
|
||||
std::vector<block_header_response> headers;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status)
|
||||
@@ -1172,26 +1225,33 @@ namespace cryptonote
|
||||
uint64_t min_count;
|
||||
uint64_t max_count;
|
||||
bool unlocked;
|
||||
uint64_t recent_cutoff;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amounts);
|
||||
KV_SERIALIZE(min_count);
|
||||
KV_SERIALIZE(max_count);
|
||||
KV_SERIALIZE(unlocked);
|
||||
KV_SERIALIZE(recent_cutoff);
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct entry
|
||||
{
|
||||
uint64_t amount;
|
||||
uint64_t instances;
|
||||
uint64_t total_instances;
|
||||
uint64_t unlocked_instances;
|
||||
uint64_t recent_instances;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount);
|
||||
KV_SERIALIZE(instances);
|
||||
KV_SERIALIZE(total_instances);
|
||||
KV_SERIALIZE(unlocked_instances);
|
||||
KV_SERIALIZE(recent_instances);
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
entry(uint64_t amount, uint64_t instances): amount(amount), instances(instances) {}
|
||||
entry(uint64_t amount, uint64_t total_instances, uint64_t unlocked_instances, uint64_t recent_instances):
|
||||
amount(amount), total_instances(total_instances), unlocked_instances(unlocked_instances), recent_instances(recent_instances) {}
|
||||
entry() {}
|
||||
};
|
||||
|
||||
@@ -1226,5 +1286,54 @@ namespace cryptonote
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
struct COMMAND_RPC_GET_COINBASE_TX_SUM
|
||||
{
|
||||
struct request
|
||||
{
|
||||
uint64_t height;
|
||||
uint64_t count;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(height);
|
||||
KV_SERIALIZE(count);
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
uint64_t emission_amount;
|
||||
uint64_t fee_amount;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status)
|
||||
KV_SERIALIZE(emission_amount)
|
||||
KV_SERIALIZE(fee_amount)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE
|
||||
{
|
||||
struct request
|
||||
{
|
||||
uint64_t grace_blocks;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(grace_blocks)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
uint64_t fee;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status)
|
||||
KV_SERIALIZE(fee)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
100
src/serialization/list.h
Normal file
100
src/serialization/list.h
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2014-2015, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "serialization.h"
|
||||
|
||||
namespace serialization
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename Archive, class T>
|
||||
bool serialize_list_element(Archive& ar, T& e)
|
||||
{
|
||||
return ::do_serialize(ar, e);
|
||||
}
|
||||
|
||||
template <typename Archive>
|
||||
bool serialize_list_element(Archive& ar, uint64_t& e)
|
||||
{
|
||||
ar.serialize_varint(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <template <bool> class Archive, class T>
|
||||
bool do_serialize(Archive<false> &ar, std::list<T> &l)
|
||||
{
|
||||
size_t cnt;
|
||||
ar.begin_array(cnt);
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
l.clear();
|
||||
|
||||
// very basic sanity check
|
||||
if (ar.remaining_bytes() < cnt) {
|
||||
ar.stream().setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
if (i > 0)
|
||||
ar.delimit_array();
|
||||
l.push_back(T());
|
||||
T &t = l.back();
|
||||
if (!::serialization::detail::serialize_list_element(ar, t))
|
||||
return false;
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
}
|
||||
ar.end_array();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <template <bool> class Archive, class T>
|
||||
bool do_serialize(Archive<true> &ar, std::list<T> &l)
|
||||
{
|
||||
size_t cnt = l.size();
|
||||
ar.begin_array(cnt);
|
||||
for (typename std::list<T>::iterator i = l.begin(); i != l.end(); ++i) {
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
if (i != l.begin())
|
||||
ar.delimit_array();
|
||||
if(!::serialization::detail::serialize_list_element(ar, *i))
|
||||
return false;
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
}
|
||||
ar.end_array();
|
||||
return true;
|
||||
}
|
||||
96
src/serialization/pair.h
Normal file
96
src/serialization/pair.h
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2014-2015, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "serialization.h"
|
||||
|
||||
namespace serialization
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename Archive, class T>
|
||||
bool serialize_pair_element(Archive& ar, T& e)
|
||||
{
|
||||
return ::do_serialize(ar, e);
|
||||
}
|
||||
|
||||
template <typename Archive>
|
||||
bool serialize_pair_element(Archive& ar, uint64_t& e)
|
||||
{
|
||||
ar.serialize_varint(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <template <bool> class Archive, class F, class S>
|
||||
inline bool do_serialize(Archive<false>& ar, std::pair<F,S>& p)
|
||||
{
|
||||
size_t cnt;
|
||||
ar.begin_array(cnt);
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
if (cnt != 2)
|
||||
return false;
|
||||
|
||||
if (!::serialization::detail::serialize_pair_element(ar, p.first))
|
||||
return false;
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
ar.delimit_array();
|
||||
if (!::serialization::detail::serialize_pair_element(ar, p.second))
|
||||
return false;
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
|
||||
ar.end_array();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <template <bool> class Archive, class F, class S>
|
||||
inline bool do_serialize(Archive<true>& ar, std::pair<F,S>& p)
|
||||
{
|
||||
ar.begin_array(2);
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
if(!::serialization::detail::serialize_pair_element(ar, p.first))
|
||||
return false;
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
ar.delimit_array();
|
||||
if(!::serialization::detail::serialize_pair_element(ar, p.second))
|
||||
return false;
|
||||
if (!ar.stream().good())
|
||||
return false;
|
||||
ar.end_array();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
@@ -59,6 +60,16 @@ struct is_blob_type { typedef boost::false_type type; };
|
||||
template <class T>
|
||||
struct has_free_serializer { typedef boost::true_type type; };
|
||||
|
||||
/*! \struct is_pair_type
|
||||
*
|
||||
* \brief a descriptor for dispatching serialize
|
||||
*/
|
||||
template <class T>
|
||||
struct is_pair_type { typedef boost::false_type type; };
|
||||
|
||||
template<typename F, typename S>
|
||||
struct is_pair_type<std::pair<F,S>> { typedef boost::true_type type; };
|
||||
|
||||
/*! \struct serializer
|
||||
*
|
||||
* \brief ... wouldn't a class be better?
|
||||
@@ -75,20 +86,26 @@ struct has_free_serializer { typedef boost::true_type type; };
|
||||
template <class Archive, class T>
|
||||
struct serializer{
|
||||
static bool serialize(Archive &ar, T &v) {
|
||||
return serialize(ar, v, typename boost::is_integral<T>::type(), typename is_blob_type<T>::type());
|
||||
return serialize(ar, v, typename boost::is_integral<T>::type(), typename is_blob_type<T>::type(), typename is_pair_type<T>::type());
|
||||
}
|
||||
static bool serialize(Archive &ar, T &v, boost::false_type, boost::true_type) {
|
||||
template<typename A>
|
||||
static bool serialize(Archive &ar, T &v, boost::false_type, boost::true_type, A a) {
|
||||
ar.serialize_blob(&v, sizeof(v));
|
||||
return true;
|
||||
}
|
||||
static bool serialize(Archive &ar, T &v, boost::true_type, boost::false_type) {
|
||||
template<typename A>
|
||||
static bool serialize(Archive &ar, T &v, boost::true_type, boost::false_type, A a) {
|
||||
ar.serialize_int(v);
|
||||
return true;
|
||||
}
|
||||
static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type) {
|
||||
static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type, boost::false_type) {
|
||||
//serialize_custom(ar, v, typename has_free_serializer<T>::type());
|
||||
return v.do_serialize(ar);
|
||||
}
|
||||
static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type, boost::true_type) {
|
||||
//serialize_custom(ar, v, typename has_free_serializer<T>::type());
|
||||
return do_serialize(ar, v);
|
||||
}
|
||||
static void serialize_custom(Archive &ar, T &v, boost::true_type) {
|
||||
}
|
||||
};
|
||||
@@ -328,3 +345,5 @@ namespace serialization {
|
||||
|
||||
#include "string.h"
|
||||
#include "vector.h"
|
||||
#include "list.h"
|
||||
#include "pair.h"
|
||||
|
||||
@@ -27,18 +27,16 @@
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
set(simplewallet_sources
|
||||
simplewallet.cpp
|
||||
password_container.cpp)
|
||||
simplewallet.cpp)
|
||||
|
||||
set(simplewallet_headers)
|
||||
|
||||
set(simplewallet_private_headers
|
||||
simplewallet.h
|
||||
password_container.h)
|
||||
simplewallet.h)
|
||||
|
||||
bitmonero_private_headers(simplewallet
|
||||
monero_private_headers(simplewallet
|
||||
${simplewallet_private_headers})
|
||||
bitmonero_add_executable(simplewallet
|
||||
monero_add_executable(simplewallet
|
||||
${simplewallet_sources}
|
||||
${simplewallet_headers}
|
||||
${simplewallet_private_headers})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,13 +37,14 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
#include "cryptonote_core/account.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "wallet/wallet2.h"
|
||||
#include "console_handler.h"
|
||||
#include "password_container.h"
|
||||
#include "wallet/password_container.h"
|
||||
#include "crypto/crypto.h" // for definition of crypto::secret_key
|
||||
|
||||
/*!
|
||||
@@ -58,7 +59,6 @@ namespace cryptonote
|
||||
class simple_wallet : public tools::i_wallet2_callback
|
||||
{
|
||||
public:
|
||||
static bool get_password(const boost::program_options::variables_map& vm, bool allow_entry, tools::password_container &pwd_container);
|
||||
static const char *tr(const char *str) { return i18n_translate(str, "cryptonote::simple_wallet"); }
|
||||
|
||||
public:
|
||||
@@ -70,7 +70,6 @@ namespace cryptonote
|
||||
bool run();
|
||||
void stop();
|
||||
void interrupt();
|
||||
bool generate_from_json(const boost::program_options::variables_map& vm, std::string &wallet_file, std::string &password);
|
||||
|
||||
//wallet *create_wallet();
|
||||
bool process_command(const std::vector<std::string> &args);
|
||||
@@ -82,13 +81,11 @@ namespace cryptonote
|
||||
|
||||
void wallet_idle_thread();
|
||||
|
||||
bool new_wallet(const std::string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key,
|
||||
bool recover, bool two_random, bool testnet, const std::string &old_language);
|
||||
bool new_wallet(const std::string &wallet_file, const std::string& password, const cryptonote::account_public_address& address,
|
||||
const crypto::secret_key& spendkey, const crypto::secret_key& viewkey, bool testnet);
|
||||
bool new_wallet(const std::string &wallet_file, const std::string& password, const cryptonote::account_public_address& address,
|
||||
const crypto::secret_key& viewkey, bool testnet);
|
||||
bool open_wallet(const std::string &wallet_file, const std::string& password, bool testnet);
|
||||
bool new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key,
|
||||
bool recover, bool two_random, const std::string &old_language);
|
||||
bool new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address,
|
||||
const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey);
|
||||
bool open_wallet(const boost::program_options::variables_map& vm);
|
||||
bool close_wallet();
|
||||
|
||||
bool viewkey(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
@@ -110,6 +107,7 @@ namespace cryptonote
|
||||
bool set_default_mixin(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_auto_refresh(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_refresh_type(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool set_confirm_missing_payment_id(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool help(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool start_mining(const std::vector<std::string> &args);
|
||||
bool stop_mining(const std::vector<std::string> &args);
|
||||
@@ -123,8 +121,11 @@ namespace cryptonote
|
||||
bool transfer_main(int transfer_type, const std::vector<std::string> &args);
|
||||
bool transfer(const std::vector<std::string> &args);
|
||||
bool transfer_new(const std::vector<std::string> &args);
|
||||
bool locked_transfer(const std::vector<std::string> &args);
|
||||
bool sweep_all(const std::vector<std::string> &args);
|
||||
bool sweep_unmixable(const std::vector<std::string> &args);
|
||||
bool sign_transfer(const std::vector<std::string> &args);
|
||||
bool submit_transfer(const std::vector<std::string> &args);
|
||||
std::vector<std::vector<cryptonote::tx_destination_entry>> split_amounts(
|
||||
std::vector<cryptonote::tx_destination_entry> dsts, size_t num_splits
|
||||
);
|
||||
@@ -148,10 +149,15 @@ namespace cryptonote
|
||||
bool verify(const std::vector<std::string> &args);
|
||||
bool export_key_images(const std::vector<std::string> &args);
|
||||
bool import_key_images(const std::vector<std::string> &args);
|
||||
bool export_outputs(const std::vector<std::string> &args);
|
||||
bool import_outputs(const std::vector<std::string> &args);
|
||||
|
||||
uint64_t get_daemon_blockchain_height(std::string& err);
|
||||
bool try_connect_to_daemon(bool silent = false);
|
||||
bool ask_wallet_create_if_needed();
|
||||
bool accept_loaded_tx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message = std::string());
|
||||
bool accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs);
|
||||
bool accept_loaded_tx(const tools::wallet2::signed_tx_set &txs);
|
||||
bool get_address_from_str(const std::string &str, cryptonote::account_public_address &address, bool &has_payment_id, crypto::hash8 &payment_id);
|
||||
|
||||
/*!
|
||||
@@ -247,10 +253,6 @@ namespace cryptonote
|
||||
bool m_restoring; // are we restoring, by whatever method?
|
||||
uint64_t m_restore_height; // optional
|
||||
|
||||
std::string m_daemon_address;
|
||||
std::string m_daemon_host;
|
||||
int m_daemon_port;
|
||||
|
||||
epee::console_handlers_binder m_cmd_binder;
|
||||
|
||||
std::unique_ptr<tools::wallet2> m_wallet;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define MONERO_VERSION_TAG "@VERSIONTAG@"
|
||||
#define MONERO_VERSION "0.10.0.0"
|
||||
#define MONERO_VERSION "0.10.1.0"
|
||||
#define MONERO_RELEASE_NAME "Wolfram Warptangent"
|
||||
#define MONERO_VERSION_FULL MONERO_VERSION "-" MONERO_VERSION_TAG
|
||||
|
||||
@@ -31,21 +31,26 @@
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
set(wallet_sources
|
||||
password_container.cpp
|
||||
wallet2.cpp
|
||||
wallet_args.cpp
|
||||
wallet_rpc_server.cpp
|
||||
api/wallet.cpp
|
||||
api/wallet_manager.cpp
|
||||
api/transaction_info.cpp
|
||||
api/transaction_history.cpp
|
||||
api/pending_transaction.cpp
|
||||
api/utils.cpp)
|
||||
api/utils.cpp
|
||||
api/address_book.cpp)
|
||||
|
||||
set(wallet_api_headers
|
||||
wallet2_api.h)
|
||||
|
||||
|
||||
set(wallet_private_headers
|
||||
password_container.h
|
||||
wallet2.h
|
||||
wallet_args.h
|
||||
wallet_errors.h
|
||||
wallet_rpc_server.h
|
||||
wallet_rpc_server_commands_defs.h
|
||||
@@ -55,11 +60,12 @@ set(wallet_private_headers
|
||||
api/transaction_info.h
|
||||
api/transaction_history.h
|
||||
api/pending_transaction.h
|
||||
api/common_defines.h)
|
||||
api/common_defines.h
|
||||
api/address_book.h)
|
||||
|
||||
bitmonero_private_headers(wallet
|
||||
monero_private_headers(wallet
|
||||
${wallet_private_headers})
|
||||
bitmonero_add_library(wallet
|
||||
monero_add_library(wallet
|
||||
${wallet_sources}
|
||||
${wallet_api_headers}
|
||||
${wallet_private_headers})
|
||||
@@ -76,6 +82,44 @@ target_link_libraries(wallet
|
||||
${Boost_REGEX_LIBRARY}
|
||||
PRIVATE
|
||||
${EXTRA_LIBRARIES})
|
||||
add_dependencies(wallet version)
|
||||
|
||||
if (NOT BUILD_GUI_DEPS)
|
||||
set(wallet_rpc_sources
|
||||
wallet_rpc_server.cpp)
|
||||
|
||||
set(wallet_rpc_headers)
|
||||
|
||||
set(wallet_rpc_private_headers
|
||||
wallet_rpc_server.h)
|
||||
|
||||
monero_private_headers(wallet_rpc_server
|
||||
${wallet_rpc_private_headers})
|
||||
monero_add_executable(wallet_rpc_server
|
||||
${wallet_rpc_sources}
|
||||
${wallet_rpc_headers}
|
||||
${wallet_rpc_private_headers})
|
||||
|
||||
target_link_libraries(wallet_rpc_server
|
||||
PRIVATE
|
||||
wallet
|
||||
rpc
|
||||
cryptonote_core
|
||||
crypto
|
||||
common
|
||||
${Boost_CHRONO_LIBRARY}
|
||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
add_dependencies(wallet_rpc_server version)
|
||||
set_property(TARGET wallet_rpc_server
|
||||
PROPERTY
|
||||
OUTPUT_NAME "monero-wallet-rpc")
|
||||
install(TARGETS wallet_rpc_server DESTINATION bin)
|
||||
endif()
|
||||
|
||||
|
||||
# build and install libwallet_merged only if we building for GUI
|
||||
if (BUILD_GUI_DEPS)
|
||||
|
||||
131
src/wallet/api/address_book.cpp
Normal file
131
src/wallet/api/address_book.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
|
||||
#include "address_book.h"
|
||||
#include "wallet.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Monero {
|
||||
|
||||
AddressBook::~AddressBook() {}
|
||||
|
||||
AddressBookImpl::AddressBookImpl(WalletImpl *wallet)
|
||||
: m_wallet(wallet) {}
|
||||
|
||||
bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description)
|
||||
{
|
||||
LOG_PRINT_L2("Adding row");
|
||||
|
||||
clearStatus();
|
||||
|
||||
cryptonote::account_public_address addr;
|
||||
bool has_payment_id;
|
||||
crypto::hash8 payment_id_short;
|
||||
if(!cryptonote::get_account_integrated_address_from_str(addr, has_payment_id, payment_id_short, m_wallet->m_wallet->testnet(), dst_addr)) {
|
||||
m_errorString = "Invalid destination address";
|
||||
m_errorCode = Invalid_Address;
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::hash pid32 = cryptonote::null_hash;
|
||||
bool long_pid = (payment_id.empty())? false : tools::wallet2::parse_long_payment_id(payment_id, pid32);
|
||||
if(!payment_id.empty() && !long_pid) {
|
||||
m_errorString = "Invalid payment ID";
|
||||
m_errorCode = Invalid_Payment_Id;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool r = m_wallet->m_wallet->add_address_book_row(addr,pid32,description);
|
||||
if (r)
|
||||
refresh();
|
||||
else
|
||||
m_errorCode = General_Error;
|
||||
return r;
|
||||
}
|
||||
|
||||
void AddressBookImpl::refresh()
|
||||
{
|
||||
LOG_PRINT_L2("Refreshing addressbook");
|
||||
|
||||
clearRows();
|
||||
|
||||
// Fetch from Wallet2 and create vector of AddressBookRow objects
|
||||
std::vector<tools::wallet2::address_book_row> rows = m_wallet->m_wallet->get_address_book();
|
||||
for (size_t i = 0; i < rows.size(); ++i) {
|
||||
tools::wallet2::address_book_row * row = &rows.at(i);
|
||||
|
||||
std::string payment_id = (row->m_payment_id == cryptonote::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id);
|
||||
std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->testnet(),row->m_address);
|
||||
|
||||
AddressBookRow * abr = new AddressBookRow(i, address, payment_id, row->m_description);
|
||||
m_rows.push_back(abr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool AddressBookImpl::deleteRow(int rowId)
|
||||
{
|
||||
LOG_PRINT_L2("Deleting address book row " << rowId);
|
||||
bool r = m_wallet->m_wallet->delete_address_book_row(rowId);
|
||||
if (r)
|
||||
refresh();
|
||||
return r;
|
||||
}
|
||||
|
||||
void AddressBookImpl::clearRows() {
|
||||
for (auto r : m_rows) {
|
||||
delete r;
|
||||
}
|
||||
m_rows.clear();
|
||||
}
|
||||
|
||||
void AddressBookImpl::clearStatus(){
|
||||
m_errorString = "";
|
||||
m_errorCode = 0;
|
||||
}
|
||||
|
||||
std::vector<AddressBookRow*> AddressBookImpl::getAll() const
|
||||
{
|
||||
return m_rows;
|
||||
}
|
||||
|
||||
|
||||
AddressBookImpl::~AddressBookImpl()
|
||||
{
|
||||
clearRows();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Bitmonero = Monero;
|
||||
69
src/wallet/api/address_book.h
Normal file
69
src/wallet/api/address_book.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2014-2016, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "wallet/wallet2_api.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
namespace Monero {
|
||||
|
||||
class AddressBookRow;
|
||||
class WalletImpl;
|
||||
|
||||
class AddressBookImpl : public AddressBook
|
||||
{
|
||||
public:
|
||||
AddressBookImpl(WalletImpl * wallet);
|
||||
~AddressBookImpl();
|
||||
|
||||
// Fetches addresses from Wallet2
|
||||
void refresh();
|
||||
std::vector<AddressBookRow*> getAll() const;
|
||||
bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description);
|
||||
bool deleteRow(int rowId);
|
||||
|
||||
// Error codes. See AddressBook:ErrorCode enum in wallet2_api.h
|
||||
std::string errorString() const {return m_errorString;}
|
||||
int errorCode() const {return m_errorCode;}
|
||||
|
||||
private:
|
||||
void clearRows();
|
||||
void clearStatus();
|
||||
|
||||
private:
|
||||
WalletImpl *m_wallet;
|
||||
std::vector<AddressBookRow*> m_rows;
|
||||
std::string m_errorString;
|
||||
int m_errorCode;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace Bitmonero = Monero;
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Bitmonero {
|
||||
namespace Monero {
|
||||
|
||||
PendingTransaction::~PendingTransaction() {}
|
||||
|
||||
@@ -69,11 +69,19 @@ string PendingTransactionImpl::errorString() const
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
std::vector<std::string> PendingTransactionImpl::txid() const
|
||||
{
|
||||
std::vector<std::string> txid;
|
||||
for (const auto &pt: m_pending_tx)
|
||||
txid.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(pt.tx)));
|
||||
return txid;
|
||||
}
|
||||
|
||||
bool PendingTransactionImpl::commit()
|
||||
{
|
||||
|
||||
LOG_PRINT_L0("m_pending_tx size: " << m_pending_tx.size());
|
||||
assert(m_pending_tx.size() == 1);
|
||||
LOG_PRINT_L3("m_pending_tx size: " << m_pending_tx.size());
|
||||
|
||||
try {
|
||||
while (!m_pending_tx.empty()) {
|
||||
auto & ptx = m_pending_tx.back();
|
||||
@@ -128,11 +136,18 @@ uint64_t PendingTransactionImpl::dust() const
|
||||
uint64_t PendingTransactionImpl::fee() const
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (const auto ptx : m_pending_tx) {
|
||||
for (const auto &ptx : m_pending_tx) {
|
||||
result += ptx.fee;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t PendingTransactionImpl::txCount() const
|
||||
{
|
||||
return m_pending_tx.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Bitmonero = Monero;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Bitmonero {
|
||||
namespace Monero {
|
||||
|
||||
class WalletImpl;
|
||||
class PendingTransactionImpl : public PendingTransaction
|
||||
@@ -49,6 +49,8 @@ public:
|
||||
uint64_t amount() const;
|
||||
uint64_t dust() const;
|
||||
uint64_t fee() const;
|
||||
std::vector<std::string> txid() const;
|
||||
uint64_t txCount() const;
|
||||
// TODO: continue with interface;
|
||||
|
||||
private:
|
||||
@@ -62,3 +64,5 @@ private:
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace Bitmonero = Monero;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
using namespace epee;
|
||||
|
||||
namespace Bitmonero {
|
||||
namespace Monero {
|
||||
|
||||
TransactionHistory::~TransactionHistory() {}
|
||||
|
||||
@@ -55,26 +55,50 @@ TransactionHistoryImpl::TransactionHistoryImpl(WalletImpl *wallet)
|
||||
|
||||
TransactionHistoryImpl::~TransactionHistoryImpl()
|
||||
{
|
||||
|
||||
for (auto t : m_history)
|
||||
delete t;
|
||||
}
|
||||
|
||||
int TransactionHistoryImpl::count() const
|
||||
{
|
||||
return m_history.size();
|
||||
boost::shared_lock<boost::shared_mutex> lock(m_historyMutex);
|
||||
int result = m_history.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
TransactionInfo *TransactionHistoryImpl::transaction(int index) const
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(m_historyMutex);
|
||||
// sanity check
|
||||
if (index < 0)
|
||||
return nullptr;
|
||||
unsigned index_ = static_cast<unsigned>(index);
|
||||
return index_ < m_history.size() ? m_history[index_] : nullptr;
|
||||
}
|
||||
|
||||
TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) const
|
||||
{
|
||||
return nullptr;
|
||||
boost::shared_lock<boost::shared_mutex> lock(m_historyMutex);
|
||||
auto itr = std::find_if(m_history.begin(), m_history.end(),
|
||||
[&](const TransactionInfo * ti) {
|
||||
return ti->hash() == id;
|
||||
});
|
||||
return itr != m_history.end() ? *itr : nullptr;
|
||||
}
|
||||
|
||||
std::vector<TransactionInfo *> TransactionHistoryImpl::getAll() const
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(m_historyMutex);
|
||||
return m_history;
|
||||
}
|
||||
|
||||
void TransactionHistoryImpl::refresh()
|
||||
{
|
||||
// multithreaded access:
|
||||
// boost::lock_guard<boost::mutex> guarg(m_historyMutex);
|
||||
// for "write" access, locking exclusively
|
||||
boost::unique_lock<boost::shared_mutex> lock(m_historyMutex);
|
||||
|
||||
// TODO: configurable values;
|
||||
uint64_t min_height = 0;
|
||||
uint64_t max_height = (uint64_t)-1;
|
||||
@@ -84,8 +108,6 @@ void TransactionHistoryImpl::refresh()
|
||||
delete t;
|
||||
m_history.clear();
|
||||
|
||||
|
||||
|
||||
// transactions are stored in wallet2:
|
||||
// - confirmed_transfer_details - out transfers
|
||||
// - unconfirmed_transfer_details - pending out transfers
|
||||
@@ -109,7 +131,7 @@ void TransactionHistoryImpl::refresh()
|
||||
ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
|
||||
ti->m_blockheight = pd.m_block_height;
|
||||
// TODO:
|
||||
// ti->m_timestamp = pd.m_timestamp;
|
||||
ti->m_timestamp = pd.m_timestamp;
|
||||
m_history.push_back(ti);
|
||||
|
||||
/* output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%20.20s %s %s %s")
|
||||
@@ -135,8 +157,8 @@ void TransactionHistoryImpl::refresh()
|
||||
const crypto::hash &hash = i->first;
|
||||
const tools::wallet2::confirmed_transfer_details &pd = i->second;
|
||||
|
||||
uint64_t fee = pd.m_amount_in - pd.m_amount_out;
|
||||
uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
|
||||
uint64_t fee = pd.m_amount_in - pd.m_amount_out;
|
||||
|
||||
|
||||
std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id);
|
||||
@@ -151,6 +173,7 @@ void TransactionHistoryImpl::refresh()
|
||||
ti->m_direction = TransactionInfo::Direction_Out;
|
||||
ti->m_hash = string_tools::pod_to_hex(hash);
|
||||
ti->m_blockheight = pd.m_block_height;
|
||||
ti->m_timestamp = pd.m_timestamp;
|
||||
|
||||
// single output transaction might contain multiple transfers
|
||||
for (const auto &d: pd.m_dests) {
|
||||
@@ -180,14 +203,11 @@ void TransactionHistoryImpl::refresh()
|
||||
ti->m_failed = is_failed;
|
||||
ti->m_pending = true;
|
||||
ti->m_hash = string_tools::pod_to_hex(hash);
|
||||
ti->m_timestamp = pd.m_timestamp;
|
||||
m_history.push_back(ti);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TransactionInfo *TransactionHistoryImpl::transaction(int index) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
}
|
||||
namespace Bitmonero = Monero;
|
||||
|
||||
@@ -29,8 +29,9 @@
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "wallet/wallet2_api.h"
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
namespace Bitmonero {
|
||||
namespace Monero {
|
||||
|
||||
class TransactionInfo;
|
||||
class WalletImpl;
|
||||
@@ -51,7 +52,10 @@ private:
|
||||
// TransactionHistory is responsible of memory management
|
||||
std::vector<TransactionInfo*> m_history;
|
||||
WalletImpl *m_wallet;
|
||||
mutable boost::shared_mutex m_historyMutex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace Bitmonero = Monero;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Bitmonero {
|
||||
namespace Monero {
|
||||
|
||||
TransactionInfo::~TransactionInfo() {}
|
||||
|
||||
@@ -110,3 +110,5 @@ const std::vector<TransactionInfo::Transfer> &TransactionInfoImpl::transfers() c
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Bitmonero = Monero;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user