Compare commits

...

174 Commits

Author SHA1 Message Date
wowario
c70878b54e update git urls 2020-06-28 18:01:22 +03:00
jw
c8ed320949 Merge pull request #280 from wowario/gitian
gitian rename to wownero
2020-06-28 07:19:25 -07:00
jw
f7ba826cd2 Merge pull request #279 from wowario/warning
fix warning by removing std::move() on temporary http_client object
2020-06-28 07:19:12 -07:00
jw
e91b041c75 Merge pull request #278 from wowario/checkpoints
build: prepare v0.8.0.1 release
2020-06-28 07:18:43 -07:00
jw
aefce0c5fe Merge pull request #277 from wowario/off
build: disable trezor
2020-06-28 07:18:27 -07:00
jw
2f8ccfe0ca Merge pull request #276 from wowario/upstream
Upstream
2020-06-28 07:18:12 -07:00
wowario
a85e6fc276 gitian rename to wownero 2020-06-28 11:12:07 +03:00
woodser
0ce2ef719f fix warning by removing std::move() on temporary http_client object 2020-06-27 10:16:23 +03:00
wowario
9f5fa3f7f9 update checkpoints 2020-06-27 10:05:27 +03:00
wowario
c5e224944e build: disable trezor 2020-06-27 04:44:34 +03:00
Dusan Klinec
b5b1463487 add trezor support to sweep_single 2020-06-27 04:04:54 +03:00
moneromooo-monero
ae60c289f9 epee: fix array underflow in unicode parsing
Reported by minerscan

Also independently found by OSS-Fuzz just recently
2020-06-27 04:04:35 +03:00
moneromooo-monero
6da460a8df tx_pool: mine stem txes in fake chain mode
This fixes the functional tests, since txes would not be mined
after being sent to the daemon (they'd be waiting for the
dandelion timeout first)
2020-06-27 04:04:20 +03:00
moneromooo-monero
72655f78fc blockchain: fix timestamp/difficulty cache getting out of sync
The cache is discarded when a block is popped, but then gets
rebuilt when the difficulty for next block is requested.
While this is all properly locked, it does not take into account
the delay caused by a database transaction being only committed
(and thus its effects made visible to other threads) later on,
which means another thread could request difficulty between
the pop and the commit, which would end up using stale database
view to build the cache, but that cache would not be invalidated
again when the transaction gets committed, which would cause the
cache to not match the new database data.

To fix this, we now keep track of when the cache is invalidated
so we can invalidate it again upon database transaction commit
to ensure it gets calculated again with fresh data next time it
is nedeed.
2020-06-27 03:58:50 +03:00
Lee Clagett
4be84b7753 Fix D++ block template check 2020-06-27 03:53:37 +03:00
moneromooo-monero
b3847bc194 blockchain: fix total_height in getblocks.bin response 2020-06-27 03:53:19 +03:00
moneromooo-monero
c573ee65f6 rpc: fix loading rpc payment data from file
Got broken after making one of those micro optimizations requested on review..
2020-06-27 03:53:03 +03:00
moneromooo-monero
eb49cb728e rpc: fix comparison of seconds vs microseconds 2020-06-27 03:52:50 +03:00
moneromooo-monero
fd83d71bc7 functional_tests: add simple relay_tx test 2020-06-27 03:52:37 +03:00
moneromooo-monero
da1720ec30 rpc: fix relay_tx error return mixup 2020-06-27 03:52:22 +03:00
moneromooo-monero
6c652ef1ad daemon: remove time based "update needed" status string 2020-06-27 03:52:09 +03:00
moneromooo-monero
e592a515db rpc: don't display invalid json errors on default log level
It's not something the user needs to know, and will display
attacker controlled data
2020-06-27 03:51:55 +03:00
François Colas
5df0ffb57c Fix incorrect lenght of command INS_PREFIX_HASH
buffer_send[4] (LC) is an unsigned char, len should not
exceed 254 (255 - 1 for the option).
2020-06-27 03:51:41 +03:00
Denis Smirnov
d9939ce2fa fix typo in pick_preferred_rct_inputs 2020-06-27 03:51:27 +03:00
jw
29ebcc4e7e Merge pull request #274 from wowario/upstream
Upstream
2020-06-23 07:29:48 -07:00
jw
d759d13815 Merge pull request #272 from 00-matt/readme-gentoo
readme: Add Gentoo install instructions
2020-06-23 07:29:34 -07:00
jw
31ef8e30c4 Merge pull request #271 from wowario/rename
mining_status print output
2020-06-23 07:28:47 -07:00
jw
34779a4047 Merge pull request #270 from 00-matt/fix-boost173
Fix boost compatibility
2020-06-23 07:28:25 -07:00
jw
1b5a28351d Merge pull request #268 from Aluisyo/patch-5
update ppa keyserver keys
2020-06-23 07:27:15 -07:00
moneromooo-monero
c5d7dd9f18 fix a few typos in error messages
Reported by adrelanos
2020-06-23 07:27:04 +03:00
selsta
a4e2fac1ff workflows: update msys2 setup action v0 -> v1 2020-06-23 07:19:45 +03:00
selsta
b993d1b833 workflows: fix windows build 2020-06-22 18:41:43 +03:00
Matt Smith
d8b68a6369 readme: Add Gentoo install instructions 2020-06-22 15:06:37 +01:00
wowario
7c2b754321 mining_status print output 2020-06-22 17:05:23 +03:00
Lee Clagett
da7e511967 Fix boost <1.60 compilation and fix boost 1.73+ warnings 2020-06-22 15:01:41 +01:00
Suzyo Nyirenda
95afa9c538 update ppa keyserver keys 2020-06-10 13:26:58 +02:00
jw
c3e70dffc5 Merge pull request #264 from wowario/readme
remove link
2020-06-03 07:42:54 -07:00
清武 博二
72effc5c07 remove link 2020-06-03 08:52:30 +03:00
moneromooo-monero
804c985ecc rpc: add a sanity limit to a few RPC in restricted mode 2020-05-25 13:09:51 +03:00
moneromooo-monero
1861889b31 rpc: lock access to the rpc payment object 2020-05-25 13:09:37 +03:00
rbrunner7
81f79d900b [release-v0.16] MMS: New 'config_checksum' subcommand 2020-05-25 13:09:20 +03:00
Doyle
e0a9633557 ByteSlice: Fix persisting ptr to std::moved SSO buffer
The Bug:
1. Construct `byte_slice.portion_` with `epee::span(buffer)` which copies a pointer to the SSO buffer to `byte_slice.portion_`
2. It constructs `byte_slice.storage_` with `std::move(buffer)` (normally this swap pointers, but SSO means a memcpy and clear on the original SSO buffer)
3. `slice.data()` returns a pointer from `slice.portion_` that points to the original SSO cleared buffer, `slice.storage_` has the actual string.
2020-05-25 13:07:28 +03:00
moneromooo-monero
19f284ddf9 cryptonote_core: remove "We are most likely forked" message
It's time based and we don't have forks every 6 months anymore
2020-05-25 13:05:32 +03:00
moneromooo-monero
9c10229268 protocol: move the "peer claims higher version" warning to debug
Because there's a neverending supply of cunts claiming a wrong
version just to say "look at me" I guess
2020-05-25 13:05:18 +03:00
moneromooo-monero
18cb1753b7 wallet2: fix multisig data clearing stomping on a vector 2020-05-25 13:05:04 +03:00
moneromooo-monero
4eb2f5c2c8 serialization: fix bad rapidjson api usage 2020-05-25 13:04:50 +03:00
moneromooo-monero
e062e1efe3 cryptonote_protocol: stricter limit to number of objects requested
Reported by xnbya
2020-05-25 13:04:32 +03:00
moneromooo-monero
24660441a9 cryptonote_protocol: reject requests/notifications before handshake
Reported by xnbya
2020-05-25 13:04:17 +03:00
moneromooo-monero
1125b332d2 easylogging++: sanitize log payload
Some of it might be coming from untrusted sources

Reported by itsunixiknowthis
2020-05-25 13:04:04 +03:00
moneromooo-monero
009abd48e5 blockchain: detect and log bad difficulty calculations 2020-05-25 13:03:45 +03:00
moneromooo-monero
60cf237210 protocol: don't drop a connection if we can't get a compatible chain
This can now happen if:
- we have a pruned db
- we have not connected to the monero network for a while
- we connect to a node
- that node asks us for history
- we only have a pruned version of the most recent common block

In that case, it's better to not reply but keep the connection alive,
so we can sync off it.
2020-05-25 12:59:32 +03:00
moneromooo-monero
4ef1ab3e38 epee: use memwipe rather than memset for md5 secrets
That's used by HTTP auth now
2020-05-25 12:59:18 +03:00
jw
a37da20bc7 Merge pull request #261 from wowario/fix
build: fix boost 1.73 compatibility
2020-05-22 11:32:55 -07:00
selsta
7f868fafcc build: fix boost 1.73 compatibility 2020-05-22 21:27:12 +03:00
jw
1271a7e3a9 Merge pull request #259 from wowario/comment
comment out v16 fork
2020-05-19 11:51:20 -07:00
wowario
7a545ddc2d comment out v16 fork 2020-05-19 06:51:48 +03:00
jw
16a1f497e3 Merge pull request #258 from fuwa0529/SHA-3-tests
Sha 3 tests
2020-05-18 15:04:20 -07:00
jw
70804bd639 Merge pull request #257 from wowario/readme
add fork date to README.md
2020-05-18 15:04:10 -07:00
jw
3b1c27db69 Merge pull request #256 from wowario/SHA-3
switch to SHA-3 PoW
2020-05-18 15:03:57 -07:00
fuwa
ac29d15fc3 hash_tests: add sha3 2020-05-15 22:02:05 +08:00
fuwa
4b5eda696f hash_tests: disable slow-4, since wow uses cn-r 2020-05-15 22:01:59 +08:00
fuwa
533f58dae6 tests: fix build for wow 2020-05-15 22:01:56 +08:00
wowario
eeffe5c719 add fork date to README.md 2020-05-15 08:50:40 +03:00
wowario
87dcc37776 switch to SHA-3 PoW
Co-authored-by: fuwa <fuwa0529@users.noreply.github.com>
2020-05-15 08:37:36 +03:00
jw
6e43f020ae Merge pull request #255 from wowario/last
upstream
2020-05-14 08:40:03 -07:00
jw
57a5022f7d Merge pull request #254 from wowario/build
build: prepare v0.8.0.0 release
2020-05-14 08:39:46 -07:00
Lee Clagett
4c757a7a2a Fixed bugs for take_slice and byte_stream->byte_slice 2020-05-14 18:25:49 +03:00
moneromooo-monero
febb8df4bb blockchain: fix theoretical race getting bulk timestamps 2020-05-14 18:25:14 +03:00
moneromooo-monero
e74aff06c2 simplewallet: don't complain about incoming payment ids on change 2020-05-14 18:24:45 +03:00
wowario
7e3dbdde05 build: prepare v0.8.0.0 release 2020-05-14 17:44:48 +03:00
jw
116d29906c Merge pull request #253 from wowario/testforks
add testnet fork heights
2020-05-11 09:22:15 -07:00
wowario
9d31efa09e add testnet fork heights 2020-05-11 18:37:41 +03:00
jw
12a2a4084b Merge pull request #252 from wowario/testnet
refactor difficulty for testnet
2020-05-11 07:35:01 -07:00
jw
d1859d6224 Merge pull request #251 from wowario/upstream
Upstream
2020-05-11 07:05:44 -07:00
wowario
193c15ecce refactor difficulty for testnet 2020-05-09 23:22:28 +03:00
xiphon
eeadc8b723 p2p: startup speedup, init seed nodes on first 'connect_to_seed()' 2020-05-09 12:14:03 +03:00
moneromooo-monero
3a8f49f79c cryptonote_core: take out the time based upgrade warning
It doesn't really work anymore since we don't have a fork soon
2020-05-09 11:41:37 +03:00
xiphon
1e981f5be6 wallet2: fix keys file deserialization exception handling 2020-05-09 11:41:04 +03:00
moneromooo-monero
b59ef9a359 cryptonote_protocol: do not request pruned borromean sig txes
We don't have a function to calculate their weight from a pruned
version (yet).
2020-05-09 11:40:31 +03:00
Lee Clagett
e1bba18cc5 Fixes for ZMQ JSON-RPC endpoint names for raw tx 2020-05-09 11:40:06 +03:00
moneromooo-monero
a018e01370 wallet2: fix subaddress expansion when receiving monero 2020-05-09 11:39:42 +03:00
moneromooo-monero
014bc83b5e message_store: don't print an error when there is no mms file
It confuses people
2020-05-09 11:39:15 +03:00
xiphon
a0048e2a49 rpc: fix 'use_bootstrap_daemon_if_necessary' return value 2020-05-09 11:38:49 +03:00
xiphon
30ed4a23bf wallet2: check_connection return false on get_version status != OK 2020-05-09 11:38:25 +03:00
Lee Clagett
0e59f26064 Used legacy category to match insert_key_images behavior 2020-05-09 11:38:05 +03:00
Lee Clagett
a3fc63fa78 Revert functional test changes in babf25d2e and 571546067 2020-05-09 11:37:44 +03:00
moneromooo-monero
0c201ab438 cryptonote: fix reuse of non default tx data when relaying
An automatic tx variable is initialized properly on the first
run through the loop, but not the second. Moving the variable
inside the loop ensures the ctor is called again to init it.
2020-05-09 11:37:19 +03:00
xiphon
4cb99f9365 cryptonote_core: skip dns checkpoints on startup if not enforced 2020-05-09 11:36:53 +03:00
moneromooo-monero
c26c40472d simplewallet: report timestamp based expected unlock time on balance 2020-05-09 11:36:23 +03:00
moneromooo-monero
9ac662cb14 use memwipe on secret k/alpha values
Reported by UkoeHB_ and sarang
2020-05-09 11:35:47 +03:00
Lee Clagett
0b8e49a0aa Add byte_stream for zero-copy serialization, and add support in ZMQ-JSON. 2020-05-09 11:35:23 +03:00
jw
f879d48df7 Merge pull request #250 from wowario/upstream
Upstream
2020-05-04 08:27:07 -07:00
jw
603ca020ed Merge pull request #249 from fuwa0529/remove-unbound-rebased
Remove remove unbound
2020-05-04 08:26:40 -07:00
Sarang Noether
ecc2c3b707 Bulletproofs: verification speedup 2020-05-04 17:45:02 +03:00
Sumo Gr
8347fb8d58 unit_tests: fix gcc+ warning 2020-05-04 17:45:02 +03:00
xiphon
2b8bab2132 bootstrap_daemon: fix missing virtual destructor and lambda capture (clang warning) 2020-05-04 17:45:02 +03:00
mj-xmr
9b70fad289 FindCcache automatically 2020-05-04 17:45:02 +03:00
moneromooo-monero
4aad596a95 simplewallet: add sweep_account command
Expects an account number, then the usual sweep_all options

Useful to move monero that was accidentally sent to a subaddress
with a very large account index.
2020-05-04 17:45:02 +03:00
Dusan Klinec
ebe75aaa5f trezor: adapt to new passphrase mechanism
- choice where to enter passphrase is now made on the host
- use wipeable string in the comm stack
- wipe passphrase memory
- protocol optimizations, prepare for new firmware version
- minor fixes and improvements
- tests fixes, HF12 support
2020-05-04 17:45:01 +03:00
Sumo Gr
f5765455c5 simplewallet : missing function block separator 2020-05-04 17:45:01 +03:00
sumogr
9fde7e7253 simplewallet: fix strings (show_transfers & export_transfers) 2020-05-04 10:14:57 +03:00
cslashm
43cadb23b6 Add timelock verification on device 2020-05-04 10:14:35 +03:00
ArqTras
b5920da958 openssl update
Not available source updated

g version
2020-05-04 10:14:11 +03:00
Lee Clagett
9fb542e89c Use byte_slice for sending zmq messages - removes data copy within zmq 2020-05-04 10:13:38 +03:00
Sumo Gr
39e2802b9a txpool.cpp: rename var to fix for old g++ version (xenial default) 2020-05-04 10:13:12 +03:00
Lee Clagett
2f8fff39bf Always reject duplicate key-images from second txid 2020-05-04 10:12:11 +03:00
Lee Clagett
839a9e3707 Allow unrestricted rpc calls to get full txpool info 2020-05-04 10:11:52 +03:00
moneromooo-monero
2dcfca2799 functional_tests: ensure signatures never reuse a timestamp 2020-05-04 10:11:31 +03:00
moneromooo-monero
47b8e6437a functional_tests: ensure signed timestamps are fresh
This fixes a test failure now that timestamps are more constrained
2020-05-04 10:11:11 +03:00
xiphon
a0b1b89534 wallet_api: checkUpdate - optional version and buildtag params 2020-05-04 10:10:37 +03:00
Sumo Gr
b38aac4a81 update openssl 1.0.2r link 2020-05-04 10:10:12 +03:00
moneromooo-monero
0df692a814 daemon: fix print_net_stats RPC calls 2020-05-04 10:08:49 +03:00
Lee Clagett
b7be110ec3 Fixed string_ref usage bug in epee::from_hex::vector 2020-05-04 10:08:22 +03:00
woodser
3278e86ed8 Allow wallet2.h to run in WebAssembly
- Add abstract_http_client.h which http_client.h extends.
- Replace simple_http_client with abstract_http_client in wallet2,
message_store, message_transporter, and node_rpc_proxy.
- Import and export wallet data in wallet2.
- Use #if defined __EMSCRIPTEN__ directives to skip incompatible code.
2020-05-04 10:07:52 +03:00
rbrunner7
5fcc5da9f7 Daemon: Print estimates for time until fully synced 2020-05-04 10:07:26 +03:00
fuwa
8f17e8c0af Revert "remove unbound"
This reverts commit d9e982cba569c72a17801857addd4fb9ad929449.
2020-05-02 16:47:02 +08:00
fuwa
03743db2ed Revert "fix unbound on static build"
This reverts commit 86b6758dad0137fb997b320892ff7e59c575d26a.
2020-05-02 16:47:02 +08:00
jw
56c01e22bc Merge pull request #248 from qvqc/dev-v0.8
WOW'up translations
2020-04-30 09:36:19 -07:00
qvqc
6a5f0688b8 WOW'up translations 2020-04-30 11:55:27 -04:00
jw
459f8da6af Merge pull request #246 from wownero/revert-245-tor
Revert "allow sync over tor"
2020-04-22 17:05:05 -07:00
jw
acab673a6e Revert "allow sync over tor" 2020-04-22 17:03:37 -07:00
jw
ed16ffcb4e Merge pull request #245 from fuwa0529/tor
allow sync over tor
2020-04-22 16:32:42 -07:00
fuwa
d3184d030d allow sync over tor 2020-04-23 06:35:50 +08:00
jw
a17e36f1f5 Merge pull request #244 from qvqc/dev-v0.8
Dev v0.8
2020-04-22 14:53:13 -07:00
qvqc
7747151e98 update current seed nodes 2020-04-22 17:10:35 -04:00
qvqc
24974ccd36 update p2p peers in readme 2020-04-22 17:10:14 -04:00
jw
9312008532 Merge pull request #242 from fuwa0529/dev-v0.8
add tor peers
2020-04-22 10:58:28 -07:00
fuwa
7a73554c04 add tor peers 2020-04-22 21:43:32 +08:00
jw
b39feaad30 Merge pull request #240 from fuwa0529/dev-v0.8
duplicate v0.8 ASCII art in wallet-rpc
2020-04-18 10:18:23 -07:00
jw
67eaf231ad Merge pull request #239 from wowario/upstream
Upstream
2020-04-18 10:17:58 -07:00
fuwa
c74ff98e78 duplicate v0.8 ASCII art in wallet-rpc 2020-04-19 00:26:59 +08:00
Lee Clagett
94f4af6cc4 Adding Dandelion++ support to public networks:
- New flag in NOTIFY_NEW_TRANSACTION to indicate stem mode
  - Stem loops detected in tx_pool.cpp
  - Embargo timeout for a blackhole attack during stem phase
2020-04-18 11:24:38 +03:00
Lee Clagett
d4c7ae4554 Correct key image check in tx_pool 2020-04-18 11:24:04 +03:00
Sumo Gr
8d6e97ba0d depends: update qt 5.7.1 download link
5.7.1 was removed from official qt.io archive, this is one of the few mirrors remaining that keep a copy.
I think it would be better if @TheCharlatan updated to a newer version soon than merging this PR
2020-04-18 11:23:39 +03:00
moneromooo-monero
a33c86d875 blockchain_db: faster fetching of consecutive txes
Useful for wallet refresh or node sync
2020-04-18 11:23:01 +03:00
moneromooo-monero
b33dfc2ee4 simplewallet: fix smart mining not starting after first setup
Also avoid rewriting the wallet if the setting is already was we need
2020-04-18 11:22:32 +03:00
moneromooo-monero
1bbb2cbd63 simplewallet: new "address one-off <major> <minor>" command 2020-04-18 11:22:02 +03:00
jw
ca0abf8615 Merge pull request #238 from fuwa0529/dev-v0.8
fix unbound on static build
2020-04-12 10:53:27 -07:00
fuwa
146f5ea3f4 fix unbound on static build 2020-04-12 23:37:57 +08:00
jw
dc517f5da6 Merge pull request #237 from fuwa0529/dev-v0.8
remove unbound
2020-04-12 07:55:47 -07:00
fuwa
f516f8ce23 remove unbound 2020-04-12 19:35:55 +08:00
jw
b0e3091152 Merge pull request #236 from wowario/rebase
Rebase
2020-04-06 08:12:44 -07:00
wowario
f30b320d41 update Dockerfile 2020-04-06 18:04:07 +03:00
wowario
ca5db2fb30 update PKGBUILD 2020-04-06 18:03:58 +03:00
wowario
3c0737a8c0 drop test build 2020-04-06 15:21:12 +03:00
wowario
40d7bec2a7 update approx_blockchain_height 2020-04-06 14:26:05 +03:00
wowario
4fae945114 bender 2020-04-06 14:06:42 +03:00
wowario
c9a8f4f01c update checkpoints.dat 2020-04-06 13:10:35 +03:00
wowario
69663861e0 add v0.8 ASCII art 2020-04-06 09:47:39 +03:00
wowario
aafa830f85 update RandomWOW submodule 2020-04-06 09:40:49 +03:00
wowario
6a9515697e build: prepare v0.7.1.0 update
Signed-off-by: wowario <wowario@protonmail.com>
2020-04-06 09:09:32 +03:00
清武 博二
65f6d4cc47 Update README.md 2020-04-06 09:09:32 +03:00
wowario
5ebb10cb5b remove ded code 2020-04-06 09:09:32 +03:00
wowario
0705cff367 add wowario gpg key 2020-04-06 09:09:32 +03:00
wowario
2185265e44 update tor addresses 2020-04-06 09:09:32 +03:00
fuwa
3434473395 update the package name on NixOS 2020-04-06 09:09:31 +03:00
wowario
9d1e2828d4 absurdity day hard fork 2020-04-06 09:09:31 +03:00
wowario
cd36916956 update README 2020-04-06 09:09:31 +03:00
wowario
2bcaa4ec02 update checkpoints.dat 2020-04-06 09:09:31 +03:00
wowario
17d4fb378e fix hash2rct in get_exponent 2020-04-06 09:09:31 +03:00
fuwa
b78a40f7a4 fix cn-pow variant 2020-04-06 09:09:31 +03:00
wowario
cf607654b6 add RandomWOW submodule 2020-04-06 09:09:31 +03:00
wowario
a2ab66e258 remove Randomx submodule 2020-04-06 09:09:30 +03:00
fuwa
f764cf0626 remove zeromq completely 2020-04-06 09:09:30 +03:00
fuwa
338771fe21 hotfix "no ring" error 2020-04-06 09:09:30 +03:00
Suzyo Nyirenda
87f6f29c4b added public node (wow.aluisyo.network) 2020-04-06 09:09:30 +03:00
fuwa
22d3dc9a45 fix old bulletproof conditional branches 2020-04-06 09:09:30 +03:00
fuwa
140daa4783 wallet2: fix hf rules for small BP 2020-04-06 09:09:30 +03:00
wowario
e5e2ca539f sanity check: comment out #4691 2020-04-06 09:09:29 +03:00
wowario
1730faf01a sanity check: change to false #5434 2020-04-06 09:09:29 +03:00
fuwa
aff20484c3 allow system libminiupnp, revert #6b8539 2020-04-06 09:09:29 +03:00
wowario
6b1d4e67bc Cryptonight variant 4 aka cn/wow 2020-04-06 09:09:29 +03:00
wowario
e89be7b80c support old BP 2020-04-06 09:09:29 +03:00
wowario
652bd57080 initial commit 2020-04-06 09:09:17 +03:00
276 changed files with 11545 additions and 6647 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1 +1 @@
custom: https://web.getmonero.org/get-started/contributing/
custom: https://dev-funding.webui.wowkira.co

View File

@@ -16,17 +16,19 @@ jobs:
build-windows:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v1
with:
submodules: recursive
- uses: numworks/setup-msys2@v1
- name: update pacman
run: msys2do pacman -Syu --noconfirm
- name: install monero dependencies
run: msys2do pacman -S --noconfirm mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb git
- uses: eine/setup-msys2@v1
with:
update: true
install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb git
- name: build
run: msys2do make release-static-win64 -j2
run: make release-static-win64 -j2
build-ubuntu:
runs-on: ubuntu-latest
@@ -58,22 +60,3 @@ jobs:
- name: build
run: cmake -DBUILD_GUI_DEPS=ON && make -j3
test-ubuntu:
needs: build-ubuntu
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
submodules: recursive
- name: remove bundled boost
run: sudo rm -rf /usr/local/share/boost
- name: update apt
run: sudo apt update
- name: install monero dependencies
run: sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev
- name: install requests
run: pip install requests
- name: tests
env:
CTEST_OUTPUT_ON_FAILURE: ON
run: make release-test -j3

8
.gitmodules vendored
View File

@@ -12,6 +12,8 @@
[submodule "external/trezor-common"]
path = external/trezor-common
url = https://github.com/trezor/trezor-common.git
[submodule "external/randomx"]
path = external/randomx
url = https://github.com/tevador/RandomX
[submodule "external/RandomWOW"]
path = external/RandomWOW
url = https://github.com/wownero/RandomWOW
branch = 1.1.7-wow

View File

@@ -48,6 +48,8 @@ message(STATUS "CMake version ${CMAKE_VERSION}")
project(monero)
include(FindCcache) # Has to be included after the project() macro, to be able to read the CXX variable.
enable_language(C ASM)
function (die msg)
@@ -183,6 +185,15 @@ else()
message(STATUS "Building without build tag")
endif()
# Update and init submodules by default
if(NOT MANUAL_SUBMODULES)
find_package(Git)
if(GIT_FOUND)
message(STATUS "Initializing submodules")
execute_process(COMMAND git "submodule" "update" "--init" "--recursive" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
endif()
endif()
if(NOT MANUAL_SUBMODULES)
find_package(Git)
if(GIT_FOUND)
@@ -202,7 +213,7 @@ if(NOT MANUAL_SUBMODULES)
check_submodule(external/unbound)
check_submodule(external/rapidjson)
check_submodule(external/trezor-common)
check_submodule(external/randomx)
check_submodule(external/RandomWOW)
endif()
endif()
@@ -251,7 +262,7 @@ endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
enable_testing()
option(BUILD_DOCUMENTATION "Build the Doxygen documentation." ON)
option(BUILD_DOCUMENTATION "Build the Doxygen documentation." OFF)
option(BUILD_TESTS "Build tests." OFF)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(DEFAULT_BUILD_DEBUG_UTILITIES ON)
@@ -456,6 +467,14 @@ ExternalProject_Add(generate_translations_header
include_directories("${CMAKE_CURRENT_BINARY_DIR}/translations")
add_subdirectory(external)
# Final setup for miniupnpc
if(UPNP_STATIC OR IOS)
add_definitions("-DUPNP_STATIC")
else()
add_definitions("-DUPNP_DYNAMIC")
include_directories(${UPNP_INCLUDE})
endif()
# Final setup for libunbound
include_directories(${UNBOUND_INCLUDE})
link_directories(${UNBOUND_LIBRARY_DIRS})
@@ -953,6 +972,9 @@ find_library(NORM_LIBRARY norm)
find_library(PROTOLIB_LIBRARY protolib)
find_library(SODIUM_LIBRARY sodium)
set(ZMQ_INCLUDE_PATH zmq_dummy_include_path)
set(ZMQ_LIB zmq_dummy_lib_2)
if(NOT ZMQ_INCLUDE_PATH)
message(FATAL_ERROR "Could not find required header zmq.h")
endif()

View File

@@ -11,8 +11,6 @@ RUN set -ex && \
g++ \
make \
pkg-config \
graphviz \
doxygen \
git \
curl \
libtool-bin \
@@ -55,8 +53,8 @@ RUN set -ex \
ENV BOOST_ROOT /usr/local/boost_${BOOST_VERSION}
# OpenSSL
ARG OPENSSL_VERSION=1.1.1b
ARG OPENSSL_HASH=5c557b023230413dfb0756f3137a13e6d726838ccd1430888ad15bfb2b43ea4b
ARG OPENSSL_VERSION=1.1.1g
ARG OPENSSL_HASH=ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46
RUN set -ex \
&& curl -s -O https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
&& echo "${OPENSSL_HASH} openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c \
@@ -68,28 +66,6 @@ RUN set -ex \
&& make install
ENV OPENSSL_ROOT_DIR=/usr/local/openssl-${OPENSSL_VERSION}
# ZMQ
ARG ZMQ_VERSION=v4.3.2
ARG ZMQ_HASH=a84ffa12b2eb3569ced199660bac5ad128bff1f0
RUN set -ex \
&& git clone https://github.com/zeromq/libzmq.git -b ${ZMQ_VERSION} \
&& cd libzmq \
&& test `git rev-parse HEAD` = ${ZMQ_HASH} || exit 1 \
&& ./autogen.sh \
&& ./configure --enable-static --disable-shared \
&& make \
&& make install \
&& ldconfig
# zmq.hpp
ARG CPPZMQ_VERSION=v4.4.1
ARG CPPZMQ_HASH=f5b36e563598d48fcc0d82e589d3596afef945ae
RUN set -ex \
&& git clone https://github.com/zeromq/cppzmq.git -b ${CPPZMQ_VERSION} \
&& cd cppzmq \
&& test `git rev-parse HEAD` = ${CPPZMQ_HASH} || exit 1 \
&& mv *.hpp /usr/local/include
# Readline
ARG READLINE_VERSION=8.0
ARG READLINE_HASH=e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461
@@ -127,44 +103,6 @@ RUN set -ex \
&& make \
&& make install
# Libusb
ARG USB_VERSION=v1.0.22
ARG USB_HASH=0034b2afdcdb1614e78edaa2a9e22d5936aeae5d
RUN set -ex \
&& git clone https://github.com/libusb/libusb.git -b ${USB_VERSION} \
&& cd libusb \
&& test `git rev-parse HEAD` = ${USB_HASH} || exit 1 \
&& ./autogen.sh \
&& ./configure --disable-shared \
&& make \
&& make install
# Hidapi
ARG HIDAPI_VERSION=hidapi-0.8.0-rc1
ARG HIDAPI_HASH=40cf516139b5b61e30d9403a48db23d8f915f52c
RUN set -ex \
&& git clone https://github.com/signal11/hidapi -b ${HIDAPI_VERSION} \
&& cd hidapi \
&& test `git rev-parse HEAD` = ${HIDAPI_HASH} || exit 1 \
&& ./bootstrap \
&& ./configure --enable-static --disable-shared \
&& make \
&& make install
# Protobuf
ARG PROTOBUF_VERSION=v3.7.1
ARG PROTOBUF_HASH=6973c3a5041636c1d8dc5f7f6c8c1f3c15bc63d6
RUN set -ex \
&& git clone https://github.com/protocolbuffers/protobuf -b ${PROTOBUF_VERSION} \
&& cd protobuf \
&& test `git rev-parse HEAD` = ${PROTOBUF_HASH} || exit 1 \
&& git submodule update --init --recursive \
&& ./autogen.sh \
&& ./configure --enable-static --disable-shared \
&& make \
&& make install \
&& ldconfig
WORKDIR /src
COPY . .
@@ -188,25 +126,25 @@ RUN set -ex && \
rm -rf /var/lib/apt
COPY --from=builder /src/build/release/bin /usr/local/bin/
# Create monero user
RUN adduser --system --group --disabled-password monero && \
mkdir -p /wallet /home/monero/.bitmonero && \
chown -R monero:monero /home/monero/.bitmonero && \
chown -R monero:monero /wallet
# Create wownero user
RUN adduser --system --group --disabled-password wownero && \
mkdir -p /wallet /home/wownero/.wownero && \
chown -R wownero:wownero /home/wownero/.wownero && \
chown -R wownero:wownero /wallet
# Contains the blockchain
VOLUME /home/monero/.bitmonero
VOLUME /home/wownero/.wownero
# Generate your wallet via accessing the container and run:
# cd /wallet
# monero-wallet-cli
# wownero-wallet-cli
VOLUME /wallet
EXPOSE 18080
EXPOSE 18081
EXPOSE 34567
EXPOSE 34568
# switch to user monero
USER monero
# switch to user wownero
USER wownero
ENTRYPOINT ["monerod", "--p2p-bind-ip=0.0.0.0", "--p2p-bind-port=18080", "--rpc-bind-ip=0.0.0.0", "--rpc-bind-port=18081", "--non-interactive", "--confirm-external-bind"]
ENTRYPOINT ["wownerod", "--p2p-bind-ip=0.0.0.0", "--p2p-bind-port=34567", "--rpc-bind-ip=0.0.0.0", "--rpc-bind-port=34568", "--non-interactive", "--confirm-external-bind"]

View File

@@ -73,7 +73,7 @@ debug-test-trezor:
debug-all:
mkdir -p $(builddir)/debug
cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE)
cd $(builddir)/debug && cmake -D BUILD_TESTS=OFF -D USE_DEVICE_TREZOR=OFF -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE)
debug-static-all:
mkdir -p $(builddir)/debug
@@ -89,7 +89,7 @@ debug-static-win32:
cmake-release:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D CMAKE_BUILD_TYPE=Release $(topdir)
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D CMAKE_BUILD_TYPE=Release $(topdir)
release: cmake-release
cd $(builddir)/release && $(MAKE)
@@ -100,11 +100,11 @@ release-test:
release-all:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE)
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D USE_DEVICE_TREZOR=OFF -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE)
release-static:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE)
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D USE_DEVICE_TREZOR=OFF -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE)
coverage:
mkdir -p $(builddir)/debug
@@ -136,15 +136,15 @@ release-static-linux-armv8:
release-static-linux-x86_64:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x64" $(topdir) && $(MAKE)
cd $(builddir)/release && cmake -D STATIC=ON -D USE_DEVICE_TREZOR=OFF -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x64" $(topdir) && $(MAKE)
release-static-freebsd-x86_64:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" $(topdir) && $(MAKE)
cd $(builddir)/release && cmake -D STATIC=ON -D USE_DEVICE_TREZOR=OFF -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" $(topdir) && $(MAKE)
release-static-mac-x86_64:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" $(topdir) && $(MAKE)
cd $(builddir)/release && cmake -D STATIC=ON -D USE_DEVICE_TREZOR=OFF -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" $(topdir) && $(MAKE)
release-static-linux-i686:
mkdir -p $(builddir)/release
@@ -152,7 +152,7 @@ release-static-linux-i686:
release-static-win64:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=$(shell cd ${MINGW_PREFIX}/.. && pwd -W) $(topdir) && $(MAKE)
cd $(builddir)/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D USE_DEVICE_TREZOR=OFF -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=$(shell cd ${MINGW_PREFIX}/.. && pwd -W) $(topdir) && $(MAKE)
release-static-win32:
mkdir -p $(builddir)/release

65
PKGBUILD Normal file
View File

@@ -0,0 +1,65 @@
# Maintainer: wowario <wowario[at]protonmail[dot]com>
pkgname=wownero-git
pkgver=0.8.0.0
pkgrel=1
pkgdesc="Wownero: a fairly launched privacy-centric meme coin with no premine and a finite supply"
license=('BSD')
arch=('x86_64')
url="https://wownero.org/"
depends=('boost-libs' 'libunwind' 'openssl' 'readline' 'zeromq' 'pcsclite' 'hidapi' 'protobuf')
makedepends=('git' 'cmake' 'boost')
source=(
"${pkgname}"::"git+https://github.com/wownero/wownero#tag=v${pkgver}"
"git+https://github.com/monero-project/unbound.git"
"git+https://github.com/monero-project/miniupnp.git"
"git+https://github.com/Tencent/rapidjson.git"
"git+https://github.com/trezor/trezor-common.git"
"git+https://github.com/wownero/RandomWOW.git"
"wownero.sysusers"
"wownero.tmpfiles")
sha512sums=('SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP')
prepare() {
cd "${pkgname}"
git submodule init
git config submodule.external/unbound.url "$srcdir/unbound"
git config submodule.external/miniupnp.url "$srcdir/miniupnp"
git config submodule.external/rapidjson.url "$srcdir/rapidjson"
git config submodule.external/trezor-common.url "$srcdir/trezor-common"
git config submodule.external/RandomWOW.url "$srcdir/RandomWOW"
git submodule update
}
build() {
cd "${pkgname}"
mkdir -p build && cd build
cmake -D BUILD_TESTS=OFF -D CMAKE_BUILD_TYPE=release -D ARCH=default ../
make
}
package() {
backup=('etc/wownerod.conf')
cd "${pkgname}"
install -Dm644 "LICENSE" -t "${pkgdir}/usr/share/licenses/${pkgname}"
install -Dm644 "utils/conf/wownerod.conf" "${pkgdir}/etc/wownerod.conf"
install -Dm644 "utils/systemd/wownerod.service" "${pkgdir}/usr/lib/systemd/system/wownerod.service"
install -Dm644 "../wownero.sysusers" "${pkgdir}/usr/lib/sysusers.d/wownero.conf"
install -Dm644 "../wownero.tmpfiles" "${pkgdir}/usr/lib/tmpfiles.d/wownero.conf"
install -Dm755 "build/bin/wownero-wallet-cli" \
"build/bin/wownero-wallet-rpc" \
"build/bin/wownerod" \
-t "${pkgdir}/usr/bin"
}
# vim: ts=2 sw=2 et:

821
README.md
View File

@@ -1,603 +1,140 @@
# Monero
# ~~Mo~~Wownero - Such privacy! Many coins! Wow! 🐕
Copyright (c) 2014-2019 The Monero Project.
Portions Copyright (c) 2012-2013 The Cryptonote developers.
## Table of Contents
# CyberWOW
An Android pruned full node for Wownero
- [Development resources](#development-resources)
- [Vulnerability response](#vulnerability-response)
- [Research](#research)
- [Announcements](#announcements)
- [Translations](#translations)
- [Coverage](#coverage)
- [Introduction](#introduction)
- [About this project](#about-this-project)
- [Supporting the project](#supporting-the-project)
- [License](#license)
- [Contributing](#contributing)
- [Scheduled software upgrades](#scheduled-software-upgrades)
- [Release staging schedule and protocol](#release-staging-schedule-and-protocol)
- [Compiling Monero from source](#compiling-monero-from-source)
- [Dependencies](#dependencies)
- [Internationalization](#Internationalization)
- [Using Tor](#using-tor)
- [Debugging](#Debugging)
- [Known issues](#known-issues)
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/org.wownero.cyberwow/)
<a href='https://play.google.com/store/apps/details?id=org.wownero.cyberwow'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height='80'/></a>
## Development resources
# Wownerujo
An Android Wallet for Wownero
- 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](https://webchat.freenode.net/?randomnick=1&channels=%23monero-dev&prompt=1&uio=d4)
- It is HIGHLY recommended that you join the #monero-dev IRC channel if you are developing software that uses Monero. Due to the nature of this open source software project, joining this channel and idling is the best way to stay updated on best practices and new developments in the Monero ecosystem. All you need to do is join the IRC channel and idle to stay updated with the latest in Monero development. If you do not, you risk wasting resources on developing integrations that are not compatible with the Monero network. The Monero core team and community continuously make efforts to communicate updates, developments, and documentation via other platforms but for the best information, you need to talk to other Monero developers, and they are on IRC. #monero-dev is about Monero development, not getting help about using Monero, or help about development of other software, including yours, unless it also pertains to Monero code itself. For these cases, checkout #monero.
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/com.wownero.wownerujo/)
<a href='https://play.google.com/store/apps/details?id=com.wownero.wownerujo'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height='80'/></a>
## Vulnerability response
## Resources
- Our [Vulnerability Response Process](https://github.com/monero-project/meta/blob/master/VULNERABILITY_RESPONSE_PROCESS.md) encourages responsible disclosure
- We are also available via [HackerOne](https://hackerone.com/monero)
- Web: [wownero.org](http://wownero.org)
- Twitter: [@w0wn3r0](https://twitter.com/w0wn3r0)
- Reddit: [/r/wownero](https://www.reddit.com/r/wownero)
- Mail: [wownero@protonmail.com](mailto:wownero@protonmail.com)
- GitHub: [https://git.wownero.com/wownero/wownero](https://git.wownero.com/wownero/wownero)
- IRC: [#wownero on Freenode](https://kiwiirc.com/client/irc.freenode.net/?nick=suchchatter|?#wownero)
- Bitmessage Chan: wownero (`BM-2cSzWtrj2pzLva9GF1Jp2TYsnLjrnJpvba`)
- Wownero Funding System: [https://funding.wownero.com](https://funding.wownero.com)
## Research
Blockchain Explorers
- https://explore.wownero.com
- https://explorer.wowkira.com
- http://wow5eqtzqvsg5jctqzg5g7uk3u62sfqiacj5x6lo4by7bvnj6jkvubyd.onion
The [Monero Research Lab](https://src.getmonero.org/resources/research-lab/) is an open forum where the community coordinates research into Monero cryptography, protocols, fungibility, analysis, and more. We welcome collaboration and contributions from outside researchers! Because not all Lab work and publications are distributed as traditional preprints or articles, they may be easy to miss if you are conducting literature reviews for your own Monero research. You are encouraged to get in touch with our researchers if you have questions, wish to collaborate, or would like guidance to help avoid unnecessarily duplicating earlier or known work.
Free Public Nodes
- wow7dhbgiljnkspkzpjyy66auegbrye2ptfv4gucgbhireg5rrjza5ad.onion:34568
- so.wow.candy.surf:34568 (US)
- such.wow.candy.surf:34568 (CAN)
- very.wow.candy.surf:34568 (IN)
- much.wow.candy.surf:34568 (UK)
Our researchers are available on IRC in [#monero-research-lab on Freenode](https://webchat.freenode.net/?randomnick=1&channels=%23monero-research-lab&prompt=1&uio=d4) or by email:
- Sarang Noether, Ph.D.: [sarang@getmonero.org](mailto:sarang@getmonero.org) or [sarang.noether@protonmail.com](mailto:sarang.noether@protonmail.com); [research repository](https://github.com/SarangNoether/research-lab)
- Surae Noether (Brandon Goodell), Ph.D.: [surae@getmonero.org](mailto:surae@getmonero.org) or [surae.noether@protonmail.com](mailto:surae.noether@protonmail.com); [research repository](https://github.com/b-g-goodell/research-lab)
## Announcements
- You can subscribe to an [announcement listserv](https://lists.getmonero.org) to get critical announcements from the Monero core team. The announcement list can be very helpful for knowing when software updates are needed.
## Translations
The CLI wallet is available in different languages. If you want to help translate it, see our self-hosted localization platform, Weblate, on [translate.getmonero.org]( https://translate.getmonero.org/projects/monero/cli-wallet/). Every translation *must* be uploaded on the platform, pull requests directly editing the code in this repository will be closed. If you need help with Weblate, you can find a guide with screenshots [here](https://github.com/monero-ecosystem/monero-translations/blob/master/weblate.md).
&nbsp;
If you need help/support/info about translations, contact the localization workgroup. You can find the complete list of contacts on the repository of the workgroup: [monero-translations](https://github.com/monero-ecosystem/monero-translations#contacts).
## Coverage
| Type | Status |
|-----------|--------|
| Coverity | [![Coverity Status](https://scan.coverity.com/projects/9657/badge.svg)](https://scan.coverity.com/projects/9657/)
| Coveralls | [![Coveralls Status](https://coveralls.io/repos/github/monero-project/monero/badge.svg?branch=master)](https://coveralls.io/github/monero-project/monero?branch=master)
| License | [![License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
Tor Peers
- wowp2p5gelm6vhl2d5tvfqills63jilgy6hkvlrqljooov5ktaxgqdad.onion
- f3moshycuklu3mb3wnlfjwn26nsgzreqtfzfuyjjk46u7jqxlhf7d5id.onion
## Introduction
Monero is a private, secure, untraceable, decentralised digital currency. You are your bank, you control your funds, and nobody can trace your transfers unless you allow them to do so.
**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 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.
**Decentralization:** The utility of monero depends on its decentralised peer-to-peer consensus network - anyone should be able to run the monero software, validate the integrity of the blockchain, and participate in all aspects of the monero network using consumer-grade commodity hardware. Decentralization of the monero network is maintained by software development that minimizes the costs of running the monero software and inhibits the proliferation of specialized, non-commodity hardware.
## About this project
This is the core implementation of Monero. It is open source and completely free to use without restrictions, except for those specified in the license agreement below. There are no restrictions on anyone creating an alternative implementation of Monero that uses the protocol and network in a compatible manner.
As with many development projects, the repository on Github is considered to be the "staging" area for the latest changes. Before changes are merged into that branch on the main repository, they are tested by individual developers in their own branches, submitted as a pull request, and then subsequently tested by contributors who focus on testing and code reviews. That having been said, the repository should be carefully considered before using it in a production environment, unless there is a patch in the repository for a particular show-stopping issue you are experiencing. It is generally a better idea to use a tagged release for stability.
**Anyone is welcome to contribute to Monero's codebase!** If you have a fix or code change, feel free to submit it as a pull request directly to the "master" branch. In cases where the change is relatively small or does not affect other parts of the codebase it may be merged in immediately by any one of the collaborators. On the other hand, if the change is particularly large or complex, it is expected that it will be discussed at length either well in advance of the pull request being submitted, or even directly on the pull request.
## Supporting the project
Monero is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Both Monero and Bitcoin donations can be made to **donate.getmonero.org** if using a client that supports the [OpenAlias](https://openalias.org) standard. Alternatively you can send XMR to the Monero donation address via the `donate` command (type `help` in the command-line wallet for details).
The Monero donation address is: `44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A` (viewkey: `f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501`)
The Bitcoin donation address is: `1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H`
Core development funding and/or some supporting services are also graciously provided by sponsors:
[<img width="80" src="https://static.getmonero.org/images/sponsors/mymonero.png"/>](https://mymonero.com)
[<img width="150" src="https://static.getmonero.org/images/sponsors/kitware.png?1"/>](https://kitware.com)
[<img width="100" src="https://static.getmonero.org/images/sponsors/dome9.png"/>](https://dome9.com)
[<img width="150" src="https://static.getmonero.org/images/sponsors/araxis.png"/>](https://araxis.com)
[<img width="150" src="https://static.getmonero.org/images/sponsors/jetbrains.png"/>](https://www.jetbrains.com/)
[<img width="150" src="https://static.getmonero.org/images/sponsors/navicat.png"/>](https://www.navicat.com/)
[<img width="150" src="https://static.getmonero.org/images/sponsors/symas.png"/>](https://www.symas.com/)
There are also several mining pools that kindly donate a portion of their fees, [a list of them can be found on our Bitcointalk post](https://bitcointalk.org/index.php?topic=583449.0).
## License
See [LICENSE](LICENSE).
## Contributing
If you want to help out, see [CONTRIBUTING](CONTRIBUTING.md) for a set of guidelines.
Wownero is a privacy-centric memecoin that was fairly launched on April 1, 2018 with no pre-mine, stealth-mine or ICO. Wownero has a maximum supply of around 184 million WOW with a slow and steady emission over 50 years. It is a fork of Monero, but with its own genesis block, so there is no degradation of privacy due to ring signatures using different participants for the same tx outputs on opposing forks.
## Scheduled software upgrades
Monero uses a fixed-schedule software upgrade (hard fork) mechanism to implement new features. This means that users of Monero (end users and service providers) should run current versions and upgrade their software on a regular schedule. Software upgrades occur during the months of April and October. The required software for these upgrades will be available prior to the scheduled date. Please check the repository prior to this date for the proper Monero software version. Below is the historical schedule and the projected schedule for the next upgrade.
Dates are provided in the format YYYY-MM-DD.
Wownero uses a fixed-schedule software upgrade (hard fork) mechanism to implement new features. This means that users of Wownero (end users and service providers) should run current versions and upgrade their software on a regular schedule. The required software for these upgrades will be available prior to the scheduled date. Please check the repository prior to this date for the proper Wownero software version. Below is the historical schedule and the projected schedule for the next upgrade.
Dates are provided in the format YYYY-MM-DD.
| Software upgrade block height | Date | Fork version | Minimum Monero version | Recommended Monero version | Details |
| Software upgrade block height | Date | Release Name | Minimum Wownero version | Recommended Wownero version | Details |
| ------------------------------ | -----------| ----------------- | ---------------------- | -------------------------- | ---------------------------------------------------------------------------------- |
| 1009827 | 2016-03-22 | v2 | v0.9.4 | v0.9.4 | Allow only >= ringsize 3, blocktime = 120 seconds, fee-free blocksize 60 kb |
| 1141317 | 2016-09-21 | v3 | v0.9.4 | v0.10.0 | Splits coinbase into denominations |
| 1220516 | 2017-01-05 | v4 | v0.10.1 | v0.10.2.1 | Allow normal and RingCT transactions |
| 1288616 | 2017-04-15 | v5 | v0.10.3.0 | v0.10.3.1 | Adjusted minimum blocksize and fee algorithm |
| 1400000 | 2017-09-16 | v6 | v0.11.0.0 | v0.11.0.0 | Allow only RingCT transactions, allow only >= ringsize 5 |
| 1546000 | 2018-04-06 | v7 | v0.12.0.0 | v0.12.3.0 | Cryptonight variant 1, ringsize >= 7, sorted inputs
| 1685555 | 2018-10-18 | v8 | v0.13.0.0 | v0.13.0.4 | max transaction size at half the penalty free block size, bulletproofs enabled, cryptonight variant 2, fixed ringsize [11](https://youtu.be/KOO5S4vxi0o)
| 1686275 | 2018-10-19 | v9 | v0.13.0.0 | v0.13.0.4 | bulletproofs required
| 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format
| 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format
| 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.15.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
| 1 | 2018-04-01 | Awesome Akita | v0.1.0.0 | v0.1.0.0 | Cryptonight variant 1, ringsize >= 8, sorted inputs
| 69,69 | 2018-04-24 | Busty Brazzers | v0.2.0.0 | v0.2.0.0 | Bulletproofs, LWMA difficulty algorithm, ringsize >= 10, reduce unlock to 4
| 53,666 | 2018-10-06 | Cool Cage | v0.3.0.0 | v0.3.1.3 | Cryptonight variant 2, LWMA v2, ringsize = 22, MMS
| 63,469 | 2018-11-11 | Dank Doge | v0.4.0.0 | v0.4.0.0 | LWMA v4
| 81,769 | 2019-02-19 | Erotic EggplantEmoji | v0.5.0.0 | v0.5.0.2 | Cryptonight/wow, LWMA v1 with N=144, Updated Bulletproofs, Fee Per Byte, Auto-churn
| 114,969 | 2019-06-14 | F For Fappening | v0.6.1.0 | v0.6.1.2 | RandomWOW, new block weight algorithm, slightly more efficient RingCT format
| 160,777 | 2019-11-20 | Gaping Goatse | v0.7.0.0 | v0.7.1.0 | Only allow >= 2 outputs, change to the block median used to calculate penalty, rct sigs in coinbase forbidden, 4 unlock time as protocol rule
| 288,888 | 2021-02-08 | Hallucinogenic Hypnotoad | v0.8.0.0 | v0.8.0.1 | SHA3-256 PoW, Dandelion++ support
X's indicate that these details have not been determined as of commit date.
\* indicates estimate as of commit date
## Release staging schedule and protocol
## Release staging and Contributing
Approximately three months prior to a scheduled software upgrade, a branch from master will be created with the new release version tag. Pull requests that address bugs should then be made to both master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
**Anyone is welcome to contribute to Wownero's codebase!**
## Compiling Monero from source
If you have a fix or code change, feel free to submit it as a pull request. Ahead of a scheduled software upgrade, a development branch will be created with the new release version tag. Pull requests that address bugs should be made to Master. Pull requests that require review and testing (generally, optimizations and new features) should be made to the development branch. All pull requests will be considered safe until the US dollar valuation of 1 Wownero equals $1000. After this valuation has been reached, more research will be needed to introduce experimental cryptography and/or code into the codebase.
### Dependencies
The following table summarizes the tools and libraries required to build. A
few of the libraries are also included in this repository (marked as
"Vendored"). By default, the build uses the library installed on the system,
and ignores the vendored sources. However, if no library is found installed on
the system, then the vendored source will be built and used. The vendored
sources are also used for statically-linked builds because distribution
packages often include only shared library binaries (`.so`) but not static
library archives (`.a`).
| Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Void pkg | Fedora pkg | Optional | Purpose |
| ------------ | ------------- | -------- | -------------------- | ------------ | ------------------ | ------------------- | -------- | --------------- |
| GCC | 4.7.3 | NO | `build-essential` | `base-devel` | `base-devel` | `gcc` | NO | |
| CMake | 3.5 | NO | `cmake` | `cmake` | `cmake` | `cmake` | NO | |
| pkg-config | any | NO | `pkg-config` | `base-devel` | `base-devel` | `pkgconf` | NO | |
| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | `boost-devel` | `boost-devel` | NO | C++ libraries |
| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `libressl-devel` | `openssl-devel` | NO | sha256 sum |
| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | `zeromq-devel` | `zeromq-devel` | NO | ZeroMQ library |
| OpenPGM | ? | NO | `libpgm-dev` | `libpgm` | | `openpgm-devel` | NO | For ZeroMQ |
| libnorm[2] | ? | NO | `libnorm-dev` | | | | YES | For ZeroMQ |
| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | `unbound-devel` | NO | DNS resolver |
| libsodium | ? | NO | `libsodium-dev` | `libsodium` | `libsodium-devel` | `libsodium-devel` | NO | cryptography |
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | `libunwind-devel` | YES | Stack traces |
| liblzma | any | NO | `liblzma-dev` | `xz` | `liblzma-devel` | `xz-devel` | YES | For libunwind |
| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | `readline-devel` | YES | Input editing |
| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | `libldns-devel` | `ldns-devel` | YES | SSL toolkit |
| expat | 1.1 | NO | `libexpat1-dev` | `expat` | `expat-devel` | `expat-devel` | YES | XML parsing |
| GTest | 1.5 | YES | `libgtest-dev`[1] | `gtest` | `gtest-devel` | `gtest-devel` | YES | Test suite |
| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | `doxygen` | YES | Documentation |
| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | `graphviz` | YES | Documentation |
| lrelease | ? | NO | `qttools5-dev-tools` | `qt5-tools` | `qt5-tools` | `qt5-linguist` | YES | Translations |
| libhidapi | ? | NO | `libhidapi-dev` | `hidapi` | `hidapi-devel` | `hidapi-devel` | YES | Hardware wallet |
| libusb | ? | NO | `libusb-dev` | `libusb` | `libusb-devel` | `libusb-devel` | YES | Hardware wallet |
| libprotobuf | ? | NO | `libprotobuf-dev` | `protobuf` | `protobuf-devel` | `protobuf-devel` | YES | Hardware wallet |
| protoc | ? | NO | `protobuf-compiler` | `protobuf` | `protobuf` | `protobuf-compiler` | YES | Hardware wallet |
[1] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
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/ ```
[2] libnorm-dev is needed if your zmq library was built with libnorm, and not needed otherwise
Install all dependencies at once on Debian/Ubuntu:
``` sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libldns-dev libexpat1-dev doxygen graphviz libpgm-dev qttools5-dev-tools libhidapi-dev libusb-dev libprotobuf-dev protobuf-compiler ```
Install all dependencies at once on macOS with the provided Brewfile:
``` brew update && brew bundle --file=contrib/brew/Brewfile ```
FreeBSD one liner for required to build dependencies
```pkg install git gmake cmake pkgconf boost-libs libzmq libsodium```
### Cloning the repository
Clone recursively to pull-in needed submodule(s):
`$ git clone --recursive https://github.com/monero-project/monero`
If you already have a repo cloned, initialize and update:
`$ cd monero && git submodule init && git submodule update`
### Build instructions
Monero uses the CMake build system and a top-level [Makefile](Makefile) that
invokes cmake commands as needed.
#### On Linux and macOS
* Install the dependencies
* Change to the root of the source code directory, change to the most recent release branch, and build:
```bash
cd monero
git checkout release-v0.15
make
```
*Optional*: If your machine has several cores and enough memory, enable
parallel build by running `make -j<number of threads>` instead of `make`. For
this to be worthwhile, the machine should have one core and about 2GB of RAM
available per thread.
*Note*: The instructions above will compile the most stable release of the
Monero software. If you would like to use and test the most recent software,
use ```git checkout master```. The master branch may contain updates that are
both unstable and incompatible with release software, though testing is always
encouraged.
* 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:
```bash
make release-test
```
*NOTE*: `core_tests` test may take a few hours to complete.
* **Optional**: to build binaries suitable for debugging:
```bash
make debug
```
* **Optional**: to build statically-linked binaries:
```bash
make release-static
```
Dependencies need to be built with -fPIC. Static libraries usually aren't, so you may have to build them yourself with -fPIC. Refer to their documentation for how to build them.
* **Optional**: build documentation in `doc/html` (omit `HAVE_DOT=YES` if `graphviz` is not installed):
```bash
HAVE_DOT=YES doxygen Doxyfile
```
#### On the Raspberry Pi
Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (2017-09-07 or later) from https://www.raspberrypi.org/downloads/raspbian/. If you are using Raspian Jessie, [please see note in the following section](#note-for-raspbian-jessie-users).
* `apt-get update && apt-get upgrade` to install all of the latest software
* Install the dependencies for Monero from the 'Debian' column in the table above.
* Increase the system swap size:
```bash
sudo /etc/init.d/dphys-swapfile stop
sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=2048
sudo /etc/init.d/dphys-swapfile start
```
* If using an external hard disk without an external power supply, ensure it gets enough power to avoid hardware issues when syncing, by adding the line "max_usb_current=1" to /boot/config.txt
* Clone monero and checkout the most recent release version:
```bash
git clone https://github.com/monero-project/monero.git
cd monero
git checkout tags/v0.15.0.0
```
* Build:
```bash
make release
```
* Wait 4-6 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
#### *Note for Raspbian Jessie users:*
If you are using the older Raspbian Jessie image, compiling Monero is a bit more complicated. The version of Boost available in the Debian Jessie repositories is too old to use with Monero, and thus you must compile a newer version yourself. The following explains the extra steps, and has been tested on a Raspberry Pi 2 with a clean install of minimal Raspbian Jessie.
* As before, `apt-get update && apt-get upgrade` to install all of the latest software, and increase the system swap size
```bash
sudo /etc/init.d/dphys-swapfile stop
sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=2048
sudo /etc/init.d/dphys-swapfile start
```
* Then, install the dependencies for Monero except `libunwind` and `libboost-all-dev`
* Install the latest version of boost (this may first require invoking `apt-get remove --purge libboost*-dev` to remove a previous version if you're not using a clean install):
```bash
cd
wget https://sourceforge.net/projects/boost/files/boost/1.72.0/boost_1_72_0.tar.bz2
tar xvfo boost_1_72_0.tar.bz2
cd boost_1_72_0
./bootstrap.sh
sudo ./b2
```
* Wait ~8 hours
```bash
sudo ./bjam cxxflags=-fPIC cflags=-fPIC -a install
```
* Wait ~4 hours
* From here, follow the [general Raspberry Pi instructions](#on-the-raspberry-pi) from the "Clone monero and checkout most recent release version" step.
#### On Windows:
Binaries for Windows are built on Windows using the MinGW toolchain within
[MSYS2 environment](https://www.msys2.org). The MSYS2 environment emulates a
POSIX system. The toolchain runs within the environment and *cross-compiles*
binaries that can run outside of the environment as a regular Windows
application.
**Preparing the build environment**
* Download and install the [MSYS2 installer](https://www.msys2.org), either the 64-bit or the 32-bit package, depending on your system.
* Open the MSYS shell via the `MSYS2 Shell` shortcut
* Update packages using pacman:
```bash
pacman -Syu
```
* Exit the MSYS shell using Alt+F4
* Edit the properties for the `MSYS2 Shell` shortcut changing "msys2_shell.bat" to "msys2_shell.cmd -mingw64" for 64-bit builds or "msys2_shell.cmd -mingw32" for 32-bit builds
* Restart MSYS shell via modified shortcut and update packages again using pacman:
```bash
pacman -Syu
```
* Install dependencies:
To build for 64-bit Windows:
```bash
pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi
```
To build for 32-bit Windows:
```bash
pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi
```
* Open the MingW shell via `MinGW-w64-Win64 Shell` shortcut on 64-bit Windows
or `MinGW-w64-Win64 Shell` shortcut on 32-bit Windows. Note that if you are
running 64-bit Windows, you will have both 64-bit and 32-bit MinGW shells.
**Cloning**
* To git clone, run:
```bash
git clone --recursive https://github.com/monero-project/monero.git
```
**Building**
* Change to the cloned directory, run:
```bash
cd monero
```
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.15.0.0'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.15.0.0
```
* If you are on a 64-bit system, run:
```bash
make release-static-win64
```
* If you are on a 32-bit system, run:
```bash
make release-static-win32
```
* The resulting executables can be found in `build/release/bin`
* **Optional**: to build Windows binaries suitable for debugging on a 64-bit system, run:
```bash
make debug-static-win64
```
* **Optional**: to build Windows binaries suitable for debugging on a 32-bit system, run:
```bash
make debug-static-win32
```
* The resulting executables can be found in `build/debug/bin`
### On FreeBSD:
The project can be built from scratch by following instructions for Linux above(but use `gmake` instead of `make`).
If you are running monero in a jail, you need to add `sysvsem="new"` to your jail configuration, otherwise lmdb will throw the error message: `Failed to open lmdb environment: Function not implemented`.
Monero is also available as a port or package as 'monero-cli`.
### On OpenBSD:
You will need to add a few packages to your system. `pkg_add cmake gmake zeromq libiconv boost`.
The `doxygen` and `graphviz` packages are optional and require the xbase set.
Running the test suite also requires `py-requests` package.
Build monero: `env DEVELOPER_LOCAL_TOOLS=1 BOOST_ROOT=/usr/local gmake release-static`
Note: you may encounter the following error, when compiling the latest version of monero as a normal user:
```
LLVM ERROR: out of memory
c++: error: unable to execute command: Abort trap (core dumped)
```
Then you need to increase the data ulimit size to 2GB and try again: `ulimit -d 2000000`
### On Solaris:
The default Solaris linker can't be used, you have to install GNU ld, then run cmake manually with the path to your copy of GNU ld:
```bash
mkdir -p build/release
cd build/release
cmake -DCMAKE_LINKER=/path/to/ld -D CMAKE_BUILD_TYPE=Release ../..
cd ../..
```
Then you can run make as usual.
### On Linux for Android (using docker):
```bash
# Build image (for ARM 32-bit)
docker build -f utils/build_scripts/android32.Dockerfile -t monero-android .
# Build image (for ARM 64-bit)
docker build -f utils/build_scripts/android64.Dockerfile -t monero-android .
# Create container
docker create -it --name monero-android monero-android bash
# Get binaries
docker cp monero-android:/src/build/release/bin .
```
### Building portable statically linked binaries
By default, in either dynamically or statically linked builds, binaries target the specific host processor on which the build happens and are not portable to other processors. Portable binaries can be built using the following targets:
* ```make release-static-linux-x86_64``` builds binaries on Linux on x86_64 portable across POSIX systems on x86_64 processors
* ```make release-static-linux-i686``` builds binaries on Linux on x86_64 or i686 portable across POSIX systems on i686 processors
* ```make release-static-linux-armv8``` builds binaries on Linux portable across POSIX systems on armv8 processors
* ```make release-static-linux-armv7``` builds binaries on Linux portable across POSIX systems on armv7 processors
* ```make release-static-linux-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
### Cross Compiling
You can also cross-compile static binaries on Linux for Windows and macOS with the `depends` system.
* ```make depends target=x86_64-linux-gnu``` for 64-bit linux binaries.
* ```make depends target=x86_64-w64-mingw32``` for 64-bit windows binaries.
* Requires: `python3 g++-mingw-w64-x86-64 wine1.6 bc`
* ```make depends target=x86_64-apple-darwin11``` for macOS binaries.
* Requires: `cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev`
* ```make depends target=i686-linux-gnu``` for 32-bit linux binaries.
* Requires: `g++-multilib bc`
* ```make depends target=i686-w64-mingw32``` for 32-bit windows binaries.
* Requires: `python3 g++-mingw-w64-i686`
* ```make depends target=arm-linux-gnueabihf``` for armv7 binaries.
* Requires: `g++-arm-linux-gnueabihf`
* ```make depends target=aarch64-linux-gnu``` for armv8 binaries.
* Requires: `g++-aarch64-linux-gnu`
* ```make depends target=riscv64-linux-gnu``` for RISC V 64 bit binaries.
* Requires: `g++-riscv64-linux-gnu`
* ```make depends target=x86_64-unknown-freebsd``` for freebsd binaries.
* Requires: `clang-8`
* ```make depends target=arm-linux-android``` for 32bit android binaries
* ```make depends target=aarch64-linux-android``` for 64bit android binaries
The required packages are the names for each toolchain on apt. Depending on your distro, they may have different names.
Using `depends` might also be easier to compile Monero on Windows than using MSYS. Activate Windows Subsystem for Linux (WSL) with a distro (for example Ubuntu), install the apt build-essentials and follow the `depends` steps as depicted above.
The produced binaries still link libc dynamically. If the binary is compiled on a current distribution, it might not run on an older distribution with an older installation of libc. Passing `-DBACKCOMPAT=ON` to cmake will make sure that the binary will run on systems having at least libc version 2.17.
## Installing Monero from a package
**DISCLAIMER: These packages are not part of this repository or maintained by this project's contributors, and as such, do not go through the same review process to ensure their trustworthiness and security.**
## Installing from a package
Packages are available for
* Debian Bullseye and Sid
* Arch Linux/Manjaro
```bash
sudo apt install monero
```
More info and versions in the [Debian package tracker](https://tracker.debian.org/pkg/monero).
yay -S wownero-git
* Arch Linux (via [AUR](https://aur.archlinux.org/)):
- Stable release: [`monero`](https://aur.archlinux.org/packages/monero)
- Bleeding edge: [`monero-git`](https://aur.archlinux.org/packages/monero-git)
* Gentoo
* Void Linux:
emerge --noreplace eselect-repository
eselect repository enable monero
emaint sync -r monero
echo '*/*::monero ~amd64' >> /etc/portage/package.accept_keywords
emerge net-p2p/wownero
```bash
xbps-install -S monero
```
* NixOS
* GuixSD
nix-shell -p wownero
```bash
guix package -i monero
```
* Ubuntu 18.04/Ubuntu 16.04/Debian 9/Debian 8 (amd64)
* Docker
```bash
# Build using all available cores
docker build -t monero .
# or build using a specific number of cores (reduce RAM requirement)
docker build --build-arg NPROC=1 -t monero .
# either run in foreground
docker run -it -v /monero/chain:/root/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
# or in background
docker run -it -d -v /monero/chain:/root/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
```
* The build needs 3 GB space.
* Wait one hour or more
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 8BC34ABB48E565F0
sudo add-apt-repository "deb http://ppa.wownero.com/ bionic main"
sudo apt-get update
sudo apt-get install wownero
Packaging for your favorite distribution would be a welcome contribution!
## Running monerod
**DISCLAIMER: These packages are not part of this repository, and as such, do not go through the same review process to ensure their trustworthiness and security.**
## Building from Source
* Arch Linux/Manjaro
sudo pacman -Syu && sudo pacman -S base-devel cmake boost openssl zeromq libpgm unbound libsodium git
git clone https://git.wownero.com/wownero/wownero
cd wownero
make -j2
* Debian/Ubuntu
sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libpgm-dev git
git clone https://git.wownero.com/wownero/wownero
cd wownero
make -j2
## Running Binaries
The build places the binary in `bin/` sub-directory within the build directory
from which cmake was invoked (repository root by default). To run in
foreground:
```bash
./bin/monerod
```
./bin/wownerod
To list all available options, run `./bin/monerod --help`. Options can be
To list all available options, run `./bin/wownerod --help`. Options can be
specified either on the command line or in a configuration file passed by the
`--config-file` argument. To specify an option in the configuration file, add
a line with the syntax `argumentname=value`, where `argumentname` is the name
@@ -605,171 +142,53 @@ of the argument without the leading dashes, for example `log-level=1`.
To run in background:
```bash
./bin/monerod --log-file monerod.log --detach
```
./bin/wownerod --log-file wownerod.log --detach
To run as a systemd service, copy
[monerod.service](utils/systemd/monerod.service) to `/etc/systemd/system/` and
[monerod.conf](utils/conf/monerod.conf) to `/etc/`. The [example
service](utils/systemd/monerod.service) assumes that the user `monero` exists
[wownerod.service](utils/systemd/wownerod.service) to `/etc/systemd/system/` and
[wownerod.conf](utils/conf/wownerod.conf) to `/etc/`. The [example
service](utils/systemd/wownerod.service) assumes that the user `wownero` exists
and its home is the data directory specified in the [example
config](utils/conf/monerod.conf).
config](utils/conf/wownerod.conf).
If you're on Mac, you may need to add the `--max-concurrency 1` option to
monero-wallet-cli, and possibly monerod, if you get crashes refreshing.
Once node is synced to network, run the CLI wallet by entering:
## Internationalization
./bin/wownero-wallet-cli
See [README.i18n.md](README.i18n.md).
Type `help` in CLI wallet to see standard commands (for advanced options, type `help_advanced`).
## Using Tor
## Tor Anonymity Network
> There is a new, still experimental, [integration with Tor](ANONYMITY_NETWORKS.md). The
> feature allows connecting over IPv4 and Tor simulatenously - IPv4 is used for
> relaying blocks and relaying transactions received by peers whereas Tor is
> used solely for relaying transactions received over local RPC. This provides
> privacy and better protection against surrounding node (sybil) attacks.
* Install [Tor Browser](https://www.torproject.org/download/)
* Open `torrc` file in a text editor ([installation directory]/Browser/TorBrowser/Data/Tor/torrc) and add hidden service information as follows:
While Monero isn't made to integrate with Tor, it can be used wrapped with torsocks, by
setting the following configuration parameters and environment variables:
```
HiddenServiceDir [installation directory]/Browser/TorBrowser/Data/Tor/wow_node
HiddenServiceVersion 3
HiddenServicePort 44568 127.0.0.1:44568
```
* Save `torrc` file and restart Tor Browser (keep open)
* Change directory to the `wow_node` folder, open `hostname` file, and copy your node's ".onion" address
* Start wownerod with the following parameters:
* `--p2p-bind-ip 127.0.0.1` on the command line or `p2p-bind-ip=127.0.0.1` in
monerod.conf to disable listening for connections on external interfaces.
* `--no-igd` on the command line or `no-igd=1` in monerod.conf to disable IGD
(UPnP port forwarding negotiation), which is pointless with Tor.
* `DNS_PUBLIC=tcp` or `DNS_PUBLIC=tcp://x.x.x.x` where x.x.x.x is the IP of the
desired DNS server, for DNS requests to go over TCP, so that they are routed
through Tor. When IP is not specified, monerod uses the default list of
servers defined in [src/common/dns_utils.cpp](src/common/dns_utils.cpp).
* `TORSOCKS_ALLOW_INBOUND=1` to tell torsocks to allow monerod to bind to interfaces
to accept connections from the wallet. On some Linux systems, torsocks
allows binding to localhost by default, so setting this variable is only
necessary to allow binding to local LAN/VPN interfaces to allow wallets to
connect from remote hosts. On other systems, it may be needed for local wallets
as well.
* Do NOT pass `--detach` when running through torsocks with systemd, (see
[utils/systemd/monerod.service](utils/systemd/monerod.service) for details).
* If you use the wallet with a Tor daemon via the loopback IP (eg, 127.0.0.1:9050),
then use `--untrusted-daemon` unless it is your own hidden service.
Example command line to start monerod through Tor:
```bash
DNS_PUBLIC=tcp torsocks monerod --p2p-bind-ip 127.0.0.1 --no-igd
```
./wownerod --tx-proxy tor,127.0.0.1:9150,10 --add-peer hdps3qwnusz64r7odvynmae6myc2uyvrsc2emap6636qeuzll72eouid.onion:44568 --anonymous-inbound YOUR_NODE_ADDRESS.onion:44568,127.0.0.1:44568,25
```
### Using Tor on Tails
### Access remote Tor node from CLI wallet
TAILS ships with a very restrictive set of firewall rules. Therefore, you need
to add a rule to allow this connection too, in addition to telling torsocks to
allow inbound connections. Full example:
```bash
sudo iptables -I OUTPUT 2 -p tcp -d 127.0.0.1 -m tcp --dport 18081 -j ACCEPT
DNS_PUBLIC=tcp torsocks ./monerod --p2p-bind-ip 127.0.0.1 --no-igd --rpc-bind-ip 127.0.0.1 \
--data-dir /home/amnesia/Persistent/your/directory/to/the/blockchain
```
./wownero-wallet-cli --proxy 127.0.0.1:9150 --daemon-address wow7dhbgiljnkspkzpjyy66auegbrye2ptfv4gucgbhireg5rrjza5ad.onion:34568
```
## Debugging
Use port `9050` instead of `9150` if you installed Tor as a standalone daemon. For more information, check out [ANONYMITY_NETWORKS](https://git.wownero.com/wownero/wownero/src/branch/master/ANONYMITY_NETWORKS.md).
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.
## Donating to Wownero Project
### Obtaining stack traces and core dumps on Unix systems
Developers are volunteers doing this mostly for shits and giggles. If you would like to support our shenanigans and stimulant addictions, please consider donating to [WFS proposals](https://funding.wownero.com/proposals) or the [dev slush fund](https://dev-funding.webui.wowkira.com).
We generally use the tool `gdb` (GNU debugger) to provide stack trace functionality, and `ulimit` to provide core dumps in builds which crash or segfault.
Donations may also be sent to:
* To use `gdb` in order to obtain a stack trace for a build that has stalled:
XMR: `44SQVPGLufPasUcuUQSZiF5c9BFzjcP8ucDxzzFDgLf1VkCEFaidJ3u2AhSKMhPLKA3jc2iS8wQHFcaigM6fXmo6AnFRn5B`
Run the build.
Once it stalls, enter the following command:
```bash
gdb /path/to/monerod `pidof monerod`
```
Type `thread apply all bt` within gdb in order to obtain the stack trace
* If however the core dumps or segfaults:
Enter `ulimit -c unlimited` on the command line to enable unlimited filesizes for core dumps
Enter `echo core | sudo tee /proc/sys/kernel/core_pattern` to stop cores from being hijacked by other tools
Run the build.
When it terminates with an output along the lines of "Segmentation fault (core dumped)", there should be a core dump file in the same directory as monerod. It may be named just `core`, or `core.xxxx` with numbers appended.
You can now analyse this core dump with `gdb` as follows:
```bash
gdb /path/to/monerod /path/to/dumpfile`
```
Print the stack trace with `bt`
* If a program crashed and cores are managed by systemd, the following can also get a stack trace for that crash:
```bash
coredumpctl -1 gdb
```
#### To run monero within gdb:
Type `gdb /path/to/monerod`
Pass command-line options with `--args` followed by the relevant arguments
Type `run` to run monerod
### Analysing memory corruption
There are two tools available:
#### ASAN
Configure Monero with the -D SANITIZE=ON cmake flag, eg:
```bash
cd build/debug && cmake -D SANITIZE=ON -D CMAKE_BUILD_TYPE=Debug ../..
```
You can then run the monero tools normally. Performance will typically halve.
#### valgrind
Install valgrind and run as `valgrind /path/to/monerod`. It will be very slow.
### 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:
```bash
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.
# Known Issues
## Protocols
### Socket-based
Because of the nature of the socket-based protocols that drive monero, certain protocol weaknesses are somewhat unavoidable at this time. While these weaknesses can theoretically be fully mitigated, the effort required (the means) may not justify the ends. As such, please consider taking the following precautions if you are a monero node operator:
- Run `monerod` on a "secured" machine. If operational security is not your forte, at a very minimum, have a dedicated a computer running `monerod` and **do not** browse the web, use email clients, or use any other potentially harmful apps on your `monerod` machine. **Do not click links or load URL/MUA content on the same machine**. Doing so may potentially exploit weaknesses in commands which accept "localhost" and "127.0.0.1".
- If you plan on hosting a public "remote" node, start `monerod` with `--restricted-rpc`. This is a must.
### Blockchain-based
Certain blockchain "features" can be considered "bugs" if misused correctly. Consequently, please consider the following:
- When receiving monero, be aware that it may be locked for an arbitrary time if the sender elected to, preventing you from spending that monero until the lock time expires. You may want to hold off acting upon such a transaction until the unlock time lapses. To get a sense of that time, you can consider the remaining blocktime until unlock as seen in the `show_transfers` command.
BTC: `bc1qcw9zglp3fxyl25zswemw7jczlqryms2lsmu464`

57
cmake/FindCcache.cmake Normal file
View File

@@ -0,0 +1,57 @@
# Copyright (c) 2014-2020, 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.
# - Try to find readline include dirs and libraries
#
# Automatically finds ccache build accelerator, if it's found in PATH.
#
# Usage of this module as follows:
#
# project(monero)
# include(FindCcache) # Include AFTER the project() macro to be able to reach the CMAKE_CXX_COMPILER variable
#
# Properties modified by this module:
#
# GLOBAL PROPERTY RULE_LAUNCH_COMPILE set to ccache, when ccache found
# GLOBAL PROPERTY RULE_LAUNCH_LINK set to ccache, when ccache found
find_program(CCACHE_FOUND ccache)
if (CCACHE_FOUND)
set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp")
file(WRITE "${TEMP_CPP_FILE}" "int main() { return 0; }")
execute_process(COMMAND "${CCACHE_FOUND}" "${CMAKE_CXX_COMPILER}" "${TEMP_CPP_FILE}" RESULT_VARIABLE RET)
if (${RET} EQUAL 0)
message("found usable ccache: ${CCACHE_FOUND}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_FOUND}")
else()
message("found ccache ${CCACHE_FOUND}, but is UNUSABLE! Return code: ${RET}")
endif()
else()
message("ccache NOT found!")
endif()

View File

@@ -1,6 +1,6 @@
package=openssl
$(package)_version=1.0.2r
$(package)_download_path=https://www.openssl.org/source
$(package)_download_path=https://ftp.openssl.org/source/old/1.0.2
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=ae51d08bba8a83958e894946f15303ff894d75c2b8bbd44a852b64e3fe11d0d6
$(package)_patches=fix_arflags.patch

View File

@@ -1,6 +1,6 @@
PACKAGE=qt
$(package)_version=5.7.1
$(package)_download_path=https://download.qt.io/archive/qt/5.7/5.7.1/submodules
$(package)_download_path=http://linorg.usp.br/Qt/archive/qt/5.7/5.7.1/submodules
$(package)_suffix=opensource-src-$($(package)_version).tar.gz
$(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2019, The Monero Project
// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -39,10 +39,22 @@
namespace epee
{
struct byte_slice_data;
class byte_stream;
struct release_byte_slice
{
void operator()(byte_slice_data*) const noexcept;
//! For use with `zmq_message_init_data`, use second arg for buffer pointer.
static void call(void*, void* ptr) noexcept;
void operator()(byte_slice_data* ptr) const noexcept
{
call(nullptr, ptr);
}
};
//! Frees ref count + buffer allocated internally by `byte_buffer`.
struct release_byte_buffer
{
void operator()(std::uint8_t* buf) const noexcept;
};
/*! Inspired by slices in golang. Storage is thread-safe reference counted,
@@ -99,6 +111,9 @@ namespace epee
//! Convert `buffer` into a slice using one allocation for shared count.
explicit byte_slice(std::string&& buffer);
//! Convert `stream` into a slice with zero allocations.
explicit byte_slice(byte_stream&& stream) noexcept;
byte_slice(byte_slice&& source) noexcept;
~byte_slice() noexcept = default;
@@ -140,6 +155,23 @@ namespace epee
\throw std::out_of_range If `size() < end`.
\return Slice starting at `data() + begin` of size `end - begin`. */
byte_slice get_slice(std::size_t begin, std::size_t end) const;
//! \post `empty()` \return Ownership of ref-counted buffer.
std::unique_ptr<byte_slice_data, release_byte_slice> take_buffer() noexcept;
};
//! Alias for a buffer that has space for a `byte_slice` ref count.
using byte_buffer = std::unique_ptr<std::uint8_t, release_byte_buffer>;
/*! \return `buf` with a new size of exactly `length`. New bytes not
initialized. A `nullptr` is returned on allocation failure. */
byte_buffer byte_buffer_resize(byte_buffer buf, std::size_t length) noexcept;
/*! Increase `buf` of size `current` by `more` bytes.
\throw std::range_error if `current + more` exceeds `size_t` bounds.
\return Buffer of `current + more` bytes. A `nullptr` is returned on
allocation failure. */
byte_buffer byte_buffer_increase(byte_buffer buf, std::size_t current, std::size_t more);
} // epee

View File

@@ -0,0 +1,224 @@
// Copyright (c) 2020, 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 <cassert>
#include <cstdint>
#include <cstring>
#include "byte_slice.h"
#include "span.h"
namespace epee
{
/*! \brief A partial drop-in replacement for `std::ostream`.
Only a few base `std::ostream` functions are implemented - enough for
rapidjson output currently.
Advantages over `std::stringstream` or `rapidjson::StringBuffer`:
- The internal buffer can be taken without a copy.
- The internal buffer can be given to `byte_slice` with zero
allocations for reference count.
- The internal buffer can be given to `zmq_msg_data_init` without a
copy or extra allocation.
an additional advantage over `std::stringstream`:
- Construction is significantly faster - the global `std::locale`
does not have to be acquired (global thread synchronization), and
an extra allocation for `std::stringbuf` is not needed (which is an
addition to the buffer inside of that object). */
class byte_stream
{
byte_buffer buffer_; //! Beginning of buffer
std::uint8_t* next_write_; //! Current write position
const std::uint8_t* end_; //! End of buffer
std::size_t increase_size_; //! Minimum buffer size increase
//! \post `requested <= available()`
void overflow(const std::size_t requested);
//! Ensures that at least `requested` bytes are available.
void check(const std::size_t requested)
{
const std::size_t remaining = available();
if (remaining < requested)
overflow(requested);
}
public:
using char_type = std::uint8_t;
using Ch = char_type;
//! \return Default minimum size increase on buffer overflow
static constexpr std::size_t default_increase() noexcept { return 4096; }
//! Increase internal buffer by at least `byte_stream_increase` bytes.
byte_stream() noexcept
: byte_stream(default_increase())
{}
//! Increase internal buffer by at least `increase` bytes.
explicit byte_stream(const std::size_t increase) noexcept
: buffer_(nullptr),
next_write_(nullptr),
end_(nullptr),
increase_size_(increase)
{}
byte_stream(byte_stream&& rhs) noexcept;
~byte_stream() noexcept = default;
byte_stream& operator=(byte_stream&& rhs) noexcept;
//! \return The minimum increase size on buffer overflow
std::size_t increase_size() const noexcept { return increase_size_; }
const std::uint8_t* data() const noexcept { return buffer_.get(); }
std::uint8_t* tellp() const noexcept { return next_write_; }
std::size_t available() const noexcept { return end_ - next_write_; }
std::size_t size() const noexcept { return next_write_ - buffer_.get(); }
std::size_t capacity() const noexcept { return end_ - buffer_.get(); }
//! Compatibility with rapidjson.
void Flush() const noexcept
{}
/*! Reserve at least `more` bytes.
\post `size() + more <= available()`.
\throw std::range_error if exceeding max `size_t` value.
\throw std::bad_alloc if allocation fails. */
void reserve(const std::size_t more)
{
check(more);
}
/*! Copy `length` bytes starting at `ptr` to end of stream.
\throw std::range_error If exceeding max size_t value.
\throw std::bad_alloc If allocation fails. */
void write(const std::uint8_t* ptr, const std::size_t length)
{
check(length);
std::memcpy(tellp(), ptr, length);
next_write_ += length;
}
/*! Copy `length` bytes starting at `ptr` to end of stream.
\throw std::range_error if exceeding max `size_t` value.
\throw std::bad_alloc if allocation fails. */
void write(const char* ptr, const std::size_t length)
{
write(reinterpret_cast<const std::uint8_t*>(ptr), length);
}
/*! Copy `source` to end of stream.
\throw std::range_error if exceeding max `size_t` value.
\throw std::bad_alloc if allocation fails. */
void write(const epee::span<const std::uint8_t> source)
{
write(source.data(), source.size());
}
/*! Copy `source` to end of stream.
\throw std::range_error if exceeding max `size_t` value.
\throw std::bad_alloc if allocation fails. */
void write(const epee::span<const char> source)
{
write(source.data(), source.size());
}
/*! Copy `ch` to end of stream.
\throw std::range_error if exceeding max `size_t` value.
\throw std::bad_alloc if allocation fails. */
void put(const std::uint8_t ch)
{
check(1);
put_unsafe(ch);
}
/*! Copy `ch` to end of stream. Provides rapidjson compatability.
\throw std::range_error if exceeding max `size_t` value.
\throw std::bad_alloc if allocation fails. */
void Put(const std::uint8_t ch)
{
put(ch);
}
/*! Writes `ch` to end of stream without runtime capacity checks. Must use
`reserve` before calling this function. Primarily for use with
rapidjson, which writes characters at a time but reserves memory in
blocks. Most applications want to use `put` or `write`. */
void put_unsafe(const std::uint8_t ch) noexcept
{
assert(1 <= available());
*(tellp()) = ch;
++next_write_;
}
/*! Write `ch` to end of stream `count` times.
\throw std::range_error if exceeding max `size_t` value.
\throw std::bad_alloc if allocation fails. */
void put_n(const std::uint8_t ch, const std::size_t count)
{
check(count);
std::memset(tellp(), count, ch);
next_write_ += count;
}
/*! Copy `ch` to end of stream.
\throw std::range_error if exceeding max `size_t` value.
\throw std::bad_alloc if allocation fails. */
void push_back(const std::uint8_t ch)
{
put(ch);
}
//! \return The internal buffer. \post `size() == capacity() == 0`.
byte_buffer take_buffer() noexcept;
};
//! Compatability/optimization for rapidjson.
inline void PutReserve(byte_stream& dest, const std::size_t length)
{
dest.reserve(length);
}
//! Compatability/optimization for rapidjson.
inline void PutUnsafe(byte_stream& dest, const std::uint8_t ch)
{
dest.put_unsafe(ch);
}
//! Compability/optimization for rapidjson.
inline void PutN(byte_stream& dest, const std::uint8_t ch, const std::size_t count)
{
dest.put_n(ch, count);
}
} // epee

View File

@@ -465,7 +465,7 @@ eof:
bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, std::function<std::string(void)> prompt, const std::string& usage = "")
{
async_console_handler console_handler;
return console_handler.run(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), prompt, usage);
return console_handler.run(ptsrv, std::bind<bool>(no_srv_param_adapter<t_server, t_handler>, std::placeholders::_1, std::placeholders::_2, handlr), prompt, usage);
}
template<class t_server, class t_handler>
@@ -634,7 +634,7 @@ eof:
bool run_handling(std::function<std::string(void)> prompt, const std::string& usage_string, std::function<void(void)> exit_handler = NULL)
{
return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string, exit_handler);
return m_console_handler.run(std::bind(&console_handlers_binder::process_command_str, this, std::placeholders::_1), prompt, usage_string, exit_handler);
}
void print_prompt()

View File

@@ -277,7 +277,7 @@ namespace md5
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
memwipe ((POINTER)context, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
@@ -369,7 +369,7 @@ namespace md5
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
memwipe ((POINTER)x, sizeof (x));
}
/* Note: Replace "for loop" with standard memcpy if possible.
@@ -431,9 +431,9 @@ namespace md5
MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
/* scrub the pads and key context (if used) */
MD5_memset( (POINTER)&k_ipad, 0, sizeof(k_ipad));
MD5_memset( (POINTER)&k_opad, 0, sizeof(k_opad));
MD5_memset( (POINTER)&tk, 0, sizeof(tk));
memwipe( (POINTER)&k_ipad, sizeof(k_ipad));
memwipe( (POINTER)&k_opad, sizeof(k_opad));
memwipe( (POINTER)&tk, sizeof(tk));
/* and we're done. */
}
@@ -459,7 +459,7 @@ namespace md5
state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
}
MD5_memset( (POINTER)&hmac, 0, sizeof(hmac));
memwipe( (POINTER)&hmac, sizeof(hmac));
}

View File

@@ -0,0 +1,87 @@
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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 <boost/optional/optional.hpp>
#include "http_auth.h"
#include "net/net_ssl.h"
namespace epee
{
namespace net_utils
{
inline const char* get_hex_vals()
{
static constexpr const char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
return hexVals;
}
inline const char* get_unsave_chars()
{
//static constexpr char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&";
static constexpr const char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
return unsave_chars;
}
bool is_unsafe(unsigned char compare_char);
std::string dec_to_hex(char num, int radix);
int get_index(const char *s, char c);
std::string hex_to_dec_2bytes(const char *s);
std::string convert(char val);
std::string conver_to_url_format(const std::string& uri);
std::string convert_from_url_format(const std::string& uri);
std::string convert_to_url_format_force_all(const std::string& uri);
namespace http
{
class abstract_http_client
{
public:
abstract_http_client() {}
virtual ~abstract_http_client() {}
bool set_server(const std::string& address, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
virtual void set_server(std::string host, std::string port, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect) = 0;
virtual void set_auto_connect(bool auto_connect) = 0;
virtual bool connect(std::chrono::milliseconds timeout) = 0;
virtual bool disconnect() = 0;
virtual bool is_connected(bool *ssl = NULL) = 0;
virtual bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0;
virtual bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0;
virtual bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0;
virtual uint64_t get_bytes_sent() const = 0;
virtual uint64_t get_bytes_received() const = 0;
};
class http_client_factory
{
public:
virtual ~http_client_factory() {}
virtual std::unique_ptr<abstract_http_client> create() = 0;
};
}
}
}

View File

@@ -32,7 +32,6 @@
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/chrono.hpp>
@@ -210,15 +209,15 @@ PRAGMA_WARNING_DISABLE_VS(4355)
socket().async_receive(boost::asio::buffer(buffer_),
boost::asio::socket_base::message_peek,
strand_.wrap(
boost::bind(&connection<t_protocol_handler>::handle_receive, self,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
std::bind(&connection<t_protocol_handler>::handle_receive, self,
std::placeholders::_1,
std::placeholders::_2)));
else
async_read_some(boost::asio::buffer(buffer_),
strand_.wrap(
boost::bind(&connection<t_protocol_handler>::handle_read, self,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
std::bind(&connection<t_protocol_handler>::handle_read, self,
std::placeholders::_1,
std::placeholders::_2)));
#if !defined(_WIN32) || !defined(__i686)
// not supported before Windows7, too lazy for runtime check
// Just exclude for 32bit windows builds
@@ -688,7 +687,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
reset_timer(get_default_timeout(), false);
async_write(boost::asio::buffer(m_send_que.front().data(), size_now ) ,
strand_.wrap(
boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
std::bind(&connection<t_protocol_handler>::handle_write, self, std::placeholders::_1, std::placeholders::_2)
)
);
//_dbg3("(chunk): " << size_now);
@@ -892,7 +891,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), void(), "Unexpected queue size");
async_write(boost::asio::buffer(m_send_que.front().data(), size_now) ,
strand_.wrap(
boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2)
std::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), std::placeholders::_1, std::placeholders::_2)
)
);
//_dbg3("(normal)" << size_now);
@@ -1402,7 +1401,7 @@ POP_WARNINGS
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));
sock_.async_connect(remote_endpoint, std::bind<void>(connect_callback, std::placeholders::_1, local_shared_context));
while(local_shared_context->ec == boost::asio::error::would_block)
{
bool r = local_shared_context->cond.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(conn_timeout));

View File

@@ -33,6 +33,7 @@
#include <string>
#include <utility>
#include "memwipe.h"
#include "string_tools.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -200,6 +201,11 @@ namespace net_utils
this->~http_response_info();
new(this) http_response_info();
}
void wipe()
{
memwipe(&m_body[0], m_body.size());
}
};
}
}

View File

@@ -47,6 +47,7 @@
#include "string_tools.h"
#include "reg_exp_definer.h"
#include "abstract_http_client.h"
#include "http_base.h"
#include "http_auth.h"
#include "to_nonconst_iterator.h"
@@ -105,140 +106,11 @@ namespace net_utils
//---------------------------------------------------------------------------
static inline const char* get_hex_vals()
{
static const char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
return hexVals;
}
static inline const char* get_unsave_chars()
{
//static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&";
static const char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
return unsave_chars;
}
static inline bool is_unsafe(unsigned char compare_char)
{
if(compare_char <= 32 || compare_char >= 123)
return true;
const char* punsave = get_unsave_chars();
for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++)
if(compare_char == punsave[ichar_pos])
return true;
return false;
}
static inline
std::string dec_to_hex(char num, int radix)
{
int temp=0;
std::string csTmp;
int num_char;
num_char = (int) num;
if (num_char < 0)
num_char = 256 + num_char;
while (num_char >= radix)
{
temp = num_char % radix;
num_char = (int)floor((float)num_char / (float)radix);
csTmp = get_hex_vals()[temp];
}
csTmp += get_hex_vals()[num_char];
if(csTmp.size() < 2)
{
csTmp += '0';
}
std::reverse(csTmp.begin(), csTmp.end());
//_mbsrev((unsigned char*)csTmp.data());
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)
{
std::string csRet;
csRet += "%";
csRet += dec_to_hex(val, 16);
return csRet;
}
static inline std::string conver_to_url_format(const std::string& uri)
{
std::string result;
for(size_t i = 0; i!= uri.size(); i++)
{
if(is_unsafe(uri[i]))
result += convert(uri[i]);
else
result += uri[i];
}
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)
{
std::string result;
for(size_t i = 0; i!= uri.size(); i++)
{
result += convert(uri[i]);
}
return result;
}
namespace http
{
template<typename net_client_type>
class http_simple_client_template: public i_target_handler
class http_simple_client_template : public i_target_handler, public abstract_http_client
{
private:
enum reciev_machine_state
@@ -279,7 +151,7 @@ namespace net_utils
public:
explicit http_simple_client_template()
: i_target_handler()
: i_target_handler(), abstract_http_client()
, m_net_client()
, m_host_buff()
, m_port()
@@ -299,26 +171,19 @@ namespace net_utils
const std::string &get_host() const { return m_host_buff; };
const std::string &get_port() const { return m_port; };
bool set_server(const std::string& address, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect)
{
http::url_content parsed{};
const bool r = parse_url(address, parsed);
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), std::move(ssl_options));
return true;
}
using abstract_http_client::set_server;
void set_server(std::string host, std::string port, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect)
void set_server(std::string host, std::string port, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect) override
{
CRITICAL_REGION_LOCAL(m_lock);
disconnect();
m_host_buff = std::move(host);
m_port = std::move(port);
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
m_net_client.set_ssl(std::move(ssl_options));
}
void set_auto_connect(bool auto_connect)
void set_auto_connect(bool auto_connect) override
{
m_auto_connect = auto_connect;
}
@@ -330,25 +195,25 @@ namespace net_utils
m_net_client.set_connector(std::move(connector));
}
bool connect(std::chrono::milliseconds timeout)
bool connect(std::chrono::milliseconds timeout) override
{
CRITICAL_REGION_LOCAL(m_lock);
return m_net_client.connect(m_host_buff, m_port, timeout);
}
//---------------------------------------------------------------------------
bool disconnect()
bool disconnect() override
{
CRITICAL_REGION_LOCAL(m_lock);
return m_net_client.disconnect();
}
//---------------------------------------------------------------------------
bool is_connected(bool *ssl = NULL)
bool is_connected(bool *ssl = NULL) override
{
CRITICAL_REGION_LOCAL(m_lock);
return m_net_client.is_connected(ssl);
}
//---------------------------------------------------------------------------
virtual bool handle_target_data(std::string& piece_of_transfer)
virtual bool handle_target_data(std::string& piece_of_transfer) override
{
CRITICAL_REGION_LOCAL(m_lock);
m_response_info.m_body += piece_of_transfer;
@@ -361,15 +226,14 @@ namespace net_utils
return true;
}
//---------------------------------------------------------------------------
inline
bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
inline bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
{
CRITICAL_REGION_LOCAL(m_lock);
return invoke(uri, "GET", body, timeout, ppresponse_info, additional_params);
}
//---------------------------------------------------------------------------
inline bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
inline bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
{
CRITICAL_REGION_LOCAL(m_lock);
if(!is_connected())
@@ -442,7 +306,7 @@ namespace net_utils
return false;
}
//---------------------------------------------------------------------------
inline bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
inline bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
{
CRITICAL_REGION_LOCAL(m_lock);
return invoke(uri, "POST", body, timeout, ppresponse_info, additional_params);
@@ -456,16 +320,21 @@ namespace net_utils
return handle_reciev(timeout);
}
//---------------------------------------------------------------------------
uint64_t get_bytes_sent() const
uint64_t get_bytes_sent() const override
{
return m_net_client.get_bytes_sent();
}
//---------------------------------------------------------------------------
uint64_t get_bytes_received() const
uint64_t get_bytes_received() const override
{
return m_net_client.get_bytes_received();
}
//---------------------------------------------------------------------------
void wipe_response()
{
m_response_info.wipe();
}
//---------------------------------------------------------------------------
private:
//---------------------------------------------------------------------------
inline bool handle_reciev(std::chrono::milliseconds timeout)
@@ -1016,6 +885,14 @@ namespace net_utils
}
};
typedef http_simple_client_template<blocked_mode_client> http_simple_client;
class http_simple_client_factory : public http_client_factory
{
public:
std::unique_ptr<abstract_http_client> create() override {
return std::unique_ptr<epee::net_utils::http::abstract_http_client>(new epee::net_utils::http::http_simple_client());
}
};
}
}
}

View File

@@ -31,7 +31,7 @@
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/bind/bind.hpp>
#include "net/abstract_tcp_server2.h"
#include "http_protocol_handler.h"

View File

@@ -38,7 +38,7 @@ namespace epee
namespace net_utils
{
template<class t_request, class t_response, class t_transport>
bool invoke_http_json(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "GET")
bool invoke_http_json(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "POST")
{
std::string req_param;
if(!serialization::store_t_to_json(out_struct, req_param))
@@ -72,7 +72,7 @@ namespace epee
template<class t_request, class t_response, class t_transport>
bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "GET")
bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "POST")
{
std::string req_param;
if(!serialization::store_t_to_binary(out_struct, req_param))
@@ -101,7 +101,7 @@ namespace epee
}
template<class t_request, class t_response, class t_transport>
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, epee::json_rpc::error &error_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, epee::json_rpc::error &error_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
{
epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
req_t.jsonrpc = "2.0";
@@ -125,14 +125,14 @@ namespace epee
}
template<class t_request, class t_response, class t_transport>
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
{
epee::json_rpc::error error_struct;
return invoke_http_json_rpc(uri, method_name, out_struct, result_struct, error_struct, transport, timeout, http_method, req_id);
}
template<class t_command, class t_transport>
bool invoke_http_json_rpc(const boost::string_ref uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
bool invoke_http_json_rpc(const boost::string_ref uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
{
return invoke_http_json_rpc(uri, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id);
}

View File

@@ -28,6 +28,7 @@
#include "portable_storage_template_helper.h"
#include <boost/utility/value_init.hpp>
#include <functional>
#include "span.h"
#include "net/levin_base.h"
@@ -294,20 +295,20 @@ namespace epee
#define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \
if(!is_notify && command_id == command) \
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), context);}
#define HANDLE_INVOKE_T2(COMMAND, func) \
if(!is_notify && COMMAND::ID == command) \
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), context);}
#define HANDLE_NOTIFY2(command_id, func, type_name_in) \
if(is_notify && command_id == command) \
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), context);}
#define HANDLE_NOTIFY_T2(NOTIFY, func) \
if(is_notify && NOTIFY::ID == command) \
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, std::bind(func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), context);}
#define CHAIN_INVOKE_MAP2(func) \

View File

@@ -196,7 +196,7 @@ namespace misc_utils
uint32_t dst = 0;
for (int i = 0; i < 4; ++i)
{
const unsigned char tmp = isx[(int)*++it];
const unsigned char tmp = isx[(unsigned char)*++it];
CHECK_AND_ASSERT_THROW_MES(tmp != 0xff, "Bad Unicode encoding");
dst = dst << 4 | tmp;
}

View File

@@ -150,7 +150,7 @@ namespace epee
};
#define CRITICAL_REGION_LOCAL(x) {boost::this_thread::sleep_for(boost::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep()));} epee::critical_region_t<decltype(x)> critical_region_var(x)
#define CRITICAL_REGION_LOCAL(x) {} epee::critical_region_t<decltype(x)> critical_region_var(x)
#define CRITICAL_REGION_BEGIN(x) { boost::this_thread::sleep_for(boost::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep())); epee::critical_region_t<decltype(x)> critical_region_var(x)
#define CRITICAL_REGION_LOCAL1(x) {boost::this_thread::sleep_for(boost::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep()));} epee::critical_region_t<decltype(x)> critical_region_var1(x)
#define CRITICAL_REGION_BEGIN1(x) { boost::this_thread::sleep_for(boost::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep())); epee::critical_region_t<decltype(x)> critical_region_var1(x)

View File

@@ -26,8 +26,9 @@
# 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.
add_library(epee STATIC byte_slice.cpp hex.cpp http_auth.cpp mlog.cpp net_helper.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp
levin_base.cpp memwipe.c connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp
add_library(epee STATIC byte_slice.cpp byte_stream.cpp hex.cpp abstract_http_client.cpp http_auth.cpp mlog.cpp net_helper.cpp net_utils_base.cpp string_tools.cpp
wipeable_string.cpp levin_base.cpp memwipe.c connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp
int-util.cpp)
if (USE_READLINE AND (GNU_READLINE_FOUND OR (DEPENDS AND NOT MINGW)))

View File

@@ -0,0 +1,142 @@
#include "net/abstract_http_client.h"
#include "net/http_base.h"
#include "net/net_parse_helpers.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
namespace epee
{
namespace net_utils
{
//----------------------------------------------------------------------------------------------------
bool is_unsafe(unsigned char compare_char)
{
if(compare_char <= 32 || compare_char >= 123)
return true;
const char* punsave = get_unsave_chars();
for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++)
if(compare_char == punsave[ichar_pos])
return true;
return false;
}
//----------------------------------------------------------------------------------------------------
std::string dec_to_hex(char num, int radix)
{
int temp=0;
std::string csTmp;
int num_char;
num_char = (int) num;
if (num_char < 0)
num_char = 256 + num_char;
while (num_char >= radix)
{
temp = num_char % radix;
num_char = (int)floor((float)num_char / (float)radix);
csTmp = get_hex_vals()[temp];
}
csTmp += get_hex_vals()[num_char];
if(csTmp.size() < 2)
{
csTmp += '0';
}
std::reverse(csTmp.begin(), csTmp.end());
//_mbsrev((unsigned char*)csTmp.data());
return csTmp;
}
//----------------------------------------------------------------------------------------------------
int get_index(const char *s, char c)
{
const char *ptr = (const char*)memchr(s, c, 16);
return ptr ? ptr-s : -1;
}
//----------------------------------------------------------------------------------------------------
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);
}
//----------------------------------------------------------------------------------------------------
std::string convert(char val)
{
std::string csRet;
csRet += "%";
csRet += dec_to_hex(val, 16);
return csRet;
}
//----------------------------------------------------------------------------------------------------
std::string conver_to_url_format(const std::string& uri)
{
std::string result;
for(size_t i = 0; i!= uri.size(); i++)
{
if(is_unsafe(uri[i]))
result += convert(uri[i]);
else
result += uri[i];
}
return result;
}
//----------------------------------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------------------------------
std::string convert_to_url_format_force_all(const std::string& uri)
{
std::string result;
for(size_t i = 0; i!= uri.size(); i++)
{
result += convert(uri[i]);
}
return result;
}
namespace http
{
//----------------------------------------------------------------------------------------------------
bool epee::net_utils::http::abstract_http_client::set_server(const std::string& address, boost::optional<login> user, ssl_options_t ssl_options)
{
http::url_content parsed{};
const bool r = parse_url(address, parsed);
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), std::move(ssl_options));
return true;
}
}
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2019, The Monero Project
// Copyright (c) 2019-2020, The Monero Project
//
// All rights reserved.
//
@@ -34,6 +34,7 @@
#include <utility>
#include "byte_slice.h"
#include "byte_stream.h"
namespace epee
{
@@ -49,12 +50,16 @@ namespace epee
std::atomic<std::size_t> ref_count;
};
void release_byte_slice::operator()(byte_slice_data* ptr) const noexcept
void release_byte_slice::call(void*, void* ptr) noexcept
{
if (ptr && --(ptr->ref_count) == 0)
if (ptr)
{
ptr->~byte_slice_data();
free(ptr);
byte_slice_data* self = static_cast<byte_slice_data*>(ptr);
if (--(self->ref_count) == 0)
{
self->~byte_slice_data();
free(self);
}
}
}
@@ -113,6 +118,12 @@ namespace epee
}
} // anonymous
void release_byte_buffer::operator()(std::uint8_t* buf) const noexcept
{
if (buf)
std::free(buf - sizeof(raw_byte_slice));
}
byte_slice::byte_slice(byte_slice_data* storage, span<const std::uint8_t> portion) noexcept
: storage_(storage), portion_(portion)
{
@@ -122,10 +133,13 @@ namespace epee
template<typename T>
byte_slice::byte_slice(const adapt_buffer, T&& buffer)
: storage_(nullptr), portion_(to_byte_span(to_span(buffer)))
: storage_(nullptr), portion_(nullptr)
{
if (!buffer.empty())
{
storage_ = allocate_slice<adapted_byte_slice<T>>(0, std::move(buffer));
portion_ = to_byte_span(to_span(static_cast<adapted_byte_slice<T> *>(storage_.get())->buffer));
}
}
byte_slice::byte_slice(std::initializer_list<span<const std::uint8_t>> sources)
@@ -159,6 +173,19 @@ namespace epee
: byte_slice(adapt_buffer{}, std::move(buffer))
{}
byte_slice::byte_slice(byte_stream&& stream) noexcept
: storage_(nullptr), portion_(stream.data(), stream.size())
{
if (stream.size())
{
std::uint8_t* const data = stream.take_buffer().release() - sizeof(raw_byte_slice);
new (data) raw_byte_slice{};
storage_.reset(reinterpret_cast<raw_byte_slice*>(data));
}
else
portion_ = nullptr;
}
byte_slice::byte_slice(byte_slice&& source) noexcept
: storage_(std::move(source.storage_)), portion_(source.portion_)
{
@@ -186,14 +213,17 @@ namespace epee
byte_slice byte_slice::take_slice(const std::size_t max_bytes) noexcept
{
byte_slice out{};
std::uint8_t const* const ptr = data();
out.portion_ = {ptr, portion_.remove_prefix(max_bytes)};
if (portion_.empty())
out.storage_ = std::move(storage_); // no atomic inc/dec
else
out = {storage_.get(), out.portion_};
if (max_bytes)
{
std::uint8_t const* const ptr = data();
out.portion_ = {ptr, portion_.remove_prefix(max_bytes)};
if (portion_.empty())
out.storage_ = std::move(storage_); // no atomic inc/dec
else
out = {storage_.get(), out.portion_};
}
return out;
}
@@ -206,4 +236,36 @@ namespace epee
return {};
return {storage_.get(), {portion_.begin() + begin, end - begin}};
}
std::unique_ptr<byte_slice_data, release_byte_slice> byte_slice::take_buffer() noexcept
{
std::unique_ptr<byte_slice_data, release_byte_slice> out{std::move(storage_)};
portion_ = nullptr;
return out;
}
byte_buffer byte_buffer_resize(byte_buffer buf, const std::size_t length) noexcept
{
if (std::numeric_limits<std::size_t>::max() - sizeof(raw_byte_slice) < length)
return nullptr;
std::uint8_t* data = buf.get();
if (data != nullptr)
data -= sizeof(raw_byte_slice);
data = static_cast<std::uint8_t*>(std::realloc(data, sizeof(raw_byte_slice) + length));
if (data == nullptr)
return nullptr;
buf.release();
buf.reset(data + sizeof(raw_byte_slice));
return buf;
}
byte_buffer byte_buffer_increase(byte_buffer buf, const std::size_t current, const std::size_t more)
{
if (std::numeric_limits<std::size_t>::max() - current < more)
throw std::range_error{"byte_buffer_increase size_t overflow"};
return byte_buffer_resize(std::move(buf), current + more);
}
} // epee

View File

@@ -0,0 +1,93 @@
// Copyright (c) 2020, 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 "byte_stream.h"
#include <algorithm>
#include <limits>
#include <utility>
#include <iostream>
namespace epee
{
void byte_stream::overflow(const std::size_t requested)
{
// Recalculating `need` bytes removes at least one instruction from every
// inlined `put` call in header
assert(available() < requested);
const std::size_t need = requested - available();
const std::size_t len = size();
const std::size_t cap = capacity();
const std::size_t increase = std::max(need, increase_size());
next_write_ = nullptr;
end_ = nullptr;
buffer_ = byte_buffer_increase(std::move(buffer_), cap, increase);
if (!buffer_)
throw std::bad_alloc{};
next_write_ = buffer_.get() + len;
end_ = buffer_.get() + cap + increase;
}
byte_stream::byte_stream(byte_stream&& rhs) noexcept
: buffer_(std::move(rhs.buffer_)),
next_write_(rhs.next_write_),
end_(rhs.end_),
increase_size_(rhs.increase_size_)
{
rhs.next_write_ = nullptr;
rhs.end_ = nullptr;
}
byte_stream& byte_stream::operator=(byte_stream&& rhs) noexcept
{
if (this != std::addressof(rhs))
{
buffer_ = std::move(rhs.buffer_);
next_write_ = rhs.next_write_;
end_ = rhs.end_;
increase_size_ = rhs.increase_size_;
rhs.next_write_ = nullptr;
rhs.end_ = nullptr;
}
return *this;
}
byte_buffer byte_stream::take_buffer() noexcept
{
byte_buffer out{std::move(buffer_)};
next_write_ = nullptr;
end_ = nullptr;
return out;
}
}

View File

@@ -141,7 +141,7 @@ namespace epee
result.reserve(count / 2);
// the data to work with (std::string is always null-terminated)
auto data = src.data();
auto data = src.begin();
// convert a single hex character to an unsigned integer
auto char_to_int = [](const char *input) {
@@ -167,9 +167,9 @@ namespace epee
};
// keep going until we reach the end
while (data[0] != '\0') {
while (data != src.end()) {
// skip unwanted characters
if (!include(data[0])) {
if (!include(*data)) {
++data;
continue;
}

View File

@@ -100,7 +100,7 @@ static const char *get_default_categories(int level)
switch (level)
{
case 0:
categories = "*:WARNING,net:FATAL,net.http:FATAL,net.ssl:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,serialization:FATAL,daemon.rpc.payment:ERROR,stacktrace:INFO,logging:INFO,msgwriter:INFO";
categories = "*:WARNING,net:FATAL,net.http:FATAL,net.ssl:FATAL,net.p2p:FATAL,net.cn:FATAL,daemon.rpc:FATAL,global:INFO,verify:FATAL,serialization:FATAL,daemon.rpc.payment:ERROR,stacktrace:INFO,logging:INFO,msgwriter:INFO";
break;
case 1:
categories = "*:INFO,global:INFO,stacktrace:INFO,logging:INFO,msgwriter:INFO,perf.*:DEBUG";

View File

@@ -511,7 +511,7 @@ bool ssl_options_t::handshake(
// autodetect will reconnect without SSL - warn and keep connection encrypted
if (support != ssl_support_t::e_ssl_support_autodetect)
{
MERROR("SSL certificate is not in the allowed list, connection droppped");
MERROR("SSL certificate is not in the allowed list, connection dropped");
return false;
}
MWARNING("SSL peer has not been verified");

View File

@@ -1,5 +1,5 @@
---
name: "monero-android-0.15"
name: "wownero-android-0.8"
enable_cache: true
suites:
- "bionic"
@@ -32,8 +32,8 @@ packages:
- "python3-zmq"
- "unzip"
remotes:
- "url": "https://github.com/monero-project/monero.git"
"dir": "monero"
- "url": "https://github.com/wownero/wownero.git"
"dir": "wownero"
files: []
script: |
@@ -75,7 +75,7 @@ script: |
then
ABI=$i"eabi"
fi
NDKDIR="${BUILD_DIR}/monero/contrib/depends/$i/native/bin"
NDKDIR="${BUILD_DIR}/wownero/contrib/depends/$i/native/bin"
for prog in ${FAKETIME_HOST_PROGS}; do
WRAPPER=${WRAP_DIR}/${ABI}-${prog}
echo '#!/usr/bin/env bash' > ${WRAPPER}
@@ -97,7 +97,7 @@ script: |
export SOURCE_DATE_EPOCH=`date -d 2000-01-01T12:00:00 +%s`
git config --global core.abbrev 9
cd monero
cd wownero
# Set the version string that gets added to the tar archive name
version="`git describe`"
if [[ $version == *"-"*"-"* ]]; then
@@ -127,7 +127,7 @@ script: |
chmod 755 bin/*
cp ../LICENSE bin
chmod 644 bin/LICENSE
DISTNAME=monero-${i}-${version}
DISTNAME=wownero-${i}-${version}
mv bin ${DISTNAME}
find ${DISTNAME}/ | sort | tar --no-recursion --owner=0 --group=0 -c -T - | bzip2 -9 > ${OUTDIR}/${DISTNAME}.tar.bz2
cd ..

View File

@@ -5,8 +5,8 @@ import os
import subprocess
import sys
gsigs = 'https://github.com/monero-project/gitian.sigs.git'
gbrepo = 'https://github.com/devrandom/gitian-builder.git'
gsigs = 'https://github.com/wownero/gitian.sigs.git'
gbrepo = 'https://github.com/wownero/gitian-builder.git'
platforms = {'l': ['Linux', 'linux', 'tar.bz2'],
'a': ['Android', 'android', 'tar.bz2'],
@@ -31,8 +31,8 @@ def setup():
subprocess.check_call(['git', 'checkout', 'c0f77ca018cb5332bfd595e0aff0468f77542c23'])
os.makedirs('inputs', exist_ok=True)
os.chdir('inputs')
if not os.path.isdir('monero'):
subprocess.check_call(['git', 'clone', args.url, 'monero'])
if not os.path.isdir('wownero'):
subprocess.check_call(['git', 'clone', args.url, 'wownero'])
os.chdir('..')
make_image_prog = ['bin/make-base-vm', '--suite', 'bionic', '--arch', 'amd64']
if args.docker:
@@ -67,10 +67,10 @@ def rebuild():
suffix = platforms[i][2]
print('\nCompiling ' + args.version + ' ' + os_name)
infile = 'inputs/monero/contrib/gitian/gitian-' + tag_name + '.yml'
subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'monero='+args.commit, '--url', 'monero='+args.url, infile])
infile = 'inputs/wownero/contrib/gitian/gitian-' + tag_name + '.yml'
subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'wownero='+args.commit, '--url', 'wownero='+args.url, infile])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-'+tag_name, '--destination', '../sigs/', infile])
subprocess.check_call('mv build/out/monero-*.' + suffix + ' ../out/'+args.version, shell=True)
subprocess.check_call('mv build/out/wownero-*.' + suffix + ' ../out/'+args.version, shell=True)
print('Moving var/install.log to var/install-' + tag_name + '.log')
subprocess.check_call('mv var/install.log var/install-' + tag_name + '.log', shell=True)
print('Moving var/build.log to var/build-' + tag_name + '.log')
@@ -98,7 +98,7 @@ def build():
subprocess.check_call(['wget', '-N', '-P', 'inputs', 'https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch'])
subprocess.check_output(["echo 'a8c4e9cafba922f89de0df1f2152e7be286aba73f78505169bc351a7938dd911 inputs/osslsigncode-Backports-to-1.7.1.patch' | sha256sum -c"], shell=True)
subprocess.check_output(["echo 'f9a8cdb38b9c309326764ebc937cba1523a3a751a7ab05df3ecc99d18ae466c9 inputs/osslsigncode-1.7.1.tar.gz' | sha256sum -c"], shell=True)
subprocess.check_call(['make', '-C', 'inputs/monero/contrib/depends', 'download', 'SOURCES_PATH=' + os.getcwd() + '/cache/common'])
subprocess.check_call(['make', '-C', 'inputs/wownero/contrib/depends', 'download', 'SOURCES_PATH=' + os.getcwd() + '/cache/common'])
rebuild()
@@ -109,7 +109,7 @@ def verify():
for i, v in platforms:
print('\nVerifying v'+args.version+' '+v[0]+'\n')
subprocess.check_call(['bin/gverify', '-v', '-d', '../sigs/', '-r', args.version+'-'+v[1], 'inputs/monero/contrib/gitian/gitian-'+v[1]+'.yml'])
subprocess.check_call(['bin/gverify', '-v', '-d', '../sigs/', '-r', args.version+'-'+v[1], 'inputs/wownero/contrib/gitian/gitian-'+v[1]+'.yml'])
os.chdir(workdir)
def main():
@@ -118,7 +118,7 @@ def main():
parser = argparse.ArgumentParser(description='Script for running full Gitian builds.', usage='%(prog)s [options] signer version')
parser.add_argument('-c', '--commit', action='store_true', dest='commit', help='Indicate that the version argument is for a commit or branch')
parser.add_argument('-p', '--pull', action='store_true', dest='pull', help='Indicate that the version argument is the number of a github repository pull request')
parser.add_argument('-u', '--url', dest='url', default='https://github.com/monero-project/monero', help='Specify the URL of the repository. Default is %(default)s')
parser.add_argument('-u', '--url', dest='url', default='https://github.com/wownero/wownero', help='Specify the URL of the repository. Default is %(default)s')
parser.add_argument('-v', '--verify', action='store_true', dest='verify', help='Verify the Gitian build')
parser.add_argument('-b', '--build', action='store_true', dest='build', help='Do a Gitian build')
parser.add_argument('-B', '--buildsign', action='store_true', dest='buildsign', help='Build both signed and unsigned binaries')
@@ -190,8 +190,8 @@ def main():
if args.setup:
setup()
os.makedirs('builder/inputs/monero', exist_ok=True)
os.chdir('builder/inputs/monero')
os.makedirs('builder/inputs/wownero', exist_ok=True)
os.chdir('builder/inputs/wownero')
if args.pull:
subprocess.check_call(['git', 'fetch', args.url, 'refs/pull/'+args.version+'/merge'])
args.commit = subprocess.check_output(['git', 'show', '-s', '--format=%H', 'FETCH_HEAD'], universal_newlines=True).strip()

View File

@@ -1,5 +1,5 @@
---
name: "monero-freebsd-0.15"
name: "wownero-freebsd-0.8"
enable_cache: true
suites:
- "bionic"
@@ -32,8 +32,8 @@ packages:
- "libprotobuf-dev"
- "python3-zmq"
remotes:
- "url": "https://github.com/monero-project/monero.git"
"dir": "monero"
- "url": "https://github.com/wownero/wownero.git"
"dir": "wownero"
files: []
script: |
@@ -92,7 +92,7 @@ script: |
export SOURCE_DATE_EPOCH=`date -d 2000-01-01T12:00:00 +%s`
git config --global core.abbrev 9
cd monero
cd wownero
# Set the version string that gets added to the tar archive name
version="`git describe`"
if [[ $version == *"-"*"-"* ]]; then
@@ -124,7 +124,7 @@ script: |
chmod 755 bin/*
cp ../LICENSE bin
chmod 644 bin/LICENSE
DISTNAME=monero-${i}-${version}
DISTNAME=wownero-${i}-${version}
mv bin ${DISTNAME}
find ${DISTNAME}/ | sort | tar --no-recursion --owner=0 --group=0 -c -T - | bzip2 -9 > ${OUTDIR}/${DISTNAME}.tar.bz2
cd ..

View File

@@ -1,5 +1,5 @@
---
name: "monero-linux-0.15"
name: "wownero-linux-0.8"
enable_cache: true
suites:
- "bionic"
@@ -43,8 +43,8 @@ packages:
- "libprotobuf-dev"
- "python3-zmq"
remotes:
- "url": "https://github.com/monero-project/monero.git"
"dir": "monero"
- "url": "https://github.com/wownero/wownero.git"
"dir": "wownero"
files: []
script: |
@@ -115,7 +115,7 @@ script: |
export SOURCE_DATE_EPOCH=`date -d 2000-01-01T12:00:00 +%s`
git config --global core.abbrev 9
cd monero
cd wownero
# Set the version string that gets added to the tar archive name
version="`git describe`"
if [[ $version == *"-"*"-"* ]]; then
@@ -164,7 +164,7 @@ script: |
chmod 755 bin/*
cp ../LICENSE bin
chmod 644 bin/LICENSE
DISTNAME=monero-${i}-${version}
DISTNAME=wownero-${i}-${version}
mv bin ${DISTNAME}
find ${DISTNAME}/ | sort | tar --no-recursion --owner=0 --group=0 -c -T - | bzip2 -9 > ${OUTDIR}/${DISTNAME}.tar.bz2
cd ..

View File

@@ -1,5 +1,5 @@
---
name: "monero-osx-0.15"
name: "wownero-osx-0.8"
enable_cache: true
suites:
- "bionic"
@@ -24,8 +24,8 @@ packages:
- "python-dev"
- "python-setuptools"
remotes:
- "url": "https://github.com/monero-project/monero.git"
"dir": "monero"
- "url": "https://github.com/wownero/wownero.git"
"dir": "wownero"
files:
- "MacOSX10.11.sdk.tar.gz"
script: |
@@ -77,7 +77,7 @@ script: |
export PATH=${WRAP_DIR}:${PATH}
git config --global core.abbrev 9
cd monero
cd wownero
# Set the version string that gets added to the tar archive name
version="`git describe`"
if [[ $version == *"-"*"-"* ]]; then
@@ -113,7 +113,7 @@ script: |
chmod 755 bin/*
cp ../LICENSE bin
chmod 644 bin/LICENSE
DISTNAME=monero-${i}-${version}
DISTNAME=wownero-${i}-${version}
mv bin ${DISTNAME}
find ${DISTNAME}/ | sort | tar --no-recursion --owner=0 --group=0 -c -T - | bzip2 -9 > ${OUTDIR}/${DISTNAME}.tar.bz2
cd ..

View File

@@ -1,5 +1,5 @@
---
name: "monero-win-0.15"
name: "wownero-win-0.8"
enable_cache: true
suites:
- "bionic"
@@ -36,8 +36,8 @@ alternatives:
package: "x86_64-w64-mingw32-gcc"
path: "/usr/bin/x86_64-w64-mingw32-gcc-posix"
remotes:
- "url": "https://github.com/monero-project/monero.git"
"dir": "monero"
- "url": "https://github.com/wownero/wownero.git"
"dir": "wownero"
files: []
script: |
WRAP_DIR=$HOME/wrapped
@@ -91,7 +91,7 @@ script: |
export SOURCE_DATE_EPOCH=`date -d 2000-01-01T12:00:00 +%s`
git config --global core.abbrev 9
cd monero
cd wownero
# Set the version string that gets added to the tar archive name
version="`git describe`"
if [[ $version == *"-"*"-"* ]]; then
@@ -128,7 +128,7 @@ script: |
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake
make ${MAKEOPTS}
cp ../LICENSE bin
DISTNAME=monero-${i}-${version}
DISTNAME=wownero-${i}-${version}
mv bin ${DISTNAME}
find ${DISTNAME}/ | sort | zip -X@ ${OUTDIR}/${DISTNAME}.zip
cd .. && rm -rf build

View File

@@ -1,8 +0,0 @@
#!/bin/sh
if [ ! -d "$SNAP_USER_DATA/etc" ]; then
mkdir $SNAP_USER_DATA/etc/
cp -R $SNAP/etc/monerod.conf $SNAP_USER_DATA/etc/monerod.conf
fi
exec "$SNAP/bin/monerod" "$@"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,31 +1,29 @@
name: monero
version: 0.11.1.0-1
summary: "Monero: the secure, private, untraceable cryptocurrency https://getmonero.org"
name: wownero
version: 0.5.0.0
summary: "Wownero: the secure, private, untraceable cryptocurrency http://wownero.org"
description: |
Monero is a private, secure, untraceable, decentralised digital currency.
You are your bank, you control your funds, and nobody can trace your transfers
unless you allow them to do so.
Wownero: a fairly launched privacy-centric meme coin with no premine and a finite supply.
grade: devel
confinement: strict
apps:
monerod:
wownerod:
daemon: forking
command: |
monerod-wrapper --detach --data-dir ${SNAP_COMMON} --config-file ${SNAP_USER_DATA}/etc/monerod.conf
wownerod-wrapper --detach --data-dir ${SNAP_COMMON} --config-file ${SNAP_USER_DATA}/etc/wownerod.conf
plugs:
- network
- network-bind
monero-wallet-rpc:
wownero-wallet-rpc:
command: |
monero-wallet-rpc --log-file ${SNAP_USER_DATA}
wownero-wallet-rpc --log-file ${SNAP_USER_DATA}
plugs:
- home
- network
- network-bind
monero-wallet-cli:
wownero-wallet-cli:
command: |
monero-wallet-cli --log-file ${SNAP_USER_DATA}
wownero-wallet-cli --log-file ${SNAP_USER_DATA}
plugs:
- home
- network
@@ -71,8 +69,8 @@ parts:
plugin: dump
source: .
organize:
contrib/snap/monerod.conf: etc/monerod.conf
contrib/snap/monerod-wrapper: bin/monerod-wrapper
contrib/snap/wownerod.conf: etc/wownerod.conf
contrib/snap/wownerod-wrapper: bin/wownerod-wrapper
prime:
- etc
- bin

8
contrib/snap/wownerod-wrapper Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
if [ ! -d "$SNAP_USER_DATA/etc" ]; then
mkdir $SNAP_USER_DATA/etc/
cp -R $SNAP/etc/wownerod.conf $SNAP_USER_DATA/etc/wownerod.conf
fi
exec "$SNAP/bin/wownerod" "$@"

View File

@@ -4,7 +4,7 @@
# See 'monerod --help' for all available options.
# Overridden by snap:
# data-dir=/var/lib/monero
# log-file=/var/log/monero/monero.log
# data-dir=/var/lib/wownero
# log-file=/var/log/wownero/wownero.log
log-level=0

View File

@@ -34,22 +34,42 @@
# We always compile if we are building statically to reduce static dependency issues...
# ...except for FreeBSD, because FreeBSD is a special case that doesn't play well with
# others.
find_package(Miniupnpc REQUIRED)
message(STATUS "Using in-tree miniupnpc")
add_subdirectory(miniupnp/miniupnpc)
set_property(TARGET libminiupnpc-static PROPERTY FOLDER "external")
if(MSVC)
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267")
elseif(NOT MSVC)
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value")
endif()
if(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -D_NETBSD_SOURCE")
if(NOT IOS)
find_package(Miniupnpc QUIET)
endif()
set(UPNP_LIBRARIES "libminiupnpc-static" PARENT_SCOPE)
# If we have the correct shared version and we're not building static, use it
if(STATIC OR IOS)
set(USE_SHARED_MINIUPNPC false)
elseif(MINIUPNP_FOUND AND MINIUPNPC_VERSION_1_7_OR_HIGHER)
set(USE_SHARED_MINIUPNPC true)
endif()
if(USE_SHARED_MINIUPNPC)
message(STATUS "Using shared miniupnpc found at ${MINIUPNP_INCLUDE_DIR}")
set(UPNP_STATIC false PARENT_SCOPE)
set(UPNP_INCLUDE ${MINIUPNP_INCLUDE_DIR} PARENT_SCOPE)
set(UPNP_LIBRARIES ${MINIUPNP_LIBRARY} PARENT_SCOPE)
else()
if(STATIC)
message(STATUS "Using miniupnpc from local source tree for static build")
else()
message(STATUS "Using miniupnpc from local source tree (/external/miniupnp/miniupnpc)")
endif()
add_subdirectory(miniupnp/miniupnpc)
set_property(TARGET libminiupnpc-static PROPERTY FOLDER "external")
if(MSVC)
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267")
elseif(NOT MSVC)
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value")
endif()
set(UPNP_STATIC true PARENT_SCOPE)
set(UPNP_LIBRARIES "libminiupnpc-static" PARENT_SCOPE)
endif()
find_package(Unbound)
@@ -80,4 +100,4 @@ endif()
add_subdirectory(db_drivers)
add_subdirectory(easylogging++)
add_subdirectory(randomx EXCLUDE_FROM_ALL)
add_subdirectory(RandomWOW EXCLUDE_FROM_ALL)

1
external/RandomWOW vendored Submodule

Submodule external/RandomWOW added at 759fc58502

View File

@@ -2475,6 +2475,100 @@ void DefaultLogDispatchCallback::handle(const LogDispatchData* data) {
}
}
template<typename Transform>
static inline std::string utf8canonical(const std::string &s, Transform t = [](wint_t c)->wint_t { return c; })
{
std::string sc = "";
size_t avail = s.size();
const char *ptr = s.data();
wint_t cp = 0;
int bytes = 1;
char wbuf[8], *wptr;
while (avail--)
{
if ((*ptr & 0x80) == 0)
{
cp = *ptr++;
bytes = 1;
}
else if ((*ptr & 0xe0) == 0xc0)
{
if (avail < 1)
throw std::runtime_error("Invalid UTF-8");
cp = (*ptr++ & 0x1f) << 6;
cp |= *ptr++ & 0x3f;
--avail;
bytes = 2;
}
else if ((*ptr & 0xf0) == 0xe0)
{
if (avail < 2)
throw std::runtime_error("Invalid UTF-8");
cp = (*ptr++ & 0xf) << 12;
cp |= (*ptr++ & 0x3f) << 6;
cp |= *ptr++ & 0x3f;
avail -= 2;
bytes = 3;
}
else if ((*ptr & 0xf8) == 0xf0)
{
if (avail < 3)
throw std::runtime_error("Invalid UTF-8");
cp = (*ptr++ & 0x7) << 18;
cp |= (*ptr++ & 0x3f) << 12;
cp |= (*ptr++ & 0x3f) << 6;
cp |= *ptr++ & 0x3f;
avail -= 3;
bytes = 4;
}
else
throw std::runtime_error("Invalid UTF-8");
cp = t(cp);
if (cp <= 0x7f)
bytes = 1;
else if (cp <= 0x7ff)
bytes = 2;
else if (cp <= 0xffff)
bytes = 3;
else if (cp <= 0x10ffff)
bytes = 4;
else
throw std::runtime_error("Invalid code point UTF-8 transformation");
wptr = wbuf;
switch (bytes)
{
case 1: *wptr++ = cp; break;
case 2: *wptr++ = 0xc0 | (cp >> 6); *wptr++ = 0x80 | (cp & 0x3f); break;
case 3: *wptr++ = 0xe0 | (cp >> 12); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
case 4: *wptr++ = 0xf0 | (cp >> 18); *wptr++ = 0x80 | ((cp >> 12) & 0x3f); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
default: throw std::runtime_error("Invalid UTF-8");
}
*wptr = 0;
sc.append(wbuf, bytes);
cp = 0;
bytes = 1;
}
return sc;
}
void sanitize(std::string &s)
{
s = utf8canonical(s, [](wint_t c)->wint_t {
if (c == 9 || c == 10 || c == 13)
return c;
if (c < 0x20)
return '?';
if (c == 0x7f)
return '?';
if (c >= 0x80 && c <= 0x9f)
return '?';
return c;
});
}
void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLinePrefix, base::type::string_t&& rawLinePayload, base::type::string_t&& logLine) {
if (m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog) {
if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) {
@@ -2506,6 +2600,8 @@ void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLinePrefix,
m_data->logMessage()->logger()->logBuilder()->setColor(el::base::utils::colorFromLevel(level), false);
ELPP_COUT << rawLinePrefix;
m_data->logMessage()->logger()->logBuilder()->setColor(color == el::Color::Default ? el::base::utils::colorFromLevel(level): color, color != el::Color::Default);
try { sanitize(rawLinePayload); }
catch (const std::exception &e) { rawLinePayload = "<Invalid UTF-8 in log>"; }
ELPP_COUT << rawLinePayload;
m_data->logMessage()->logger()->logBuilder()->setColor(el::Color::Default, false);
ELPP_COUT << std::flush;

1
external/randomx vendored

Submodule external/randomx deleted from 7567cef4c6

View File

@@ -126,15 +126,15 @@ endif()
add_subdirectory(cryptonote_protocol)
if(NOT IOS)
add_subdirectory(simplewallet)
add_subdirectory(gen_multisig)
add_subdirectory(gen_ssl_cert)
add_subdirectory(daemonizer)
add_subdirectory(daemon)
add_subdirectory(blockchain_utilities)
endif()
if(BUILD_DEBUG_UTILITIES)
add_subdirectory(debug_utilities)
add_subdirectory(blockchain_utilities)
add_subdirectory(gen_multisig)
add_subdirectory(gen_ssl_cert)
endif()
if(PER_BLOCK_CHECKPOINT)

View File

@@ -53,9 +53,7 @@ bool matches_category(relay_method method, relay_category category) noexcept
case relay_category::all:
return true;
case relay_category::relayable:
if (method == relay_method::none)
return false;
return true;
return method != relay_method::none;
case relay_category::broadcasted:
case relay_category::legacy:
break;
@@ -65,6 +63,7 @@ bool matches_category(relay_method method, relay_category category) noexcept
{
default:
case relay_method::local:
case relay_method::stem:
return false;
case relay_method::block:
case relay_method::fluff:
@@ -80,6 +79,7 @@ void txpool_tx_meta_t::set_relay_method(relay_method method) noexcept
kept_by_block = 0;
do_not_relay = 0;
is_local = 0;
dandelionpp_stem = 0;
switch (method)
{
@@ -92,6 +92,9 @@ void txpool_tx_meta_t::set_relay_method(relay_method method) noexcept
default:
case relay_method::fluff:
break;
case relay_method::stem:
dandelionpp_stem = 1;
break;
case relay_method::block:
kept_by_block = 1;
break;
@@ -106,9 +109,26 @@ relay_method txpool_tx_meta_t::get_relay_method() const noexcept
return relay_method::none;
if (is_local)
return relay_method::local;
if (dandelionpp_stem)
return relay_method::stem;
return relay_method::fluff;
}
bool txpool_tx_meta_t::upgrade_relay_method(relay_method method) noexcept
{
static_assert(relay_method::none < relay_method::local, "bad relay_method value");
static_assert(relay_method::local < relay_method::stem, "bad relay_method value");
static_assert(relay_method::stem < relay_method::fluff, "bad relay_method value");
static_assert(relay_method::fluff < relay_method::block, "bad relay_method value");
if (get_relay_method() < method)
{
set_relay_method(method);
return true;
}
return false;
}
const command_line::arg_descriptor<std::string> arg_db_sync_mode = {
"db-sync-mode"
, "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[<nblocks_per_sync>[blocks]|<nbytes_per_sync>[bytes]]."
@@ -411,582 +431,7 @@ void BlockchainDB::fixup()
LOG_PRINT_L1("Database is opened read only - skipping fixup check");
return;
}
// There was a bug that would cause key images for transactions without
// any outputs to not be added to the spent key image set. There are two
// instances of such transactions, in blocks 202612 and 685498.
// The key images below are those from the inputs in those transactions.
// On testnet, there are no such transactions
// See commit 533acc30eda7792c802ea8b6417917fa99b8bc2b for the fix
static const char * const mainnet_genesis_hex = "418015bb9ae982a1975da7d79277c2705727a56894ba0fb246adaabb1f4632e3";
crypto::hash mainnet_genesis_hash;
epee::string_tools::hex_to_pod(mainnet_genesis_hex, mainnet_genesis_hash );
set_batch_transactions(true);
batch_start();
if (get_block_hash_from_height(0) == mainnet_genesis_hash)
{
// block 202612 (511 key images in 511 transactions)
static const char * const key_images_202612[] =
{
"51fc647fb27439fbb3672197d2068e4110391edf80d822f58607bd5757cba7f3",
"d8cf1c1bd41f13c4553186e130e6e2c1cd80135ddb418f350088926997a95ca9",
"95d2556c8acd1457dce7bfd9c83b1d82b821a55a9c9588b04b7b5cf562a65949",
"4b5d987fee1bb563a162d23e41741ad73560c003e26a09b6655f09496538daac",
"1d25ea86323d1578579d3894a54b99ea1c3e2dca547c6726c44aef67db958b02",
"92e46fb70be5d9df39ca83c4fc6ae26c594118314bb75502a9c9752a781d0b33",
"924d0cb9060d429be7e59d164a0f80a4dabc3607d44401b26fb93e7182ab435d",
"f63e4a23fec860fd4c3734623891330ac1ff5af251e83a0e6247287818b8a72f",
"5b14c5ef13738d015619b61dacefc2ade3660d25b35ef96330a8f4e2afc26526",
"d5016b012a2fb6ca23fd56ece544d847962264b4aee15efe1465805fd824a8fb",
"0a7f3da1d9dd341cd96829e484b07163099763ac7bd60603b7ee14f7dbcb278d",
"d716c03d7447d2b693f6f61b6ad36bd57344033fc1a11feaf60d569f40014530",
"23154a812e99ce226f6a87087e0812f419aed51289f1c0c359b0b61303b53a36",
"03940341e1a99d5b0c68eacfdf5a20df90d7d0a3d6089d39709cdd964490755c",
"ef09648814cfe071f5d8e9cfde57247ad09409265c4b6c84697bbb046809bd7e",
"8843ec52b0496ca4e895813cfe00bb18ea777d3618e9bd2e200287e888e2f5c7",
"8558bf39baf3df62b5d33cdf97163a365e6c44f4d6deef920730b4982b66449f",
"504d9380ce581de0af97d5800d5ca9e61d78df368907151ab1e567eb6445332a",
"673797763593c23b3ee07b43bd8760365e2c251a8a60a275528ff34a477110cc",
"25178c95e4d402c58d79c160d2c52dd3c45db2c78e6aaa8d24d35c64f19d4957",
"407c3a05dcc8bdcb0446b5d562cf05b4536fc7337344765215130d5f1e7ee906",
"4e7fa771a5455d8ee8295f01181a360cdc6467cc185c2834c7daf9fbf85b6f1d",
"6beb64cb024f9c5c988f942177fc9c1ec5ecfa85b7db0f13a17f9f98e8e46fe7",
"6406bfc4e486e64c889ea15577d66e5835c65c6a39ec081af8ac5acdc153b4b5",
"1b1da638709f9f85898af70ffaa5b88d5a4c9f2663ca92113c400ab25caf553c",
"da49407a9e1ed27abd28076a647177157c42517e2542e9b6a4921fdadf4e8742",
"3c3fdba2a792fddaeb033605163991a09933e8f05c6c934d718e50a613b64d69",
"82c60429171173739fa67c4807cab359620299e6ed2a9da80139b5b1e23c5456",
"0a19e5767e1381ac16f57cfa5aabd8463551d19f069f7f3465c11a8583253f3e",
"d0fae6ffdd4818399eae6224978f170f696150eaf699f2f218abc00c68530f96",
"0937889aeb3af5c64608d9a9f88229a068e53417448f00f9aa5e28c570cca8f8",
"d6072d269753020912524961ce8c6930cf35abe5c4b2bdc7fd678338d20a68fb",
"0e8bc9b06fcc842bdaa7df029bfd1f252d5defc014d58a006c10ab678ecf543f",
"9d42f90520f02c9258be53b123d69ddbce5f33f92a903d3fb4cf3358ff0e07b5",
"1cc05416b12cbe719617158773c3e6173435fc64e1ee44310dc696baecaeaa95",
"266b15222913c11ef6403ee15dc42c8c0e16bc5fa2f49110447802236e045797",
"791b123af3b71ac9497a010610f72207ff8ec642969b5cf0d2891b21e7eee562",
"946d4d7b084dc32495f22b35fc30394144c8e0ba04f3ad6e2c2bfb0173a2266d",
"2c015cb990c1583228d08b2d5de9227b950c3f57364fc1033bca5c0fbfd08c58",
"13fdc41862fd85507f579c69accb9cc6a40f5971bfa41e3caff598a3dcffd2fc",
"64b06d9874a83917c583c9439d1c736083377d67fda2961b623f7124663134c3",
"2fa49cd19e0aa02989991a4c3760f44be800fe8fb4d58b23aca382e10dc0d2d6",
"377628f265f799772e9fb6065be8b6eee200c329f729fe36c25ee179e4d20df9",
"ba94fa79134ce383b6a98b04dc6ad3d1b950e410d50a292bc770f9685e59fe91",
"875c924329f0733e31fe8d8aed70dc1906335b8a9984932b6368ea24edb39765",
"f31f4abb3f5ee42a5aae86d70b3bd9a9c1934933641893864dd333f89719d608",
"2bcd629e125514a780f568d3c2e8b12a2e7fbbee06e652bbeed3e7825508e31c",
"918b43581163ca1963de21bb9ac401756e75c3f00ac8dcfafc139f1ad5d7d998",
"5730dd57fa52749a0d6502b11c9d802ac495875542431310c674a65655b7c2a3",
"03f84b990683e569e2f6143bb963a2a8de411e7c4b7923117b94c7afcb4b43ea",
"b298c8510d35bd2be0ff0753ad7d98d480f4c6490bb67fb93cd4632ea726e8a7",
"0a771afbf9be104c01b89eaeb57073297d35ac8fbbcc0816820fdb9a29d26625",
"713d90d6ca1be1a4e05a5f8441dc528c699caa09eda49c09072f5f8291354c2e",
"988827f45c19330d9404309f63d536a447803cca7cb182ef005b074def09ab7d",
"9dcaa105b4def895f3faee704c250bdc924316f153cb972f3fb565beec0b7942",
"1c06c30afe65b59e9e22d6bb454e4209a03efe53cdbf27b3945d5d75b1b90427",
"49e08c13d1da209ec1aea7b7fbe0daa648e30febeb2aa5ffbaaabdd71a278ac2",
"e1c2e49ab7b829854c46a64772ded35459908e0f563edbcf5c612913b7767046",
"e08bb7d133490ca85a6325d46807170cd07618b6a5f6e1d069e44890cc366fab",
"5c73ca0691cde2f35b7933d6db33f0b642ec70d0bd3f2b0ebbd97754ca67e248",
"6404399151872a521dae767311712225dba65d810ba2feba209204221b5d772d",
"4a0c3aa6cef36f44edf08ad8fb1533d7e1186e317da8a3afb3d81af072043233",
"104b3e1af37cf10b663a7ec8452ea882082018c4d5be4cd49e7f532e2fea64e5",
"e723a46bf9684b4476c3005eb5c26511c58b7eb3c708ddf7470ee30a40834b32",
"18e6f0fa3aa779a73ceefabea27bff3202003fd2c558ec5f5d07920528947d57",
"c97e73eb593ff39e63307220796cc64974c0c8adac860a2559ab47c49bc0c860",
"13c363a962955b00db6d5a68b8307cd900ae9202d9b2deb357b8d433545244ac",
"76a488865151fab977d3639bac6cba4ba9b52aa17d28ac3580775ed0bff393e4",
"a14de587c9f4cd50bb470ecffd10026de97b9b5e327168a0a8906891d39d4319",
"b1d38ee1c4ca8ae2754a719706e6f71865e8c512310061b8d26438fedf78707e",
"772bb8a3f74be96fa84be5fa8f9a8ef355e2df54869c2e8ae6ad2bf54ed5057e",
"3083a7011da36be63e3f7cacd70ab52e364dd58783302f1cb07535a66b5735f5",
"2b1d892e3002aa3201deb4ffe28c0c43b75b8f30c96b5d43f6d5829049ecbd94",
"cb738aabe44c6fb17ade284bf27db0169e309bf8cf9c91c4e4e62856619a4c64",
"1707e04b792f4953f460f217b9bb94c84cef60736a749fb01277cfe0eaaa48c7",
"ab8b6bac9b8a4f00b78acb4bd50ed2758e0fa100964b6f298d2a943eb2af2b30",
"dd317193fef72490f3be01293b29e9c2f94eda10824a76ca74bf39dd7cb40ab2",
"4fb3d995b087af7517fcb79e71f43bac0c4fbda64d89417a40ca4a708f2e8bc1",
"549ba38c31bf926b2cb7e8f7f15d15df6388dce477a3aff0245caa44606849fc",
"7585c14ab9abbffb89d0fa9f00c78ecae9f7c9062e5d4f1fae8453b3951fc60b",
"953f855323f72461b7167e3df0f4fd746a06f5a7f98aa42acdce2eef822a0b2f",
"0931932d57dde94dcfb017179a5a0954b7d671422149738260a365ca44f50eb8",
"a3d179d16a4a275a3bb0f260cee9284db243abad637a9dbe92d02940f1c7ee8c",
"959843f1e76ff0785dafe312c2ea66380fdc32b9d6180920f05f874c74599a80",
"fbc36b3e1718fe6c338968b04caa01a7adb315d206abc63e56768d69e008a65d",
"f054de7eac5e2ea48072e7fb4db93594c5f5d2dfa0afe8266042b6adc80dfdca",
"39dfc68dc6ba8c457b2995562c867cef2f2cf994e8d6776a6b20869e25053f70",
"19ad7ca7629758c22ac83643605c8a32a6665bae8e35dbc9b4ad90343756ebb3",
"e89e80ea5c64cf7840f614f26e35a12c9c3091fa873e63b298835d9eda31a9ea",
"572c1b9a83c947f62331b83009cc2ec9e62eab7260b49929388e6500c45cd917",
"df0b21f679e6c0bf97f7b874e9f07c93c3467b092f3d9e1484e5646fda6eca5f",
"8f3b7c0f4b403af62fe83d3cfac3f1e2572af8afa4cea3f3e2e04291efe84cf6",
"aae8b8db243009d021d8c9897d52ee8125a17212f0a8b85f681ad8950ae45f0e",
"3d45a4957d27447dea83d9ae2ef392a3a86619bfcf8dda2db405a7b304997797",
"a5b0a619a8e3030b691bdba1ed951cd54e4bc2063602eae26d9791fb18e60301",
"14650df217dd64a2905cd058114e761502dff37d40e80789200bc53af29b265f",
"fd6a245ab5e4e6e18d7ba9b37478ce38248f0ab864e5511d2208ae3d25017e5f",
"fbe0be6dd42a11feb5db5ae56fcbbac41041ab04a35f1df075580e960c8eeab0",
"72f3f1213d9bec92ba9705b447d99cd0a6a446e37a3c1c50bb8ece1090bfe56e",
"20df836554e1534f62b2a6df9ce58e11c1b9b4746ce8ee3c462300a8c01f5e76",
"5c3d2a81b7331c86420ad32b6e9a212b73b1c3413724a0f91bf073eba18e2f1f",
"63264ddfb29cd36fc18f3ee6614c4101ba7229bc5ac375f912590d3f0df982f4",
"5ec4eb637761c1c9dbc6aa6649d4410508ef8d25d61ad6caa40c6ee3236d5515",
"270c70940536017915e1cdbc003de7279ec1c94cba1ef6130f4236f7e306e4f0",
"c1d1d57a7c03f6ddeeab5230a4910db8355e2143f473dea6e1d57c2f8d882b76",
"218c030a7fdc9917e9f87e2921e258d34d7740a68b5bee48a392b8a2acf1f347",
"ac47861c01c89ea64abee14cf6e1f317859ed56b69ae66377dc63e6575b7b1eb",
"23bf549c8a03f9870983c8098e974308ec362354b0dcf636c242a88f24fc2718",
"a3ce8b817e5212c851c6b95e693849a396c79b0d04b2a554de9b78933fbea2b7",
"7310120c1cc1961b0d3fce13743c8a7075ae426fe6cccaf83600f24cee106236",
"8fa0630f193777dcc4f5eccd1ad9ceacf80acdf65e52e4e01bf3a2b2fdd0dac6",
"4a5f5c87f67d573d0673f01abaebc26eaa62e6d04627588549cc9e6c142dc994",
"78971cccacc645116f9d380c167f955d54b386a22af112233f7de004fc0c8316",
"badc67216868e1de1bbe044bf0e6070e6ee0353d05c13fa0c43b1897db5219a2",
"c45b2a168bc51cbb615a79f97432cc4bb6b104da9cdc1fc640c930657452f71b",
"c17eda13541d14554c5db542155b08b6bf9cb403d425745b662ebc2b2b9b3a3b",
"313210cd9d2efc1603f07859bae7bd5fb5914f4a631b943f2f6ff5927a4e681a",
"6ee94ec8af4e6828f9b46c590ea55da640ef50e810a247d3e8cdf4b91c42d2c2",
"505b7a4d9f1ba6577aa2a941843f86c205b23b1ea21035925e587022e2f0aeed",
"98e6a7cd687e8192e300a8202999ec31ad57bc34f656f2ae90d148607ff6d29f",
"1be5db002c0a446cc2c1da363e5d08ae045cd8f5e76c8cccd65d5166393c0bdf",
"17c02ac6d390c5c735e1e873c40294220e89071fca08a5da396a131fa1ba8670",
"2540507c39ae6fdcd90de826077f0ca390da126166a25c15c048a60606a27367",
"5ab9328e525c7a017ef4f591d995ad4595d74cbf8ff4112af33b08c70661a304",
"9c105587a96c51d81422f64e46016564d22329760648c95dcac7218f3733f915",
"525afb1b94a75f1edc2b55c700071e14a2166acda003370047c30dba8ea80278",
"745d4a5d9f95ca4efa6261b6bcd4ecacd504b5b901a2ce1353c522a5c0c15dcc",
"5a5a568cd87ba34252ba254e6a320e1a7f52f13e7451bb887efb34ff881785f2",
"1ec50a80198cd830b51f4f7a0222015a268d9b40f04e7f838c7b8dc7abf63b01",
"68836b662d79349cb42f5cef54e6a066157d398cc87d3b13f29fc04e5cf364a5",
"658db317f355a9cbd86f673775cac0c308fe14967428fd283a36e300a6a53b2f",
"677d79a8c467dd9db38f0ef45c2787dd368f701a6b47bf7a5f06112c38da643e",
"2baa455d4066f5d628f9ecd315cb57deca71069db5d0d112ae0aa18a84b6f0d7",
"5e7b0889f351560081360ac2b1429b48b2f7d886227f144e3b198e2f1fa56ed9",
"c3d317fbf26e15add8b4f8f93df9de9b22297b8e4945ebab9ee249d4f72f4e45",
"3c0b705a5c1e31abc7e46d8ff3c148a033f6875454cfb67f8d2a2b9a57a5ba7e",
"a0ab74663561af2adc2d38be3569fbe7aa2454346416ac96e5eb26b1e01b1e2f",
"53526cffdb74327670566c1dacacffb7d30a43a7f1862ff8bab87737bfa5edb6",
"24c5d36ab98d88f87b2c71afb4ea8562e05c7aa0b50f3bc0f9ed50a4cd52989b",
"c3ce4de5f94dff65d11e33a865855a4404259cf45263914c884f79db4f35169d",
"f1009b6dcf30030cff872d636fb96ed233eb6ecb8ffed003c7da64e4f5a02f4c",
"e3729f58614d3b42450d1599d863983ab7e3e5c29fb57aad7958c8923a2627c4",
"31cf4792f7b5ce01b217ec80184edd2a7c49c0b21701f5494ee2c9bac67c28ca",
"b42a5c9c92a656c5bb2b759ce160fdfd245243aeb1786338faea63b62e9a60ce",
"a1efc8d5d0855933d5ac8fe5960c7acacb92fcb09bfbc929e5002f168251e648",
"c4322c7f3682ec94b0dcb42f13b498c36cf575d505aacc8ec8bf67a6a2abf4c9",
"684ee5aa3c98357aeaddcc30c6620939b52aeef729e24b4a46ccafc44f24d831",
"36180f2ae11d105e0efbfbddb94e6b45b08609a383e4e1a8fa3b06d7a8051de9",
"96c2d183eacc87581a0b17b8d07878bc10d436728510715109a7565d9972f8b5",
"3068c9d04d561c7e29e3f621280b61a61885de0e9ec35a66a3116ca7a9e09627",
"2eb94b9673ad6f8f88288fddfceae4baaeccb37bed88a35611d826ba06a5363b",
"fc8cd5fae8b81121001f7767dcd5f185c0fdcc88cce1fbb184ddbcfad697ba54",
"51521da1ecedea6d588d774eb155d936b32a14913c2f11d989bcc5116e65bf41",
"3d23542e597a83dd6307700d79058b920f281c65f832333734d8a0adec510495",
"11d2e01913ff0d4bd21970d709d88e63289492c0bbad7bff99c0d36858a841ca",
"de674f1eee3068d2bc8c2f2897d8556e5deb872869652f7d3a4e5dbc6f1063c8",
"e722d7f728526110c0921791b417afde4af1e87ae48ccc01911786197843104b",
"aaba3a4e2a7d20ab76edfbcccefc27acfd509db3638582c28230e73ffd71d340",
"1385a7209dafb9622dd4274179832e40c7fae19445383c34ef79adb0e4de0c98",
"108408531fca288d74de4a2c596eab8569e355d9ab2f8380f4d24073a6b3fa95",
"294476a86fcd39351ae452cdb8af9584067ec4501ec6182d0062bb154559fed3",
"e64b175e0284c5cb69c8db46344ed43b5ced8abfe3cbf0c197103cfd116944cd",
"cdd73a0f1fa7c14ed2177ae2163035333718847e49dd5cca6775bd20fc7553ad",
"d423d2a374bc66a4587a5e3affa327ca75b8116051320759a3b88a868a7b80d4",
"f13ad1e5b1315557d5497b58516eb3b0759d909725ddd0eb8a0dee439c6c0a48",
"3a600b547a6061186a54e491344fd50cc7d4f0566a386a40aba6545254773728",
"37a6f3f221fe17cc04a65aa544d5135e8297ecaf0853ba784dffacb74feb481b",
"0ca42d67d0f84b28861d63e919e6ce5ad527447fdc53a03d8497a0241bee9376",
"c7dbda42459e6fadb92c416eaef3e04674fc57915a93f3be4e656634c9654075",
"0e34d728ae4fe347a5afecdf886fbd4d48a65c5d0dfab807da6ae95b6b2d7a3a",
"f1bc69257ed510db5b2ed370010b037f452a29c49e36337264b3011ce2516216",
"33f98f6b8a8e202463955998fba3b790199daa893e5471554826cfd9daa5c02f",
"f8a0a37a2c9ebd7022d7cded1ee0318fd363020070b4cdaea800e44dcc1300d2",
"6862714daedb908a4d86a3a3f1e65ec2c29ae61501b4ddcaf184243dd095d71b",
"555cd19a6d21941c1174129b8bbcc70edcf0d6874262ce9e1e542351990d523d",
"2cd6b44326828f23a2aa33699754bfa072c4883f39d53616f6a6b74149b664b6",
"127f45d2eacb565c21c1030fe8054fd0a3a75705bc368924712aa145d414fa47",
"19225e2dae6e1166f21cdab1290194470ded09df9b66f3faad3c1cc9ebcf340f",
"b7b3f53f0539b2b4837b8bb9dae0ccbd200c8d36126d9f50199d68a4293a46d3",
"6b6323be01f27d6d759d9670825e8ebb9c4cd8016351702328df91cef36cfec8",
"020c31cfdfc5b22b10235745b89b311d271cf82f2ba16d03fdf7a8bc8538694b",
"62573218530182b79e40d0113b7d281dace6da33bfcd0f9318558de5e5c76f08",
"37d928416b15982f5bb8be40c5b62fae0b664e412c25891f8860c4242927e610",
"b07ad11134a5c0542d2b418ef3863e8ea8477de68d9310681818ddd40825fdb0",
"4af77cb76bab845b56470c95ce7b8cd84ce49a095984c1f3eed67b0ee344316e",
"e3fdd4668d8726ba6adc401ac662c0cf6b5c1872082c488ed7da966d425fb1c0",
"3dec71c81c7e78e879abc8da8b30e2446edbe98eeb8df9dafe9201ebb4c6a834",
"7105467d9c5e855f1362fbddf820ed5e757997862efc9000317d3830a2f60ef3",
"2821df94b021d3e77e8d9c0f3972340210f5ea2c0935cbf125cfc578d4d6722f",
"114e5807accc337a22598bded30ebf3e0cfd75877e239f10cb043f829c315ab5",
"d658a1c0354628cd7312593ab25d5b9083de8f0def6e8425f188101d256cd136",
"4818d3be9b2a38fcc8c85d6c46f69b502943f79cf2462dfb0b6499e761bcc836",
"92b8c943cb017b5f2d39264640c069f1ecced1d3ce9b3fd755d6df2fddb99458",
"6edbd0fdf064fcbccd4a9e7a8ea520b87cb7faf867f7fe8a5f53625beb575119",
"bf3b49c477dafb06af65bf09851c0fbef9dbc3152a7268d31b55a8e7a9a95860",
"0e234dbadfda1393be2f068182615dbb83736f84f87710b5c7965bdce9f4a26a",
"df5ceae34429e47b92bbd5505ba27666552e0eb619997f359c55699c3252b1ff",
"08c1c7d940d699a91a83249bd578772e8958ffe23179e6150f07b96f1b47ce1e",
"6f919a429270da0022d70062537bdc1b21c43a8abc552d8e366647e5b719d310",
"63c66e5fd5d27f6fda87912ce46fa91a5e5b3634ed147fa2986330fc2696d3fa",
"bde070b75296bca3aa494e7f549cd2bd1ff003776712bc98a3164b139b2054ab",
"66694196dac5b60cf5e0ae05db8f3894fe04d65910686806551f471a0a0472e9",
"0d2e97524b7ce4cf30b54e61b2689df036d099c53d42e2977b1671834bac39e7",
"e081af76e923455f408127862be5c9baf7de6b19b952aa2a1da997d4dfe594c0",
"121bf6ae1596983b703d62fecf60ea7dd3c3909acf1e0911652e7dadb420ed12",
"a25e7b17464df71cd84ad08b17c5268520923bc33fe78c21b756f17353ea39a0",
"e985f078fb44dbfdf3f4f34388f0f233a4e413e02297ee9a7dcc3fcceacd44f9",
"b9184cf45e6e6b112cd863b1719de1bcab2137eb957e8028edca3a204a9ebb96",
"157d177d5e4bcce0040eb4bddb681eacf9e2942e1c542a57ce851b4742a9cc4f",
"0823e06635c9a1a69fd8833d1e48df98d711c1c47c06f27bb384932db1bbe9ee",
"8beeec1fd1bcdecba235b449cc49abca69b6486ed1c0861a2bfb6a43c970b86f",
"349f61a1cfc9112e537522858a0edae732a2f8434cf4780d3d2ec1e96f581cca",
"587cdf72b5914d364f7e214a70481cf1131ee4a09e6b43e52428d2e56b000c13",
"a6aa0c179316534c7b9ffb5f42a2af98d1d3a166bfb413199579f259c7b5e6df",
"f9f3bb1ba8da5899b79186008ecfbd416b49f3b86d94045b91e34a40e41d5cff",
"0cdda65a60b7b4d94e794c9397e01f69fb29309ce4fac83e7392dbba6bc497f9",
"8fa5fce5ad09d43af7218ea5724cff2c4849a59ff73caf3bbca466e3c8538ba8",
"8874ef46008753fcc0b77eb7a4a8560e35966bf5a12bcad4203ad2b4c1f8bfbe",
"a8ee9a3aa2d0c08a951439ffb0e6d10315fc4776997b275de1ec19663e88c2c2",
"9c184cbbff464ab4d5f6bfa78c39bf0880fb93b1574139306a97acb940d415c9",
"5493a38c255c91ca49b958ed417f6c57e5bc444779d8f536f290596a31bc63d3",
"3e1e82b96cc599d9fc55ae74330692ccbfb538a4cc923975fd8876efe4b81552",
"16aaaf820c24c2726e349b0e49bbab72ca6eef7b3a2835de88d0cececa4da684",
"7fa52ba349f7203c3dbc2249f9881101a3318d21869dd59f17abf953d234db65",
"713d8018bb9ba3ab55c3a110120b9d7593514111075ef05f0fdb233ff2ceddc8",
"56063afb495759a0942f1c33f28a4fb8320c6d376cb3c9513249453e45f24a04",
"f9a6bacd9e055749b45174ecf3c3db18b78f3474761948a68adf601f54e59660",
"7ddd7c6d41572f93fe07c0300c34e455b6d1f4372204933bf45035241c8b060c",
"f81021b893a36b201de71330a2ea050b59dbf7560c62fa9cbea9261ab47a0ba2",
"a01fbe4114c18fd534ae1621404d25c08e3b6775a2631ff40279bafd8c9304f4",
"350fad8ebc938c6eb508a1483f385f577794a002bc1229db70a1b0131d174b9d",
"570cb8bce87f532c5051d8c4c864012408e672a7d492669e660251fb1e066bec",
"8cb6efbb129c84eba26d894c4293b476a6e9a1fe969c6ad18b554d2a57885f36",
"f384a98467bf7f084ca31bea121a4ec76e530f523d3225c21ed25a18544a9916",
"da127ab58ce557c2c95c20d6a291c2e5d880fff09dc28927b7bdfec97b995d72",
"a4d95b4f74366ec920d0a0c5d81265688cc18733ffc444cac9b01ae2431568aa",
"5ae2a71470570733422468bb733d53c85b1c8a6e7e6df5c05941556bcf342d1a",
"65a2d161ff0e095d3afe37584dbbe649f1e9cd440755b5a3c5b2a252d5c0b8bc",
"25ef70a8e41bb422ed7996a41160294e33238d6af17a532232f0a50b123431a2",
"f1f0f76ee901664a65b97104296babb9c7422370e99bb677ae07c2ee420e7f40",
"c3c66dda180b0330e75c8139b9f315a8c6b937f55d87d7be42e172bbac60d71e",
"5881786695a9e58e19d79f790c7d9243a847c0269c5770bdd01f5149c2a62a88",
"f2f816d3c8ebc7df06ab68d39223181aacc7be04364d1d4e69a56c33949bb983",
"80a1c3b6b2778d4846ad9fe0bb2dd5afd99aa897f8231bfaac45fde43d602d9f",
"72ad67cb043aa5df0c3dcc2464953a66893259d81c9cc7778c12bca3447fbd58",
"ad72420a7963b8d4536d8eba00b4b989992247cd8c01660e242a8e71edaf0e19",
"999d603d1cf6068e3bb6abe1bca976fa0ab84c4660b29ea8973de8b5cf5fd283",
"e137a5910f02a764c3a3d8f1579ac0c7e3cc34e58933216868efe010332c1e6e",
"10e0fa2362f59317626ae989bd1f962c583339d8d74d76c3e585243d152b91e8",
"1951c652704962f5c6e33a4d4aadfee5d53ce2253644d1ed542da3e278524a07",
"c938bccb7ba6c0217d8ba35ed91502aee051c8ae5bff05e88aab3b322aec936f",
"4d6386c689785edd5beb55911a3a9fc8914838c8192184199589beef8b6ddf9f",
"26f6f45a6468bc4b1f085fd28d63c264ee17564f9e247fc03ee179a0b579dcda",
"235b7bb82b72c61acd5979ca5f2ca740aee805a780ba22e11aae5cd34f6ec760",
"c027ffb585a1e4844b4907490b621b08c7e40a5e6f93e97bd4bb1b615bba9908",
"aa77fc8053d139b998577319de29457b78b1cc8b35a5f3526c0621eaa42ce6e8",
"afd0af9a11c5ae2a7c4a4571ce39ad57d8df70ef146ed83ad8eaff97b2387fb8",
"a1f8fee9f1da9a2b306489d00edf754187b55e97f4fe6f249432fe6c7f44d6be",
"4f12e8a123465a862060efb656299e6bef732e5954b02194308817b243e84d32",
"6a1ca62f7d6952ad2eba1c64035260319baf03deabf856ca860744fc886b3d3a",
"c72dd1fe890d6e4c1f7325a4f224e85aef6cdca8bf9441d228efaf126e02ba63",
"2f6ddcea18d891ef4252e657989de68adcc43c2175d49c0c059c5e49b9dd5aed",
"24efac0f240ed183c30398ee40307623f52113598f66c5864c90fc62643a2aec",
"6ba3ebc935e7cf7fbb446e7f5c12b19c4455e6894412b0eedee4fc945e429e9a",
"3519d6e5bc9649f97d07a07ef5471a553ffce35c7619f4f63e91a2ba38cbb729",
"65e073df352fa9917e5c2475167e6c523b68c1406e1b6e81109e2d4cc87c740d",
"d73bf816c3648a7d53d34be938c454e515efb0c974d5a225f33635540b2db90d",
"bce167790fc86a273db011757d09e2d1148521ce242c2ded58f26cc49993aacb",
"2d4286ed4039916f29602e86f47ea4c5b05998c0198509ca7799fcadfb337e8d",
"9837c495b1af4f76b09177514a0f3e1dceb509c52b91712f3c7d29dc1b91d09b",
"5c848b8291f39759903ce77f151acf40f3ab5afa2d4a45af62b320371c29a697",
"b92df5016ee947ce6a21365d3361977f7f2f6c14025a983c44e13d3e8cc72152",
"71d2f57222a39b1a7ed2df5e6fb23a964439b5a8e7d49b49d87e5cd5354baa75",
"88b44d0198fb15b0c20a97f87e021c744606bfd35eae2874f35c447aa4ac3cd4",
"29bb4c2557714119cd684da2867e689e37e3ca9c912db83ab84746816f6092ab",
"b1836d98a288752675b133b9018fa1edf174f311921d01926c1e1a5900c21029",
"a00645e090c7d96f3155ffbcfc41e526a763b0f53a98151ac4a7d4a5b14066b6",
"78aab09919d17773b0d62799b37bd2e2970f72f5d1eb6472489c367b6135374f",
"eb6123aeb28608f1c97b2bf62ef69f977cd0658a0ab491deebb1e972caa938c5",
"8dd7ef1650b1b30cdf7814ae4d61a237eb0acc3ec3ce0f72b1c25780329c2d7d",
"b1998419be3172858b990eea84fe10bb24b76c219cde277cb4305955fc7e0b65",
"1b10560016c4bc506eef9056dedc2943a17179081e6eaf85b48d37dc20eac3cc",
"1fb1d9d4d408a6734234910f554d272739a0d6fa401918d79b57be62c3f23ba2",
"dec878f54ce36788289b61d32de0d9539032aba22cd15522752f729659c7cc5c",
"fdbfd0773f5a66637b093dabf812197940d1134619a7e60a931b19915b7dab0a",
"21bd2c9aae052a1c187947d2964f2be4afa7b30248409c41a75522e88a4e7977",
"59326adab03416ec1d36699c18e5e4fa13ca1f2212d48c23bfdecb0be7263616",
"bcf263d39457c0aef8ef42fd98f8131198ec4fb203155dd5bcd759e499a9ca5c",
"f1ad083bcd8c7630eef93336d8a971ae8ae37166a6a00ac39684420c5f9afef8",
"d82ee2ac41b36e3c1787a01835bf054070486dc20f6565efedbbc37cd3bf5fa5",
"eba91a0dcbd3986299b0a3e66c116f77bd3421829291fd769522f01da26f107b",
"11016558b7e8c6386c6a3e862691dcba47e33e257f0e7df38901ea7c0eba894c",
"04f02795e34a0030e5186c8e700da8a46b1aa6bc0abed6b35c9c1cd6a73776b9",
"2628dc8ad7fb731d59456b2755a99c6701467125fa69816c21bfccabc31edf6b",
"9b7ca249ee5b45cd264492f30df09f708a7d9caed7beb9a5c6292f22e4c31f85",
"5c42e7caedf382092faaf392174792b3cf5f2fe29cb586387ee55611af0617c9",
"373f2fd5940a01feb79659c8b9099477f6d3e7b570ebb749c2ac336ea4be583d",
"fea22887147adc3a659a14902080b03e86b4b8b16985fdf0bbacaed00d812422",
"6a3e51a1443cff62af9fa12fafc8ea78ae74dac7792c9ae0f436f570ab33eb71",
"796be21e213d6d0cd6fbe2de1555fb73d1cf9edc041a9f1ff1ad583c4ca92460",
"03fcbcb31d3fd17f0eedb45ac5a51678c7c8b2b8498225d05f74e2892f017f72",
"d28da07c6c22daf9ae987b3033c33d3140e5a56fa1ffd7dc5c7853d55a45bcc7",
"fbb0ce02f50018741a12fc08eea80a18067d7bb0fcd96153d40bb8c808473aae",
"2bf7c05a0209b4ea31314f04bd754cd01c58102d7cde8c496c655b6494924354",
"1968a9e6e14ae86a1e02e6078fc4631851fce5dbac6aa34f860defd1ccfd0ded",
"d886181329c9e06462a1407f547d77b38ff2c868b86d8976aa478e1cbb3d66d4",
"0d465e02ff2f8eb0b5fb2fa9a38579c5d66337d4a16b58f8ed28d2d89fc02392",
"3196419015289807880ef24b6781734822d654dc260c0560d00bac65eacd5219",
"fa08390ddc333a2a12248d5ec3e51fff9b782227069fe5a0afbd8eba967ae8d1",
"49ae36a791cb84516688d59a1ed3e5112851d65f265078aa2d433b45fa984c8a",
"35daa428e12c59da6730760979aca3444d8b31149c6febd99fbfefa4b2372082",
"5ef1d697beba612ff31d1dc139817c313a4e2ad3977775943b635c141ef0f2a1",
"674256037ec00edb66b9355fb1d33a30a47a5d1f4bce2dd5475d89f1ea6502db",
"7b6f017bc550933af91eec32a79464f540c5e0c208703e175843ee4e9ffc0a50",
"bf0eb91da1d18dbb18fd9ff36c837387887ba142961176a44889718b2becb9dc",
"3e5ac43a05164b074a2ff6353e9882917c5a3dbe168c2695de895f7decf1a56c",
"35e8f004965347c2b18a000a83dd3a8084b8a4bf00522061ed1179aa1107c413",
"fccb0fff3a24e555ec96f702ec11d420338910d148fc7b039d67568ad3a0e032",
"5cab231048032dbf921b4fafa1951dd2da93bc3740667f31d5a1d5665b141261",
"ffedb24be73441fbcd069f7785ebb865870e0f3ed228190732e4ffd5962bb82d",
"a4fcfec18adf92f4ed822f64d2da9f5ae630885a1bfa626530f641db99aa7a30",
"f98bcee41b0e3deafa1efaa1863750dbfd9bd7430b82529b670867d852230b5d",
"8ab8d5fca047a52364a737c1af57bf656c9ad5049f08ef4c5aa252e61aa72123",
"91318b39ad94c1d58143586b6d90dd6092a9d7487e321f4976967b6ac445ff43",
"fabfbd4569ab018e12d5ffa9b1a40ca8eb2ca60a685817351d90eaa770d5eccb",
"bbc5ef34428d980e2401942ceecfe07cdf21bfb1acae0596ea1d43fccf504f69",
"26943e4201ea407a5667103fe07ca6e08ef76940f274349b0e2e776bcfb0acb6",
"e3b305ffe33e72841f8e2a8688cc5cc27d42aee7624b33b7b6399b42db392437",
"17c5a763dd57e6bcc7c4cf2db0eb5cf3e97116b67fe0dd519c97e4a4d55d5a62",
"bbd260216879ce86af8318ffcf73c9e063ca76dd8bc35d3b6be45b2b4184888b",
"41285591d0595bc42ab663051b410d51af39fe1720592e27acb1a8af72360a76",
"f29acd6068ce494d0c0fe294cad91bb8968e3fff3f595a113227ab545c3ca3e6",
"ec9013c6394528e7dd788ce7cc085ca79fcdfbb37565999d5b4b5a4e39452ecc",
"27829bd7f1a8fcddcad0cc34a3b3fc67d62a2f3e09f8e75d35035c2281e83afd",
"666bea9db4e15087204d076294d221d4cf5864f5d94de38f29132b1934a17ace",
"a3a30924cad3dbda3446e5a6324e0a1390c70f795d5ecfe17ee5c70b14f7d87d",
"19567fe5fdb10711d60aa4d9843e1c49c2a6d2fd1b5cf662e2105606bb7815d3",
"b139f1c3a2f15596b9320334e37e4184d5d584c4a81e72d821a7edcad3aa62d5",
"08f1531e0e3e8f8bae313b2c60a72d5601bf8b60d7a4d2f60e8481650340d250",
"c5895669e1ff182bf1dd6c00dc955265e08ded0952b8ca62a1c63ba11c99f4ca",
"84d1c28153f66c1a4eb5fa0df695e936d83294df31a08d8d8e2d4798d19d8ce0",
"b8699f6af853fdbe897848feb46a05d733363f304eac4c8c1932e6ea4bc062cb",
"10eb3f6c1d0661468d9ed83593e5e9c0b43c6feec6a5405a498194905ea6ed48",
"509e215a600d9cadcbf5d62632ba321d7314764218db00ce8c907e425fccc445",
"e62119b7be84c8eaad41ba7f4a35da403f4ed96b967a3134e89ee8b78f8792c2",
"f790754a95d59ea5ffe6b9b5cc386c600a9e19e8bec997c192764365f1d05376",
"990121b5aa4d6badfb7154db4cdbb4512124bc2f442bebac71ea90b5cc86f203",
"b6983dedaa891eb14c964d84461e5cd37ed27b61771c64978ba83e3ecea194fa",
"00fba1ceaa6aa1e378cd5b22a771d6070250ac37f4e17d7bf1a70b3139e9a860",
"429854e7738abf2ecf46909454039e2fc5a080eb9a3c0c5ea13b07426dac3ad9",
"ceb3e017944b0dd787be219d8629930b3f2e20e22b12dc88fd838488ebb896f3",
"eb9e5d14424c63e675fe771b73ca865f7d38cf334d65e2426e12a0b88c1a2236",
"556ee713449e6e59ac4b8b2e8310180c8f6280484e9db23456526cceb9216168",
"bc89c3aa889e0144ac526a1f861227430dde7e439cc6a7e9b25c9a049c3ca7b3",
"56d070c62ea99be66fff741a8e45fafda5f9ff783e84d5395b251f356ce4e16f",
"ace15859c399e5ecd13b1420d3c3703c6a88dfb4a084f7225e7ba40a4b444fc8",
"f03f1261ab6eb879fe9c5b0028cd400b3ffdfac4344e4c75f6cde3c05ded1f26",
"955b2fda8d0068226f89270028b316b5adac871f1c1c85435479aba14a381b0f",
"422509a98d7461a6b8ec87cbb173b2486577b59ea9b269e01c20567b38b3b3b2",
"007d4de62ad89a4f5985f0cd9b76a7293acf383b4e9e734e813b9df1d57f986f",
"13a04e32948225b7e22aa0137341ebbb811e0743032fac16be9d691a652db2eb",
"8244b11d880a52f9f9e1830a822e6eeeaf0b12fc759f8261bc2f490cb0794f3b",
"27d3415f8f8fd3048a1ee0d9487256dd1b0f9e31be663778efa5b3add63868ec",
"0053f888db916a8905320e253fe2f0666355e6fb6de36f897231920a3edfe39f",
"0bc5c0a2ea47fa3bb8be107e3b9d6b7226b1c8bd16ca1bab8f51b8e1de08aa8b",
"4ca13aaa161c79025b5cd6c9a8ac33554f5ceb479fe293d9a342c865cd9c9948",
"333afbe82e2a3df38bd1ef998f39c5feef2554697aa21b5410c0e95ef9156249",
"587c4fcabd18ff890064171fce3d5be0c4aa1bba46893fb6a827a85ab54d20f3",
"964328e4d51d67c4e2f1fd102a66b861d98199f81d18d660b1b4b52504cd772a",
"196aad5594651efd679d30b9feb0f0d172cf977b4f89aa670ec741a8bf21e669",
"9137bfd66bbf47bfa0bfcbb9f6e71b6eb3fd9776530e9fd30d3dab19e182f35d",
"8217392c4ed2313188f295d94148a027a7f43824a5f5fba33a0b8c1045d509b4",
"be9e12761519a4836e73015544163254877e1c4912fcea67a10e7026421dde75",
"7b5220421a520b876cc6cdba0d3895104d7fac914dca5b93f9fe8b226566b71e",
"5c83fccfeb4bf0eb8a94d43ebc84a81639a32f26c7ef77d0a2b626b7de7befdb",
"132fd6c92cf176f975efdb5ded53470b462a48a2815c6f54a93ce4f935784cc7",
"46a3dba364022d11aa616a2bc20e3be5c4390f38b9446edfa464d90d9af5d48f",
"34b3f3fd8a83905a37762060f51d0b116377b4820b031b8e668e16f46c5b0285",
"f0e397e033dabec859a4b9a9043c5f1fb0dba504764d6bcf2fe9bf2ffd318474",
"85ecf59c7dd3b24ad17f591bc4737f32f1384c370a7a6f2add06a811dc824b6c",
"4d03cdb1e6ad8e066a83654626d8c221433e8d4fd901c671300af37e000177f2",
"61cb9c651893e6401b25f2bdf79c9f3ddc9ffe69cf6c791c420462bd73e347e1",
"85f2686a42158cd5ad327781ecccd1bdcd346941dd4b4edc45f717de6a011800",
"92de2ab82cac528e6d4ccd61e5b7c79591dcad9909c8ad3c8276ece6d48c0f08",
"23a878a06bb94bff33083349149f3c860f2b00bc3fb28f04cbaf717c08af19a3",
"1b1cce18ff0323566b192885d7ced30f9a9531a2580240f2c593a7d5b8580974",
"08fcdec7ea1376d84f3b13a47a4b73c7781c9c7890bb28f712b58af4fd3f24fe",
"03cc08fc4ece807c6495272c412be23b045622cc6b786ed8d5c94156ae678a0e",
"c4d8a61dc3f5dcf4b83f27a90cbc37e816cf4754e12309626ec5679c99087c46",
"b29d00681e29001cdd63c4bc50e5e25715faef692aeebb678c8050e1c095e888",
"ac154617e93f2bb1afa232675f2135437a9cc9700c14c51c40084946596ba11a",
"ce9549de8e68ae89f424dd9e1cde8a4eea2069da667cfcfbe837691d37366668",
"426c45a98e2af35cc9708149f6c086ff5a3972e77d62c627d5e20de5d731cad8",
"7e21bfe240a3d9b77a129c734a1d428dbc890379fbaf862853f48b2f7470b2b0",
"fa090a71f77223a7210de6db18d9aa809e89fb15253aea28131df6c5a7639140",
"7094ad044c5ab025e088b43aa0b947601fabe58ed700a412fd96e4b917ced0c8",
"936d5cdc4f081b6fe36c356af4378d472cd7990303f2ea44da645afd7d5d7f9c",
"05342037d3b69349dce7b95529d4b2a63ceb9d9393217a68f7cc8c958a96c3ea",
"ff9e1c414ef27b1178b1de296526f50520b7ddb06286bf9c47792bfb449e40b6",
"2f2b7bedb34d2854b17ccb702cddd8bc0157e39721d58be0b2ad54ee291fc9f1",
"0d8db1f34140bbf7eb809137018a74af08cb3345b8a3e368cdda8521dab45791",
"b109e4bfabcfe4a1c38be1156d9ca851c75e6aa2e57c0869e40cd9056f571e07",
"5cb363547ca077c806fc69bc8c2006831ab89e72fd778ac1a48fa810934e350e",
"85ee928bb110fd64eae54a91fc8548883e7fc4c60a3c61b505c31cea2d295c86",
"1ec3df7d10ee6fd5f0532ad4fe771e6befc28b0bed0250bf523695d6d49a8246",
"de9db2fc07c866bd7b885fb41522b63d550d0ce2e8ac5e14464a41733c2319e6",
"9a27136422a8f56768db29ba172a7ba26c3c7aa910324e78e5ab3a3268ac3674",
"60213c315119bf9005cb533d1a5b403b4a13c59982fe7773d30fdd8f519f4205",
"40eb61ef1812eb8a4d389599bf449fc86653b2c4986061b952f46fc049de53f4",
"658ef0d8140162b5f04591be13b47456245f531208bbca3260b857ca09b803c5",
"02270fa66255048d724894e2206b4e773cc6a7b6d17ca090cdc25f317d5f53b9",
"2ec6a0147f419161f7198d05be5f93152d9ccc10672db0ea47ff1687c0f0dd15",
"4be1d8ceb96eb80ef7ce30079ded31163272aeccff5c18fe3aaa32ea2f5bed9d",
"04ecaf48f44de87243b17b4c71ebff00020738639336010fa57435a54b623798",
"e313a9feb7cfd1d56ec87b1f1062ff9a80da498f7b761af4bef0cecd1b4c385b",
"ede3748f971f22341f7f5844dc60fc03cdb30c7cc720ebe13ae588c17a78aa94",
"d90c0faa70e39b7c0a8c55457ed6e6478a4e4bf3707b08104326a1ee8377c3ab",
"c79ffd0bbc8d004cc542e212990df6498abddd3deb50fd00ed00a2ff690974d6",
"35c37d88cf73a89c4124b0ee537347c37fdb47156c8b0ecc509efc58236ed3f0",
"a99182f343ccf05e557ffa6df71f03688b2afcf314c59daa774fe78db6f47add",
"01115397a78af8a4ae2727ca7a01843235b626bd3db80888d3dfd0020d4135e2",
"4a55aced578470d2f7280096d7fe8095f294095fba4778d1977d6db9270472f0",
"4624adf8a5633f65b213b8ca46b55cb0ee36c41495f39b1ae70cbd545779b1a0",
"d72bcd5b57a9c47e7bd5e9a1103657d10beb7b6c6d41f2b2985bc3bd3cc74860",
"48baadb9a46293c92f29e7617846171356a42c3b5d18d49a05a7e173993785f7",
"3da927737af8cb0e1c77097e35c54158d18aabfb3051c45bcc7ddfe00b157b1f",
"b4a24bfdb2cb802c8d48a3a18fbfe18622a767fe7eddfca57d4555550ccd1643",
"c58f82ac7c49dcba1721a88358f07636c9df60d3fd383e5789b808dc57a1dc9d",
"5e1f756eff5155df073d30f4452bdafc4adaf4f35960771bf2c1e30137fd7a79",
"be4a332f289338d67bd4834eae3128c488a61d255e972da484b6252b67a46b89",
"d496e4a36238d03a83d8b45cf33d9388aa7568a279b034d1cdd87b457356cc5b",
"a1c5212730ccda34de393210e276bbd44720dda777bcfd602315a3eee582f7dc",
"08914ec63f6ef7fe1d678937dc0f6178883440b26b4aca29fce79068947e8397",
"49e2cd2bd9b974074d9814f93eed371620bd4ea5fbf97a625065704e8fb382d7",
"047c194111818b48ce93a4b006e4a09b9a2650757a87357111796e11e847bf23",
"5955b0baa8265341f35a6f24fdc79066ba3ca9c5354c69b6b37a9ef3a26be556",
"d7c962f3ea1938c5267cca4072548acf3afcce4d438ed62027caa211a5f98e8b",
"c8cfba67cb4ce7e291b35154a50476d9a5c6bbb5d6cbaaa5d2408547fea7b02b",
"de8a940d8a69a64ce264d2ab7320662aef2e391c587cb2aae22a86718d5dffbb",
"94176f1310b26e54d4de48f87b74aa0b60532f184a2268508dece86dd7f85d36",
"9ce6ee3fca56c9256a69df404782301300a6e5e7f5a25a1f6d68c0e9e42584c9",
"7c423c4a220c6ff43ab6432f92b166323c58ee77f8c096ba0b00d52d7bd507e8",
"0b62b9c1ae4d4988720e8d41d980b334458189de0a3dd01699338d7b07c3894e",
"64f45f6f75110624506c53716f2fc1d5fe5f88f82a5bc6a7459ce70eae56dbb3",
"12ffbeb8e52fed161af4d8a015d1a5c45dcb8240e5c8933ce3a88ba2c58f97e8",
"2ee6b7b96043c8ded9fb52f87cdd0d0580ca6f8cef183c8a656394a11c0aa393",
"aaef26b1f5726258bf9ce305a3e54bca65cf68779f90f9d24287245c27362e27",
"ef59588dce57c35d010bea4d209f44c62f0b7c7e65bc0226c0e4971934da9435",
"0e606c2f6f8dcd579faf4739312bd7327ac7796fa44a81780fe0d66fc7761fb9",
"2f307198afdbde5f95989a17e06ce1bb9ff36c441cf3b2248431534fe13bb9fe",
"51418e6df23d450aaacc74ef2df53a6b1693727b70bda9ebc43acfc23d8fb5ea",
"6e9e3ac46705ed80520695b924435b00d2b3079598bf7faca7fd1524be777e5e",
"1e96241e2876aad29ce64f5d7e7fbb8db7265449df816c0d30a96633778c5cb6",
"81788f00eb72696d811f946e65d2c96528c45590874a1defdd46651e9b79a3a1",
"d9aa5a9f1df50e933d7105a5d72b5fe96bfbb9fd4b5b0eaa5e80af12e72d497a",
"e1b6976a732d27fc5d6a96b6d3d0d1d5eaa6ec46bae4665f17e7a43aefc75280",
"9151c75edcec1cc90aa2d2c240ff657b0eef3f5f1ec37418c8854b2493114f1d",
"3e7c12d0132421f08ea0a390cfa325e422a6b35120fb2eb650f108a165237934",
"1ee0e85c7d8a91089c03f37318cdc9127026bf789e3ce4b75046eaa3eebd3458",
"4ae64a3ef66cad847409ce175bd5365c9097fd21647a05730ac6b45841add3c8",
"f0ea0f334cf1d64678a6dab08c07e2f94f339e8389bd17ebc882b5c8b736cbf2",
"da904db96060546ff69e28993ce8183766da9402ac10fae9fc1f1d67ebd83c90",
"db11820615f7b5e47778c45d2e083e77f49b608b587dc09ec26f077aba07a242",
"ff5c726a83bd785484de75bb03b421f9e8e382bf2740120a2fcf72326aa01c75",
"f8643a7efd6304980db323303ab73a6fd4f4ee1047520d39d571580395b97f21",
"8facf9737d07838aedf6030593bfb247d8c29fe8d9b18b2913408627a4424d7e",
"f0672964aa6e4c7dd4768e18827023787386927f4db89fd661444979afb43c18",
"6fd3649c8401f2704ed2be18518b870eb6bf2b9a6689d1b336f05bd8b49017f6",
"ed172dac7de827493e0c0fdd8d3299333acb678e72ed499e0224b389cc1e0fba",
"7f9a8a8cc8e34add11934a1a5882be5978a6d28405cb0a053ec5699a502b1cef",
"6ca829ebd2a0a40994f68c1db7978ec274b45c46e9b351df869a2bfe0630bbd4",
"0bbb017c437573a55db88258a9d9a01188bdd23bb6b26903b137814871661f47",
"9a6358d2541f46b6d05b80fe25a2cb025fbe9e4b227a6275908d5ee31c948569",
"a75d26c6d4ce944024f10e6d23e8b5b888d680120e15dc0e4fee8d8833ee0c6a",
"1d43d33556699b42c124b46e41243abf48727fe488428056fdd174a3861c1e3c",
"7b5bd3fecbaa093f005c4f806ea67846c0df6b04df7729925cb14724f6a8b582",
"6bdf2b54f2f5ab90191261d33dee80fede75896994016422b28db8ba62327d82",
"1a16181b250085a91ccecc118473fa2ab98515e894a7b63b347c24b5be560c7a",
"22d24891755910b48ad632358c26245bdcc375abc41f7e2c9fb3c7773dbf4e22",
"5b70c5d4a373d541619c944fcc3b61259550b0e9fba3eca16f0879e5845b43b9",
"b78f9098c9d76987b7409e63426a8d49972bb4e75289576c680cf96513d44b6d",
"916b53b8e85eb7e0a2a76d6fc8d2163430e7183ccb103d6705f54af4bb070907",
"dc3d78f43110d2aa9df83c5485ec33663ad5452b8cdeb1aeeac9d6b1487fb781",
"3975539ed5402cb9f5ab503584524dd141cc4296b666ec66d807f94f62b1c026",
"bd1f97fd89183643423073f22733880616456ca41960699f18e868cb9ac35508",
"90b468ff0f83460c3dd8cfe778c39d32c6bb1eeff9ac5de7804a4050d3b8073e",
"0e886d49d88b82c9f8dbdd2f38a535992f35ab16629724d746394db3898235fa",
"76c22e965242d1ca5614e829d9028dcad9c4b09393bcbdd318b0365557335fb9",
"59b168488ec8629f820a1efd8fc5a0c2adec4253e61d6a2945a68a9a43be9035",
"ff172b42854eaf2865caa985d2fb6283c5ab19574126623ffd615a761a5bce72",
"cb46ac9ccc024ee74c96e3cf1c13a6949a432e855dfa881b6a307c0e6daac59e",
"9971574924c0f413bf4c0f96bb9c2fbdfea8f475e33a8fb6f15fa40903b63444",
"1a95567deb0f45a8941e2248f33286485984a5e9d86d16c37d42169ad864dc36",
"205fc7f7ec7a83f0bc22d5269c91762cd00adc7428456d799be5a0cd76f08b0f",
"849dd41ef59a722901b7a0deb2c1fd3c110a91a726120a0a119cb7a15cf98438",
"a32880917c714612101af95e5c8d8eb5fb046fdcc68bae76c05b829b3fa73c2e",
"70b38d6d510d13b359dffa910329952c620a4bce4ee7a8552b9bb3a14572394d",
"ef257ab2f4226faa6ba288a6793f026609068effb866c18496a847e8b60b102d",
"e5196ab42ff53c8352288bde6b6b7312cd6f39f7d21b556b0db178d8470d5790",
"ca98f128bf085f2b718f2b3c12da7c4d98887cc94251a2b1705b637611bd83bb",
"79508f0b93a49ec19c5cb05906ca1ba3d3db8ed4f9c6884873d0d7e3e985ea51",
"9088be3f47f9debc63e928739f7163182b49eab044518b151f0b89f6b6aefdd0",
"46b2782fd669b6288a4d7348cf6671360277ba4864cc69bce3497369ac2ec31e",
"0fa5131557db67b430d516530be939ff25882adf68a076602f3dfad8c77c963a",
"3404302cc097d5457244453a4c9990804201ee8161188df811bcb32404998c71",
"856939710dbb90a8eeda875a31f9a52af759bd932b88e7b08df35414c54d4721",
"72569573b9b41d0ac5ce17764a139c6b8b36ef3ca6d92cec625dbcdae758ba22",
"9746da344e435a008d6acb4847211bb676376ecc76c825b5d44a28b89ceeb40e",
"3eafded1595516f032e33ec975f4c9c3a1055d13aa5575cf8a801d6103fdbeb4",
"e88a6d2daa863c0787cc523a2cab45c546fad788951b10d75e2b0954db24cca7",
"38f531e67f88f66de44d3357c8e8f2db456160ca31dd2024c9562f6afd260278",
};
// block 685498 (13 key images in one transaction)
static const char * const key_images_685498[] =
{
"749b7277aa21c70c417f255fb181c3a30b44277edf657eaaebf28a2709dd2a90",
"5a9b3e1a87332d735cedaa2b5623a6a5e99d99f5a2887c8fc84293577e8bf25c",
"bea438768445eb3650cf619bf6758e94035abfe0ccda91d4a58c582df143d835",
"376e237ff4da5e5cbd6e1bba4b01412fa751f2959c0c57006589f382413df429",
"14ac2f2e044f8635a3a42ecb46c575424073c1f6e5ed5e905f516d57f63184b5",
"2d1d2ecb77b69a2901de00897d0509c1b7855a3b2f8eb1afe419008fc03cd15a",
"ea01658f0972b77ae9112d525ec073e3ec5c3b98d5ad912d95ab2636354b70b6",
"d3934864a46101d8c242415282e7fc9ee73ad16cd40355535d226ab45ecdb61a",
"ee379b05c5d02432330ebd4ea9c4f1c87d14c388568d526a0f8a22649a14e453",
"aeb7b842b410b13ca4af7a5ffd5ae6caddc8bfec653df1b945e478839a2e0057",
"451806929d9f5c3a7f365472703871abadc25b2a5a2d75472a45e86cd76c610b",
"272d9b9fcc9e253c08da9caf8233471150019582eaefef461c1f9ceff7e2c337",
"633cdedeb3b96ec4f234c670254c6f721e0b368d00b48c6b26759db7d62cf52d",
};
if (height() > 202612)
{
for (const auto &kis: key_images_202612)
{
crypto::key_image ki;
epee::string_tools::hex_to_pod(kis, ki);
if (!has_key_image(ki))
{
LOG_PRINT_L1("Fixup: adding missing spent key " << ki);
add_spent_key(ki);
}
}
}
if (height() > 685498)
{
for (const auto &kis: key_images_685498)
{
crypto::key_image ki;
epee::string_tools::hex_to_pod(kis, ki);
if (!has_key_image(ki))
{
LOG_PRINT_L1("Fixup: adding missing spent key " << ki);
add_spent_key(ki);
}
}
}
}
batch_stop();
}
bool BlockchainDB::txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category)

View File

@@ -160,7 +160,7 @@ struct txpool_tx_meta_t
uint64_t max_used_block_height;
uint64_t last_failed_height;
uint64_t receive_time;
uint64_t last_relayed_time;
uint64_t last_relayed_time; //!< If Dandelion++ stem, randomized embargo timestamp. Otherwise, last relayed timestmap.
// 112 bytes
uint8_t kept_by_block;
uint8_t relayed;
@@ -168,13 +168,17 @@ struct txpool_tx_meta_t
uint8_t double_spend_seen: 1;
uint8_t pruned: 1;
uint8_t is_local: 1;
uint8_t bf_padding: 5;
uint8_t dandelionpp_stem : 1;
uint8_t bf_padding: 4;
uint8_t padding[76]; // till 192 bytes
void set_relay_method(relay_method method) noexcept;
relay_method get_relay_method() const noexcept;
//! \return True if `get_relay_method()` now returns `method`.
bool upgrade_relay_method(relay_method method) noexcept;
//! See `relay_category` description
bool matches(const relay_category category) const noexcept
{
@@ -1290,6 +1294,25 @@ public:
*/
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const = 0;
/**
* @brief fetches a variable number of blocks and transactions from the given height, in canonical blockchain order
*
* The subclass should return the blocks and transactions stored from the one with the given
* height. The number of blocks returned is variable, based on the max_size passed.
*
* @param start_height the height of the first block
* @param min_count the minimum number of blocks to return, if they exist
* @param max_count the maximum number of blocks to return
* @param max_size the maximum size of block/transaction data to return (will be exceeded by one blocks's worth at most, if min_count is met)
* @param blocks the returned block/transaction data
* @param pruned whether to return full or pruned tx data
* @param skip_coinbase whether to return or skip coinbase transactions (they're in blocks regardless)
* @param get_miner_tx_hash whether to calculate and return the miner (coinbase) tx hash
*
* @return true iff the blocks and transactions were found
*/
virtual bool get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const = 0;
/**
* @brief fetches the prunable transaction blob with the given hash
*

View File

@@ -786,7 +786,7 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
bi.bi_diff_lo = (cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
bi.bi_hash = blk_hash;
bi.bi_cum_rct = num_rct_outs;
if (blk.major_version >= 4)
if (m_height > 0 && blk.major_version >= 4)
{
uint64_t last_height = m_height-1;
MDB_val_set(h, last_height);
@@ -1323,7 +1323,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
if (is_hdd_result)
{
if (is_hdd_result.value())
MCLOG_RED(el::Level::Warning, "global", "The blockchain is on a rotating drive: this will be very slow, use an SSD if possible");
MCLOG_RED(el::Level::Debug, "global", "The blockchain is on a rotating drive: this will be very slow, use an SSD if possible");
}
m_folder = filename;
@@ -1476,7 +1476,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
mdb_env_close(m_env);
m_open = false;
MFATAL("Existing lmdb database needs to be converted, which cannot be done on a read-only database.");
MFATAL("Please run monerod once to convert the database.");
MFATAL("Please run wownerod once to convert the database.");
return;
}
// Note that there was a schema change within version 0 as well.
@@ -3108,6 +3108,104 @@ bool BlockchainLMDB::get_pruned_tx_blobs_from(const crypto::hash& h, size_t coun
return true;
}
bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX_RDONLY();
RCURSOR(blocks);
RCURSOR(tx_indices);
RCURSOR(txs_pruned);
if (!pruned)
{
RCURSOR(txs_prunable);
}
blocks.reserve(std::min<size_t>(max_count, 10000)); // guard against very large max count if only checking bytes
const uint64_t blockchain_height = height();
uint64_t size = 0;
MDB_val_copy<uint64_t> key(start_height);
MDB_val k, v, val_tx_id;
uint64_t tx_id = ~0;
MDB_cursor_op op = MDB_SET;
for (uint64_t h = start_height; h < blockchain_height && blocks.size() < max_count && (size < max_size || blocks.size() < min_count); ++h)
{
MDB_cursor_op op = h == start_height ? MDB_SET : MDB_NEXT;
int result = mdb_cursor_get(m_cur_blocks, &key, &v, op);
if (result == MDB_NOTFOUND)
throw0(BLOCK_DNE(std::string("Attempt to get block from height ").append(boost::lexical_cast<std::string>(h)).append(" failed -- block not in db").c_str()));
else if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve a block from the db", result).c_str()));
blocks.resize(blocks.size() + 1);
auto &current_block = blocks.back();
current_block.first.first.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
size += v.mv_size;
cryptonote::block b;
if (!parse_and_validate_block_from_blob(current_block.first.first, b))
throw0(DB_ERROR("Invalid block"));
current_block.first.second = get_miner_tx_hash ? cryptonote::get_transaction_hash(b.miner_tx) : crypto::null_hash;
// get the tx_id for the first tx (the first block's coinbase tx)
if (h == start_height)
{
crypto::hash hash = cryptonote::get_transaction_hash(b.miner_tx);
MDB_val_set(v, hash);
result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve block coinbase transaction from the db: ", result).c_str()));
const txindex *tip = (const txindex *)v.mv_data;
tx_id = tip->data.tx_id;
val_tx_id.mv_data = &tx_id;
val_tx_id.mv_size = sizeof(tx_id);
}
if (skip_coinbase)
{
result = mdb_cursor_get(m_cur_txs_pruned, &val_tx_id, &v, op);
if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve transaction data from the db: ", result).c_str()));
if (!pruned)
{
result = mdb_cursor_get(m_cur_txs_prunable, &val_tx_id, &v, op);
if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve transaction data from the db: ", result).c_str()));
}
}
op = MDB_NEXT;
current_block.second.reserve(b.tx_hashes.size());
for (const auto &tx_hash: b.tx_hashes)
{
// get pruned data
cryptonote::blobdata tx_blob;
result = mdb_cursor_get(m_cur_txs_pruned, &val_tx_id, &v, op);
if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve transaction data from the db: ", result).c_str()));
tx_blob.assign((const char*)v.mv_data, v.mv_size);
if (!pruned)
{
result = mdb_cursor_get(m_cur_txs_prunable, &val_tx_id, &v, op);
if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve transaction data from the db: ", result).c_str()));
tx_blob.append(reinterpret_cast<const char*>(v.mv_data), v.mv_size);
}
current_block.second.push_back(std::make_pair(tx_hash, std::move(tx_blob)));
size += current_block.second.back().second.size();
}
}
TXN_POSTFIX_RDONLY();
return true;
}
bool BlockchainLMDB::get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -3950,7 +4048,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial) const
{
if (amounts.size() != 1 && amounts.size() != offsets.size())
throw0(DB_ERROR("Invalid sizes of amounts and offets"));
throw0(DB_ERROR("Invalid sizes of amounts and offsets"));
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
TIME_MEASURE_START(db3);

View File

@@ -255,6 +255,7 @@ public:
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const;
virtual bool get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const;
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const;

View File

@@ -70,6 +70,7 @@ public:
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const { return false; }
virtual bool get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const { return false; }
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const override { return false; }
virtual uint64_t get_block_height(const crypto::hash& h) const override { return 0; }

View File

@@ -157,7 +157,7 @@ endif()
set_property(TARGET blockchain_import
PROPERTY
OUTPUT_NAME "monero-blockchain-import")
OUTPUT_NAME "wownero-blockchain-import")
install(TARGETS blockchain_import DESTINATION bin)
monero_add_executable(blockchain_export
@@ -178,7 +178,7 @@ target_link_libraries(blockchain_export
set_property(TARGET blockchain_export
PROPERTY
OUTPUT_NAME "monero-blockchain-export")
OUTPUT_NAME "wownero-blockchain-export")
install(TARGETS blockchain_export DESTINATION bin)
monero_add_executable(blockchain_blackball
@@ -200,7 +200,7 @@ target_link_libraries(blockchain_blackball
set_property(TARGET blockchain_blackball
PROPERTY
OUTPUT_NAME "monero-blockchain-mark-spent-outputs")
OUTPUT_NAME "wownero-blockchain-mark-spent-outputs")
install(TARGETS blockchain_blackball DESTINATION bin)
@@ -222,7 +222,7 @@ target_link_libraries(blockchain_usage
set_property(TARGET blockchain_usage
PROPERTY
OUTPUT_NAME "monero-blockchain-usage")
OUTPUT_NAME "wownero-blockchain-usage")
install(TARGETS blockchain_usage DESTINATION bin)
monero_add_executable(blockchain_ancestry
@@ -243,7 +243,7 @@ target_link_libraries(blockchain_ancestry
set_property(TARGET blockchain_ancestry
PROPERTY
OUTPUT_NAME "monero-blockchain-ancestry")
OUTPUT_NAME "wownero-blockchain-ancestry")
install(TARGETS blockchain_ancestry DESTINATION bin)
monero_add_executable(blockchain_depth
@@ -264,7 +264,7 @@ target_link_libraries(blockchain_depth
set_property(TARGET blockchain_depth
PROPERTY
OUTPUT_NAME "monero-blockchain-depth")
OUTPUT_NAME "wownero-blockchain-depth")
install(TARGETS blockchain_depth DESTINATION bin)
monero_add_executable(blockchain_stats
@@ -285,7 +285,7 @@ target_link_libraries(blockchain_stats
set_property(TARGET blockchain_stats
PROPERTY
OUTPUT_NAME "monero-blockchain-stats")
OUTPUT_NAME "wownero-blockchain-stats")
install(TARGETS blockchain_stats DESTINATION bin)
monero_add_executable(blockchain_prune_known_spent_data
@@ -307,7 +307,7 @@ target_link_libraries(blockchain_prune_known_spent_data
set_property(TARGET blockchain_prune_known_spent_data
PROPERTY
OUTPUT_NAME "monero-blockchain-prune-known-spent-data")
OUTPUT_NAME "wownero-blockchain-prune-known-spent-data")
install(TARGETS blockchain_prune_known_spent_data DESTINATION bin)
monero_add_executable(blockchain_prune
@@ -316,7 +316,7 @@ monero_add_executable(blockchain_prune
set_property(TARGET blockchain_prune
PROPERTY
OUTPUT_NAME "monero-blockchain-prune")
OUTPUT_NAME "wownero-blockchain-prune")
install(TARGETS blockchain_prune DESTINATION bin)
target_link_libraries(blockchain_prune

View File

@@ -385,12 +385,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-ancestry.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-ancestry.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -136,7 +136,7 @@ static std::string get_default_db_path()
boost::filesystem::path dir = tools::get_default_data_dir();
// remove .bitmonero, replace with .shared-ringdb
dir = dir.remove_filename();
dir /= ".shared-ringdb";
dir /= ".wow-shared-ringdb";
return dir.string();
}
@@ -1185,7 +1185,7 @@ int main(int argc, char* argv[])
const command_line::arg_descriptor<bool> arg_rct_only = {"rct-only", "Only work on ringCT outputs", false};
const command_line::arg_descriptor<bool> arg_check_subsets = {"check-subsets", "Check ring subsets (very expensive)", false};
const command_line::arg_descriptor<bool> arg_verbose = {"verbose", "Verbose output)", false};
const command_line::arg_descriptor<std::vector<std::string> > arg_inputs = {"inputs", "Path to Monero DB, and path to any fork DBs"};
const command_line::arg_descriptor<std::vector<std::string> > arg_inputs = {"inputs", "Path to Wownero DB, and path to any fork DBs"};
const command_line::arg_descriptor<std::string> arg_db_sync_mode = {
"db-sync-mode"
, "Specify sync option, using format [safe|fast|fastest]:[nrecords_per_sync]."
@@ -1228,12 +1228,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-mark-spent-outputs.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-mark-spent-outputs.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -87,12 +87,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-depth.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-depth.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -87,12 +87,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-export.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-export.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -629,7 +629,7 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
@@ -666,7 +666,7 @@ int main(int argc, char* argv[])
}
m_config_folder = command_line::get_arg(vm, cryptonote::arg_data_dir);
mlog_configure(mlog_get_default_log_path("monero-blockchain-import.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-import.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -480,12 +480,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-prune.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-prune.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -137,12 +137,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-prune-known-spent-data.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-prune-known-spent-data.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -97,12 +97,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-stats.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-stats.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -119,12 +119,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-usage.log"), true);
mlog_configure(mlog_get_default_log_path("wownero-blockchain-usage.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else

View File

@@ -43,7 +43,6 @@
#include <algorithm>
#include <cstdio>
#include <fstream>
#include <boost/iostreams/copy.hpp>
#include <atomic>
#include "common/command_line.h"

View File

@@ -41,7 +41,6 @@
#include <algorithm>
#include <cstdio>
#include <fstream>
#include <boost/iostreams/copy.hpp>
#include <atomic>
#include "common/command_line.h"

Binary file not shown.

View File

@@ -34,6 +34,7 @@
#include "string_tools.h"
#include "storages/portable_storage_template_helper.h" // epee json include
#include "serialization/keyvalue_serialization.h"
#include <functional>
#include <vector>
using namespace epee;
@@ -133,11 +134,9 @@ namespace cryptonote
//---------------------------------------------------------------------------
uint64_t checkpoints::get_max_height() const
{
std::map< uint64_t, crypto::hash >::const_iterator highest =
std::max_element( m_points.begin(), m_points.end(),
( boost::bind(&std::map< uint64_t, crypto::hash >::value_type::first, _1) <
boost::bind(&std::map< uint64_t, crypto::hash >::value_type::first, _2 ) ) );
return highest->first;
if (m_points.empty())
return 0;
return m_points.rbegin()->first;
}
//---------------------------------------------------------------------------
const std::map<uint64_t, crypto::hash>& checkpoints::get_points() const
@@ -161,56 +160,73 @@ namespace cryptonote
{
if (nettype == TESTNET)
{
ADD_CHECKPOINT(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b");
ADD_CHECKPOINT(1000000, "46b690b710a07ea051bc4a6b6842ac37be691089c0f7758cfeec4d5fc0b4a258");
ADD_CHECKPOINT(1058600, "12904f6b4d9e60fd875674e07147d2c83d6716253f046af7b894c3e81da7e1bd");
return true;
}
if (nettype == STAGENET)
{
ADD_CHECKPOINT(0, "76ee3cc98646292206cd3e86f74d88b4dcc1d937088645e9b0cbca84b7ce74eb");
ADD_CHECKPOINT(10000, "1f8b0ce313f8b9ba9a46108bfd285c45ad7c2176871fd41c3a690d4830ce2fd5");
return true;
}
ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148");
ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381");
ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d");
ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876");
ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2");
ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25");
ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6");
ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c");
ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3");
ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698");
ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2");
ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb");
ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063");
ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553");
ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61");
ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf");
ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131");
ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8");
ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d");
ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831");
ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02");
ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5");
ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd");
ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60");
ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337");
ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f");
ADD_CHECKPOINT(1000000, "a886ef5149902d8342475fee9bb296341b891ac67c4842f47a833f23c00ed721");
ADD_CHECKPOINT(1100000, "3fd720c5c8b3072fc1ccda922dec1ef25f9ed88a1e6ad4103d0fe00b180a5903");
ADD_CHECKPOINT(1150000, "1dd16f626d18e1e988490dfd06de5920e22629c972c58b4d8daddea0038627b2");
ADD_CHECKPOINT(1200000, "fa7d13a90850882060479d100141ff84286599ae39c3277c8ea784393f882d1f");
ADD_CHECKPOINT(1300000, "31b34272343a44a9f4ac7de7a8fcf3b7d8a3124d7d6870affd510d2f37e74cd0");
ADD_CHECKPOINT(1390000, "a8f5649dd4ded60eedab475f2bec8c934681c07e3cf640e9be0617554f13ff6c");
ADD_CHECKPOINT(1450000, "ac94e8860093bc7c83e4e91215cba1d663421ecf4067a0ae609c3a8b52bcfac2");
ADD_CHECKPOINT(1530000, "01759bce497ec38e63c78b1038892169203bb78f87e488172f6b854fcd63ba7e");
ADD_CHECKPOINT(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241");
ADD_CHECKPOINT(1668900, "ac2dcaf3d2f58ffcf8391639f0f1ebafcb8eac43c49479c7c37f611868d07568");
ADD_CHECKPOINT(1775600, "1c6e01c661dc22cab939e79ec6a5272190624ce8356d2f7b958e4f9a57fdb05e");
ADD_CHECKPOINT(1856000, "9b57f17f29c71a3acd8a7904b93c41fa6eb8d2b7c73936ce4f1702d14880ba29");
ADD_CHECKPOINT(1958000, "98a5d6e51afdf3146e0eefb10a66e8648d8d4d5c2742be8835e976ba217c9bb2");
ADD_CHECKPOINT(1, "97f4ce4d7879b3bea54dcec738cd2ebb7952b4e9bb9743262310cd5fec749340");
ADD_CHECKPOINT(10, "305472c87ff86d8afb3ec42634828462b0ed3d929fc05fa1ae668c3bee04837a");
ADD_CHECKPOINT(100, "a92b9deae26e19322041cbc2f850fa905748ae1e5bf69b35ca90b247c5cbfc04");
ADD_CHECKPOINT(1000, "62921e13030b29264439cafaf8320cf8aa039ee6ba7ba29c72f11b50a079269a");
ADD_CHECKPOINT(2000, "b3e1d73e3d0243239481aa76cb075cf2428556f5dc4f2e30428ea2ba36693e97");
ADD_CHECKPOINT(3000, "83a6e1ab394e80b8442b7b70b0e4c3a9fa0143e0ca51a33e829537ef5dd1bf13");
ADD_CHECKPOINT(4000, "7c70722d8cb8106b4bec67e1790614cc6e98db7afd0843b96cdff6960a0e0073");
ADD_CHECKPOINT(5000, "331ee74008e174e5fd1956f64c52793961b321a1366f7c6f7d324e8265df34f6");
ADD_CHECKPOINT(6969, "aa7b66e8c461065139b55c29538a39c33ceda93e587f84d490ed573d80511c87"); //Hard fork to v8
ADD_CHECKPOINT(7000, "2711bd33b107f744ad8bf98c1acefa18658780079496bd2f3a36f2e20b261f8e");
ADD_CHECKPOINT(7500, "5975967c4624f13f058acafe7adf9355e03e8e802eeadc84ccb22ea588bc0762");
ADD_CHECKPOINT(7900, "d9bc18cb35feb6b26bc5a19bbdbf7c852d9cc02883acb5bbce2e87d8b2c86069");
ADD_CHECKPOINT(10000, "bc5bfbf1b26c8f976d1d792ece4c6a7e93064bec62b72f1d5beae74c3f273b3b");
ADD_CHECKPOINT(20000, "52cc7edcb49eb02f28a653b824089a726f4050eb210263ee6f4180d388a1e5cc");
ADD_CHECKPOINT(30000, "d22fde5dd240ade16d3250eb0aa5d1c16dc7cb51c20484e05eb274911032b3fa");
ADD_CHECKPOINT(40000, "aee0d642322542ba069cb1c58ab2acd3560f108d4682c3dc3cb15a54d442d91f");
ADD_CHECKPOINT(50000, "5286ac2a0f39b3aefcba363cd71f2760bd1e0d763cbc81026ebdc3f80a86541f");
ADD_CHECKPOINT(53666, "3f43f56f66ef0c43cf2fd14d0d28fa2aae0ef8f40716773511345750770f1255"); //Hard fork to v9
ADD_CHECKPOINT(54500, "8ed3078b389c2b44add007803d741b58d3fbed2e1ba4139bda702152d8773c9b");
ADD_CHECKPOINT(55000, "4b662ceccefc3247edb4d654dd610b8fb496e85b88a5de43cc2bdd28171b15ff");
ADD_CHECKPOINT(57000, "08a79f09f12bb5d230b63963356a760d51618e526cfc636047a6f3798217c177");
ADD_CHECKPOINT(59000, "180b51ee2c5fbcd4362eb7a29df9422481310dd77d10bccdf8930724c31e007e");
ADD_CHECKPOINT(59900, "18cc0653ef39cb304c68045dba5eb6b885f936281cd939dea04d0e6c9cd4ae2e");
ADD_CHECKPOINT(60000, "0f02aa57a63f79f63dafed9063abe228a37cb19f00430dc3168b8a8f4ae8016c");
ADD_CHECKPOINT(61000, "509aca8c54eb5fe44623768757b6e890ae39d512478c75f614cbff3d91809350");
ADD_CHECKPOINT(62000, "7fe91ad256c08dbd961e04738968be22fb481093fbfa7959bde7796ccceba0e2");
ADD_CHECKPOINT(62150, "1a7c75f8ebeda0e20eb5877181eafd7db0fc887e3fed43e0b27ab2e7bccafd10");
ADD_CHECKPOINT(62269, "4969555d60742afb93925fd96d83ac28f45e6e3c0e583c9fb3c92d9b2100d38f");
ADD_CHECKPOINT(62405, "4d0ae890cf9f875f231c7069508ad28dc429d14814b52db114dfab7519a27584");
ADD_CHECKPOINT(62419, "bd8bf5ac4c4fb07ab4d0d492bd1699def5c095ab6943ad3b63a89d1d8b1ce748");
ADD_CHECKPOINT(62425, "41a922dba6f3906871b2ccaf31ec9c91033470c503959093dae796deda8940ea");
ADD_CHECKPOINT(62479, "a2e8ff4205ba2980eb70921b0b21b5fc656ee273664ea94b860c68ca069b60dd");
ADD_CHECKPOINT(62503, "25fa115962988b4b8f8cfd22744a3e653b22ead8c8468e64caf334fc75a97d08");
ADD_CHECKPOINT(62550, "bde522a8a81c392c98c979434aa1dd9d20b4ca52230ba6ae0362872757808a48");
ADD_CHECKPOINT(62629, "8368e1ce1d421f1fc969364558433e2b2363d0ffcb5f2d946633095e3e6734f5");
ADD_CHECKPOINT(62720, "f871cddd75951e2fe24c282d2bd28396fc922ea519b354ace992a0162cb333ff");
ADD_CHECKPOINT(62733, "8331dbeeaf23173d2235a062373a437befadb6492cceb7640127bf18653a9e61");
ADD_CHECKPOINT(62877, "62d44adc05d7d4fd9d15239c5575612207beab0bcf2da49158bf89e365441ca1");
ADD_CHECKPOINT(63469, "4e33a9343fc5b86661ec0affaeb5b5a065290602c02d817337e4a979fe5747d8"); //Hard fork to v10
ADD_CHECKPOINT(69800, "5c65428a664738bc083d1ccd6a1b5ff4305f98e7633f44033816801429b33ce1");
ADD_CHECKPOINT(75000, "e93492f79b5344e7edb31537ee65b3e908bf71110cff8188c0c62fefc015d342");
ADD_CHECKPOINT(79500, "9bbfd6f2257ce9084de30179944b7695c9b918c9c03a8a63306ab6c5828ff857");
ADD_CHECKPOINT(80920, "8fca818344f97ea3912557cbd8be659cf6a5bc1203514c27338e234251d72dfb");
ADD_CHECKPOINT(81769, "41db9fef8d0ccfa78b570ee9525d4f55de77b510c3ae4b08a1d51b9aec9ade1d"); //Hard fork to v11
ADD_CHECKPOINT(82069, "fdea800d23d0b2eea19dec8af31e453e883e8315c97e25c8bb3e88ca164f8369"); //Hard fork to v12
ADD_CHECKPOINT(85000, "31d62ab75470b15aedee6674b78767b53f10951786e991c26035743c267b247a");
ADD_CHECKPOINT(87000, "a788e5a7233ca2198ad6446ddc454b05d578e72253ed2bbca969527230f6eec2");
ADD_CHECKPOINT(88200, "50bb43d5d563524d6b9f308a2483b80934bab2ab5250757558318834476f1cfb");
ADD_CHECKPOINT(100000, "0c1f3bec32fe4ac9bd4b6ce1f4dfc52824f0947d756c9a1a453252c9423071f5");
ADD_CHECKPOINT(111450, "d6eadc95607765b36afd8b9148eac20eb101632021348cd34371fc1d8b67f6b6");
ADD_CHECKPOINT(114969, "b48245956b87f243048fd61021f4b3e5443e57eee7ff8ba4762d18926e80b80c"); //Hard fork to v13
ADD_CHECKPOINT(114980, "3a96963b93154889bd7d59c8a60cf8005e864b930627616e51a4ad11cd9a3d50");
ADD_CHECKPOINT(115257, "338e056551087fe23d6c4b4280244bc5362b004716d85ec799a775f190f9fea9"); //Hard fork to v14
ADD_CHECKPOINT(118500, "2ef1cd0c68f1b8e1acf384109431b6377dbdbd6705964be17b7358c47ea07447");
ADD_CHECKPOINT(157400, "44445d1fcc845b4d6f8e7730c50af64c09031003d584cdeaa04d6523e0acc049");
ADD_CHECKPOINT(160777, "9496690579af21f38f00e67e11c2e85a15912fe4f412aad33d1162be1579e755"); //Hard fork to v15
ADD_CHECKPOINT(194444, "0aa7ea6ade2ee8f5a525a079c53888fac415826ee8d1e8c92caa52629773db35");
ADD_CHECKPOINT(200500, "1e5c7af11e19a94f334576d79fe0179ff493ce378701f3f810b674db2760c228");
ADD_CHECKPOINT(211300, "f712b6dc0dfe896d18c5ca9097144d05ef8810b11277663638c0963d96ea172c");
ADD_CHECKPOINT(223800, "878d805ce24368a48c4bd36283f3c53510e86b09511ec6770fbaca8f1fd3c55b");
return true;
}
@@ -255,22 +271,13 @@ namespace cryptonote
std::vector<std::string> records;
// All four MoneroPulse domains have DNSSEC on and valid
static const std::vector<std::string> dns_urls = { "checkpoints.moneropulse.se"
, "checkpoints.moneropulse.org"
, "checkpoints.moneropulse.net"
, "checkpoints.moneropulse.co"
static const std::vector<std::string> dns_urls = {
};
static const std::vector<std::string> testnet_dns_urls = { "testpoints.moneropulse.se"
, "testpoints.moneropulse.org"
, "testpoints.moneropulse.net"
, "testpoints.moneropulse.co"
static const std::vector<std::string> testnet_dns_urls = {
};
static const std::vector<std::string> stagenet_dns_urls = { "stagenetpoints.moneropulse.se"
, "stagenetpoints.moneropulse.org"
, "stagenetpoints.moneropulse.net"
, "stagenetpoints.moneropulse.co"
static const std::vector<std::string> stagenet_dns_urls = {
};
if (!tools::dns_utils::load_txt_records_from_dns(records, nettype == TESTNET ? testnet_dns_urls : nettype == STAGENET ? stagenet_dns_urls : dns_urls))

View File

@@ -86,7 +86,8 @@ set(common_private_headers
updates.h
aligned.h
timings.h
combinator.h)
combinator.h
utf8.h)
monero_private_headers(common
${common_private_headers})

View File

@@ -101,8 +101,6 @@ get_builtin_ds(void)
{
static const char * const ds[] =
{
". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n",
". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n",
NULL
};
return ds;

View File

@@ -46,10 +46,6 @@ namespace tools
// All four MoneroPulse domains have DNSSEC on and valid
static const std::vector<std::string> dns_urls = {
"updates.moneropulse.org",
"updates.moneropulse.net",
"updates.moneropulse.co",
"updates.moneropulse.se"
};
if (!tools::dns_utils::load_txt_records_from_dns(records, dns_urls))
@@ -99,7 +95,7 @@ namespace tools
std::string get_update_url(const std::string &software, const std::string &subdir, const std::string &buildtag, const std::string &version, bool user)
{
const char *base = user ? "https://downloads.getmonero.org/" : "https://updates.getmonero.org/";
const char *base = user ? "" : "";
#ifdef _WIN32
static const char *extension = strncmp(buildtag.c_str(), "source", 6) ? (strncmp(buildtag.c_str(), "install-", 8) ? ".zip" : ".exe") : ".tar.bz2";
#else

114
src/common/utf8.h Normal file
View File

@@ -0,0 +1,114 @@
// Copyright (c) 2019, 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 <cctype>
#include <cwchar>
#include <stdexcept>
namespace tools
{
template<typename T, typename Transform>
inline T utf8canonical(const T &s, Transform t = [](wint_t c)->wint_t { return c; })
{
T sc = "";
size_t avail = s.size();
const char *ptr = s.data();
wint_t cp = 0;
int bytes = 1;
char wbuf[8], *wptr;
while (avail--)
{
if ((*ptr & 0x80) == 0)
{
cp = *ptr++;
bytes = 1;
}
else if ((*ptr & 0xe0) == 0xc0)
{
if (avail < 1)
throw std::runtime_error("Invalid UTF-8");
cp = (*ptr++ & 0x1f) << 6;
cp |= *ptr++ & 0x3f;
--avail;
bytes = 2;
}
else if ((*ptr & 0xf0) == 0xe0)
{
if (avail < 2)
throw std::runtime_error("Invalid UTF-8");
cp = (*ptr++ & 0xf) << 12;
cp |= (*ptr++ & 0x3f) << 6;
cp |= *ptr++ & 0x3f;
avail -= 2;
bytes = 3;
}
else if ((*ptr & 0xf8) == 0xf0)
{
if (avail < 3)
throw std::runtime_error("Invalid UTF-8");
cp = (*ptr++ & 0x7) << 18;
cp |= (*ptr++ & 0x3f) << 12;
cp |= (*ptr++ & 0x3f) << 6;
cp |= *ptr++ & 0x3f;
avail -= 3;
bytes = 4;
}
else
throw std::runtime_error("Invalid UTF-8");
cp = t(cp);
if (cp <= 0x7f)
bytes = 1;
else if (cp <= 0x7ff)
bytes = 2;
else if (cp <= 0xffff)
bytes = 3;
else if (cp <= 0x10ffff)
bytes = 4;
else
throw std::runtime_error("Invalid code point UTF-8 transformation");
wptr = wbuf;
switch (bytes)
{
case 1: *wptr++ = cp; break;
case 2: *wptr++ = 0xc0 | (cp >> 6); *wptr++ = 0x80 | (cp & 0x3f); break;
case 3: *wptr++ = 0xe0 | (cp >> 12); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
case 4: *wptr++ = 0xf0 | (cp >> 18); *wptr++ = 0x80 | ((cp >> 12) & 0x3f); *wptr++ = 0x80 | ((cp >> 6) & 0x3f); *wptr++ = 0x80 | (cp & 0x3f); break;
default: throw std::runtime_error("Invalid UTF-8");
}
*wptr = 0;
sc.append(wbuf, bytes);
cp = 0;
bytes = 1;
}
return sc;
}
}

View File

@@ -66,7 +66,6 @@ using namespace epee;
#include "util.h"
#include "stack_trace.h"
#include "memwipe.h"
#include "cryptonote_config.h"
#include "net/http_client.h" // epee::net_utils::...
#include "readline_buffer.h"
@@ -1074,16 +1073,33 @@ std::string get_nix_version_display_string()
{
if (seconds < 60)
return std::to_string(seconds) + " seconds";
std::stringstream ss;
ss << std::fixed << std::setprecision(1);
if (seconds < 3600)
return std::to_string((uint64_t)(seconds / 60)) + " minutes";
{
ss << seconds / 60.f;
return ss.str() + " minutes";
}
if (seconds < 3600 * 24)
return std::to_string((uint64_t)(seconds / 3600)) + " hours";
if (seconds < 3600 * 24 * 30.5)
return std::to_string((uint64_t)(seconds / (3600 * 24))) + " days";
if (seconds < 3600 * 24 * 365.25)
return std::to_string((uint64_t)(seconds / (3600 * 24 * 30.5))) + " months";
if (seconds < 3600 * 24 * 365.25 * 100)
return std::to_string((uint64_t)(seconds / (3600 * 24 * 30.5 * 365.25))) + " years";
{
ss << seconds / 3600.f;
return ss.str() + " hours";
}
if (seconds < 3600 * 24 * 30.5f)
{
ss << seconds / (3600 * 24.f);
return ss.str() + " days";
}
if (seconds < 3600 * 24 * 365.25f)
{
ss << seconds / (3600 * 24 * 30.5f);
return ss.str() + " months";
}
if (seconds < 3600 * 24 * 365.25f * 100)
{
ss << seconds / (3600 * 24 * 365.25f);
return ss.str() + " years";
}
return "a long time";
}
@@ -1279,6 +1295,86 @@ std::string get_nix_version_display_string()
return lines;
}
// Calculate a "sync weight" over ranges of blocks in the blockchain, suitable for
// calculating sync time estimates
uint64_t cumulative_block_sync_weight(cryptonote::network_type nettype, uint64_t start_block, uint64_t num_blocks)
{
if (nettype != cryptonote::MAINNET)
{
// No detailed data available except for Mainnet: Give back the number of blocks
// as a very simple and non-varying block sync weight for ranges of Testnet and
// Stagenet blocks
return num_blocks;
}
// The following is a table of average blocks sizes in bytes over the Monero mainnet
// blockchain, where the block size is averaged over ranges of 10,000 blocks
// (about 2 weeks worth of blocks each).
// The first array entry of 442 thus means "The average byte size of the blocks
// 0 .. 9,999 is 442". The info "block_size" from the "get_block_header_by_height"
// RPC call was used for calculating this. This table (and the whole mechanism
// of calculating a "sync weight") is most important when estimating times for
// syncing from scratch. Without it the fast progress through the (in comparison)
// rather small blocks in the early blockchain) would lead to vastly underestimated
// total sync times.
// It's no big problem for estimates that this table will, over time, and if not
// updated, miss larger and larger parts at the top of the blockchain, as long
// as block size averages there do not differ wildly.
// Without time-consuming tests it's hard to say how much the estimates would
// improve if one would not only take block sizes into account, but also varying
// verification times i.e. the different CPU effort needed for the different
// transaction types (pre / post RingCT, pre / post Bulletproofs).
// Testnet and Stagenet are neglected here because of their much smaller
// importance.
static const uint32_t average_block_sizes[] =
{
442, 1211, 1445, 1763, 2272, 8217, 5603, 9999, 16358, 10805, 5290, 4362,
4325, 5584, 4515, 5008, 4789, 5196, 7660, 3829, 6034, 2925, 3762, 2545,
2437, 2553, 2167, 2761, 2015, 1969, 2350, 1731, 2367, 2078, 2026, 3518,
2214, 1908, 1780, 1640, 1976, 1647, 1921, 1716, 1895, 2150, 2419, 2451,
2147, 2327, 2251, 1644, 1750, 1481, 1570, 1524, 1562, 1668, 1386, 1494,
1637, 1880, 1431, 1472, 1637, 1363, 1762, 1597, 1999, 1564, 1341, 1388,
1530, 1476, 1617, 1488, 1368, 1906, 1403, 1695, 1535, 1598, 1318, 1234,
1358, 1406, 1698, 1554, 1591, 1758, 1426, 2389, 1946, 1533, 1308, 2701,
1525, 1653, 3580, 1889, 2913, 8164, 5154, 3762, 3356, 4360, 3589, 4844,
4232, 3781, 3882, 5924, 10790, 7185, 7442, 8214, 8509, 7484, 6939, 7391,
8210, 15572, 39680, 44810, 53873, 54639, 68227, 63428, 62386, 68504,
83073, 103858, 117573, 98089, 96793, 102337, 94714, 129568, 251584,
132026, 94579, 94516, 95722, 106495, 121824, 153983, 162338, 136608,
137104, 109872, 91114, 84757, 96339, 74251, 94314, 143216, 155837,
129968, 120201, 109913, 101588, 97332, 104611, 95310, 93419, 113345,
100743, 92152, 57565, 22533, 37564, 21823, 19980, 18277, 18402, 14344,
12142, 15842, 13677, 17631, 18294, 22270, 41422, 39296, 36688, 33512,
33831, 27582, 22276, 27516, 27317, 25505, 24426, 20566, 23045, 26766,
28185, 26169, 27011,
28642 // Blocks 1,990,000 to 1,999,999 in December 2019
};
const uint64_t block_range_size = 10000;
uint64_t num_block_sizes = sizeof(average_block_sizes) / sizeof(average_block_sizes[0]);
uint64_t weight = 0;
uint64_t table_index = start_block / block_range_size;
for (;;) {
if (num_blocks == 0)
{
break;
}
if (table_index >= num_block_sizes)
{
// Take all blocks beyond our table as having the size of the blocks
// in the last table entry i.e. in the most recent known block range
weight += num_blocks * average_block_sizes[num_block_sizes - 1];
break;
}
uint64_t portion_size = std::min(num_blocks, block_range_size - start_block % block_range_size);
weight += portion_size * average_block_sizes[table_index];
table_index++;
num_blocks -= portion_size;
start_block += portion_size;
}
return weight;
}
std::vector<std::pair<std::string, size_t>> split_string_by_width(const std::string &s, size_t columns)
{
std::vector<std::string> lines;

View File

@@ -46,6 +46,7 @@
#endif
#include "crypto/hash.h"
#include "cryptonote_config.h"
/*! \brief Various Tools
*
@@ -252,4 +253,6 @@ namespace tools
void clear_screen();
std::vector<std::pair<std::string, size_t>> split_string_by_width(const std::string &s, size_t columns);
uint64_t cumulative_block_sync_weight(cryptonote::network_type nettype, uint64_t start_block, uint64_t num_blocks);
}

View File

@@ -42,6 +42,7 @@ set(crypto_sources
hmac-keccak.c
jh.c
keccak.c
sha3.c
oaes_lib.c
random.c
skein.c

View File

@@ -294,6 +294,7 @@ namespace crypto {
sc_mulsub(&sig.r, &sig.c, &unwrap(sec), &k);
if (!sc_isnonzero((const unsigned char*)sig.r.data))
goto try_again;
memwipe(&k, sizeof(k));
}
bool crypto_ops::check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
@@ -390,6 +391,8 @@ namespace crypto {
// sig.r = k - sig.c*r
sc_mulsub(&sig.r, &sig.c, &unwrap(r), &k);
memwipe(&k, sizeof(k));
}
bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
@@ -560,6 +563,7 @@ POP_WARNINGS
random_scalar(sig[i].c);
random_scalar(sig[i].r);
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
memwipe(&k, sizeof(k));
local_abort("invalid pubkey");
}
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
@@ -573,6 +577,8 @@ POP_WARNINGS
hash_to_scalar(buf.get(), rs_comm_size(pubs_count), h);
sc_sub(&sig[sec_index].c, &h, &sum);
sc_mulsub(&sig[sec_index].r, &sig[sec_index].c, &unwrap(sec), &k);
memwipe(&k, sizeof(k));
}
bool crypto_ops::check_ring_signature(const hash &prefix_hash, const key_image &image,

70
src/crypto/duration.h Normal file
View File

@@ -0,0 +1,70 @@
// Copyright (c) 2020, 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 <chrono>
#include "crypto/crypto.h"
namespace crypto
{
//! Generate poisson distributed values in discrete `D` time units.
template<typename D>
struct random_poisson_duration
{
using result_type = D; //!< std::chrono::duration time unit precision
using rep = typename result_type::rep; //!< Type used to represent duration value
//! \param average for generated durations
explicit random_poisson_duration(result_type average)
: dist(average.count() < 0 ? 0 : average.count())
{}
//! Generate a crypto-secure random duration
result_type operator()()
{
crypto::random_device rand{};
return result_type{dist(rand)};
}
private:
std::poisson_distribution<rep> dist;
};
/* A custom duration is used for subsecond precision because of the
variance. If 5000 milliseconds is given, 95% of the values fall between
4859ms-5141ms in 1ms increments (not enough time variance). Providing 1/4
seconds would yield 95% of the values between 3s-7.25s in 1/4s
increments. */
//! Generate random durations with 1 second precision
using random_poisson_seconds = random_poisson_duration<std::chrono::seconds>;
//! Generate random duration with 1/4 second precision
using random_poisson_subseconds =
random_poisson_duration<std::chrono::duration<std::chrono::milliseconds::rep, std::ratio<1, 4>>>;
}

View File

@@ -85,10 +85,11 @@ void hash_extra_blake(const void *data, size_t length, char *hash);
void hash_extra_groestl(const void *data, size_t length, char *hash);
void hash_extra_jh(const void *data, size_t length, char *hash);
void hash_extra_skein(const void *data, size_t length, char *hash);
void sha3(const void *data, size_t length, char *hash);
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash);
#define RX_BLOCK_VERSION 12
#define RX_BLOCK_VERSION 13
void rx_slow_hash_allocate_state(void);
void rx_slow_hash_free_state(void);
uint64_t rx_seedheight(const uint64_t height);

View File

@@ -73,6 +73,10 @@ namespace crypto {
inline void cn_slow_hash(const void *data, std::size_t length, hash &hash, int variant = 0, uint64_t height = 0) {
cn_slow_hash(data, length, reinterpret_cast<char *>(&hash), variant, 0/*prehashed*/, height);
}
inline void sha3(const void *data, std::size_t length, hash &hash) {
sha3(data, length, reinterpret_cast<char *>(&hash));
}
inline void cn_slow_hash_prehashed(const void *data, std::size_t length, hash &hash, int variant = 0, uint64_t height = 0) {
cn_slow_hash(data, length, reinterpret_cast<char *>(&hash), variant, 1/*prehashed*/, height);

View File

@@ -161,11 +161,11 @@ static void rx_initdata(randomx_cache *rs_cache, const int miners, const uint64_
CTHR_THREAD_TYPE *st;
si = malloc(miners * sizeof(seedinfo));
if (si == NULL)
local_abort("Couldn't allocate RandomX mining threadinfo");
local_abort("Couldn't allocate RandomWOW mining threadinfo");
st = malloc(miners * sizeof(CTHR_THREAD_TYPE));
if (st == NULL) {
free(si);
local_abort("Couldn't allocate RandomX mining threadlist");
local_abort("Couldn't allocate RandomWOW mining threadlist");
}
for (i=0; i<miners-1; i++) {
si[i].si_cache = rs_cache;
@@ -225,11 +225,11 @@ void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const ch
if (cache == NULL) {
cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES);
if (cache == NULL) {
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX cache");
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomWOW cache");
cache = randomx_alloc_cache(flags);
}
if (cache == NULL)
local_abort("Couldn't allocate RandomX cache");
local_abort("Couldn't allocate RandomWOW cache");
}
}
if (rx_sp->rs_height != seedheight || rx_sp->rs_cache == NULL || memcmp(seedhash, rx_sp->rs_hash, HASH_SIZE)) {
@@ -251,7 +251,7 @@ void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const ch
if (rx_dataset == NULL) {
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES);
if (rx_dataset == NULL) {
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX dataset");
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomWOW dataset");
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT);
}
if (rx_dataset != NULL)
@@ -264,14 +264,14 @@ void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const ch
miners = 0;
if (!rx_dataset_nomem) {
rx_dataset_nomem = 1;
mwarning(RX_LOGCAT, "Couldn't allocate RandomX dataset for miner");
mwarning(RX_LOGCAT, "Couldn't allocate RandomWOW dataset for miner");
}
}
CTHR_MUTEX_UNLOCK(rx_dataset_mutex);
}
rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset);
if(rx_vm == NULL) { //large pages failed
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX VM");
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomWOW VM");
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset);
}
if(rx_vm == NULL) {//fallback if everything fails
@@ -279,7 +279,7 @@ void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const ch
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset);
}
if (rx_vm == NULL)
local_abort("Couldn't allocate RandomX VM");
local_abort("Couldn't allocate RandomWOW VM");
} else if (miners) {
CTHR_MUTEX_LOCK(rx_dataset_mutex);
if (rx_dataset != NULL && rx_dataset_height != seedheight)

29
src/crypto/sha3.c Normal file
View File

@@ -0,0 +1,29 @@
#include <stddef.h>
#include <openssl/evp.h>
void handleErrors(void) {
printf("sha3 error, wow is ded\n");
exit(1);
}
void sha3(const void *data, size_t length, char *hash)
{
EVP_MD_CTX *mdctx;
if((mdctx = EVP_MD_CTX_new()) == NULL) {
handleErrors();
}
if(1 != EVP_DigestInit_ex(mdctx, EVP_sha3_256(), NULL)) {
handleErrors();
}
if(1 != EVP_DigestUpdate(mdctx, data, length)) {
handleErrors();
}
/* the digest context ctx is automatically cleaned up. */
if(1 != EVP_DigestFinal(mdctx, (unsigned char*)hash, NULL)) {
handleErrors();
}
}

View File

@@ -40,9 +40,6 @@
#include "oaes_lib.h"
#include "variant2_int_sqrt.h"
#include "variant4_random_math.h"
#include "CryptonightR_JIT.h"
#include <errno.h>
#define MEMORY (1 << 21) // 2MB scratchpad
#define ITER (1 << 20)
@@ -54,41 +51,6 @@
extern void aesb_single_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);
extern void aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey);
static void local_abort(const char *msg)
{
fprintf(stderr, "%s\n", msg);
#ifdef NDEBUG
_exit(1);
#else
abort();
#endif
}
volatile int use_v4_jit_flag = -1;
static inline int use_v4_jit(void)
{
#if defined(__x86_64__)
if (use_v4_jit_flag != -1)
return use_v4_jit_flag;
const char *env = getenv("MONERO_USE_CNV4_JIT");
if (!env) {
use_v4_jit_flag = 1;
}
else if (!strcmp(env, "0") || !strcmp(env, "no")) {
use_v4_jit_flag = 0;
}
else {
use_v4_jit_flag = 1;
}
return use_v4_jit_flag;
#else
return 0;
#endif
}
#define VARIANT1_1(p) \
do if (variant == 1) \
{ \
@@ -155,74 +117,48 @@ static inline int use_v4_jit(void)
#define VARIANT2_SHUFFLE_ADD_SSE2(base_ptr, offset) \
do if (variant >= 2) \
{ \
__m128i chunk1 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10))); \
const __m128i chunk1 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10))); \
const __m128i chunk2 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20))); \
const __m128i chunk3 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30))); \
_mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \
_mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \
_mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \
if (variant >= 4) \
{ \
chunk1 = _mm_xor_si128(chunk1, chunk2); \
_c = _mm_xor_si128(_c, chunk3); \
_c = _mm_xor_si128(_c, chunk1); \
} \
} while (0)
#define VARIANT2_SHUFFLE_ADD_NEON(base_ptr, offset) \
do if (variant >= 2) \
{ \
uint64x2_t chunk1 = vld1q_u64(U64((base_ptr) + ((offset) ^ 0x10))); \
const uint64x2_t chunk1 = vld1q_u64(U64((base_ptr) + ((offset) ^ 0x10))); \
const uint64x2_t chunk2 = vld1q_u64(U64((base_ptr) + ((offset) ^ 0x20))); \
const uint64x2_t chunk3 = vld1q_u64(U64((base_ptr) + ((offset) ^ 0x30))); \
vst1q_u64(U64((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \
vst1q_u64(U64((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \
vst1q_u64(U64((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \
if (variant >= 4) \
{ \
chunk1 = veorq_u64(chunk1, chunk2); \
_c = vreinterpretq_u8_u64(veorq_u64(vreinterpretq_u64_u8(_c), chunk3)); \
_c = vreinterpretq_u8_u64(veorq_u64(vreinterpretq_u64_u8(_c), chunk1)); \
} \
} while (0)
#define VARIANT2_PORTABLE_SHUFFLE_ADD(out, a_, base_ptr, offset) \
#define VARIANT2_PORTABLE_SHUFFLE_ADD(base_ptr, offset) \
do if (variant >= 2) \
{ \
uint64_t* chunk1 = U64((base_ptr) + ((offset) ^ 0x10)); \
uint64_t* chunk2 = U64((base_ptr) + ((offset) ^ 0x20)); \
uint64_t* chunk3 = U64((base_ptr) + ((offset) ^ 0x30)); \
\
uint64_t chunk1_old[2] = { SWAP64LE(chunk1[0]), SWAP64LE(chunk1[1]) }; \
const uint64_t chunk2_old[2] = { SWAP64LE(chunk2[0]), SWAP64LE(chunk2[1]) }; \
const uint64_t chunk3_old[2] = { SWAP64LE(chunk3[0]), SWAP64LE(chunk3[1]) }; \
const uint64_t chunk1_old[2] = { chunk1[0], chunk1[1] }; \
\
uint64_t b1[2]; \
memcpy_swap64le(b1, b + 16, 2); \
chunk1[0] = SWAP64LE(chunk3_old[0] + b1[0]); \
chunk1[1] = SWAP64LE(chunk3_old[1] + b1[1]); \
chunk1[0] = SWAP64LE(SWAP64LE(chunk3[0]) + b1[0]); \
chunk1[1] = SWAP64LE(SWAP64LE(chunk3[1]) + b1[1]); \
\
uint64_t a0[2]; \
memcpy_swap64le(a0, a_, 2); \
chunk3[0] = SWAP64LE(chunk2_old[0] + a0[0]); \
chunk3[1] = SWAP64LE(chunk2_old[1] + a0[1]); \
memcpy_swap64le(a0, a, 2); \
chunk3[0] = SWAP64LE(SWAP64LE(chunk2[0]) + a0[0]); \
chunk3[1] = SWAP64LE(SWAP64LE(chunk2[1]) + a0[1]); \
\
uint64_t b0[2]; \
memcpy_swap64le(b0, b, 2); \
chunk2[0] = SWAP64LE(chunk1_old[0] + b0[0]); \
chunk2[1] = SWAP64LE(chunk1_old[1] + b0[1]); \
if (variant >= 4) \
{ \
uint64_t out_copy[2]; \
memcpy_swap64le(out_copy, out, 2); \
chunk1_old[0] ^= chunk2_old[0]; \
chunk1_old[1] ^= chunk2_old[1]; \
out_copy[0] ^= chunk3_old[0]; \
out_copy[1] ^= chunk3_old[1]; \
out_copy[0] ^= chunk1_old[0]; \
out_copy[1] ^= chunk1_old[1]; \
memcpy_swap64le(out, out_copy, 2); \
} \
chunk2[0] = SWAP64LE(SWAP64LE(chunk1_old[0]) + b0[0]); \
chunk2[1] = SWAP64LE(SWAP64LE(chunk1_old[1]) + b0[1]); \
} while (0)
#define VARIANT2_INTEGER_MATH_DIVISION_STEP(b, ptr) \
@@ -265,18 +201,18 @@ static inline int use_v4_jit(void)
#endif
#define VARIANT2_2_PORTABLE() \
if (variant == 2 || variant == 3) { \
if (variant >= 2) { \
xor_blocks(long_state + (j ^ 0x10), d); \
xor_blocks(d, long_state + (j ^ 0x20)); \
}
#define VARIANT2_2() \
do if (variant == 2 || variant == 3) \
do if (variant >= 2) \
{ \
*U64(local_hp_state + (j ^ 0x10)) ^= SWAP64LE(hi); \
*(U64(local_hp_state + (j ^ 0x10)) + 1) ^= SWAP64LE(lo); \
hi ^= SWAP64LE(*U64(local_hp_state + (j ^ 0x20))); \
lo ^= SWAP64LE(*(U64(local_hp_state + (j ^ 0x20)) + 1)); \
*U64(hp_state + (j ^ 0x10)) ^= SWAP64LE(hi); \
*(U64(hp_state + (j ^ 0x10)) + 1) ^= SWAP64LE(lo); \
hi ^= SWAP64LE(*U64(hp_state + (j ^ 0x20))); \
lo ^= SWAP64LE(*(U64(hp_state + (j ^ 0x20)) + 1)); \
} while (0)
#define V4_REG_LOAD(dst, src) \
@@ -289,56 +225,34 @@ static inline int use_v4_jit(void)
} while (0)
#define VARIANT4_RANDOM_MATH_INIT() \
v4_reg r[9]; \
struct V4_Instruction code[NUM_INSTRUCTIONS_MAX + 1]; \
int jit = use_v4_jit(); \
v4_reg r[8]; \
struct V4_Instruction code[TOTAL_LATENCY * ALU_COUNT + 1]; \
do if (variant >= 4) \
{ \
for (int i = 0; i < 4; ++i) \
V4_REG_LOAD(r + i, (uint8_t*)(state.hs.w + 12) + sizeof(v4_reg) * i); \
v4_random_math_init(code, height); \
if (jit) \
{ \
int ret = v4_generate_JIT_code(code, hp_jitfunc, 4096); \
if (ret < 0) \
local_abort("Error generating CryptonightR code"); \
} \
} while (0)
#define VARIANT4_RANDOM_MATH(a, b, r, _b, _b1) \
do if (variant >= 4) \
{ \
uint64_t t[2]; \
memcpy(t, b, sizeof(uint64_t)); \
uint64_t t; \
memcpy(&t, b, sizeof(uint64_t)); \
\
if (sizeof(v4_reg) == sizeof(uint32_t)) \
t[0] ^= SWAP64LE((r[0] + r[1]) | ((uint64_t)(r[2] + r[3]) << 32)); \
t ^= SWAP64LE((r[0] + r[1]) | ((uint64_t)(r[2] + r[3]) << 32)); \
else \
t[0] ^= SWAP64LE((r[0] + r[1]) ^ (r[2] + r[3])); \
t ^= SWAP64LE((r[0] + r[1]) ^ (r[2] + r[3])); \
\
memcpy(b, t, sizeof(uint64_t)); \
memcpy(b, &t, sizeof(uint64_t)); \
\
V4_REG_LOAD(r + 4, a); \
V4_REG_LOAD(r + 5, (uint64_t*)(a) + 1); \
V4_REG_LOAD(r + 6, _b); \
V4_REG_LOAD(r + 7, _b1); \
V4_REG_LOAD(r + 8, (uint64_t*)(_b1) + 1); \
\
if (jit) \
(*hp_jitfunc)(r); \
else \
v4_random_math(code, r); \
\
memcpy(t, a, sizeof(uint64_t) * 2); \
\
if (sizeof(v4_reg) == sizeof(uint32_t)) { \
t[0] ^= SWAP64LE(r[2] | ((uint64_t)(r[3]) << 32)); \
t[1] ^= SWAP64LE(r[0] | ((uint64_t)(r[1]) << 32)); \
} else { \
t[0] ^= SWAP64LE(r[2] ^ r[3]); \
t[1] ^= SWAP64LE(r[0] ^ r[1]); \
} \
memcpy(a, t, sizeof(uint64_t) * 2); \
v4_random_math(code, r); \
} while (0)
@@ -404,7 +318,7 @@ static inline int use_v4_jit(void)
#define pre_aes() \
j = state_index(a); \
_c = _mm_load_si128(R128(&local_hp_state[j])); \
_c = _mm_load_si128(R128(&hp_state[j])); \
_a = _mm_load_si128(R128(a)); \
/*
@@ -417,20 +331,20 @@ static inline int use_v4_jit(void)
* This code is based upon an optimized implementation by dga.
*/
#define post_aes() \
VARIANT2_SHUFFLE_ADD_SSE2(local_hp_state, j); \
VARIANT2_SHUFFLE_ADD_SSE2(hp_state, j); \
_mm_store_si128(R128(c), _c); \
_mm_store_si128(R128(&local_hp_state[j]), _mm_xor_si128(_b, _c)); \
VARIANT1_1(&local_hp_state[j]); \
_mm_store_si128(R128(&hp_state[j]), _mm_xor_si128(_b, _c)); \
VARIANT1_1(&hp_state[j]); \
j = state_index(c); \
p = U64(&local_hp_state[j]); \
p = U64(&hp_state[j]); \
b[0] = p[0]; b[1] = p[1]; \
VARIANT2_INTEGER_MATH_SSE2(b, c); \
VARIANT4_RANDOM_MATH(a, b, r, &_b, &_b1); \
__mul(); \
VARIANT2_2(); \
VARIANT2_SHUFFLE_ADD_SSE2(local_hp_state, j); \
VARIANT2_SHUFFLE_ADD_SSE2(hp_state, j); \
a[0] += hi; a[1] += lo; \
p = U64(&local_hp_state[j]); \
p = U64(&hp_state[j]); \
p[0] = a[0]; p[1] = a[1]; \
a[0] ^= b[0]; a[1] ^= b[1]; \
VARIANT1_2(p + 1); \
@@ -457,9 +371,6 @@ union cn_slow_hash_state
THREADV uint8_t *hp_state = NULL;
THREADV int hp_allocated = 0;
THREADV v4_random_math_JIT_func hp_jitfunc = NULL;
THREADV uint8_t *hp_jitfunc_memory = NULL;
THREADV int hp_jitfunc_allocated = 0;
#if defined(_MSC_VER)
#define cpuid(info,x) __cpuidex(info,x,0)
@@ -755,10 +666,10 @@ void cn_slow_hash_allocate_state(void)
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(__DragonFly__) || defined(__NetBSD__)
hp_state = mmap(0, MEMORY, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
MAP_PRIVATE | MAP_ANON, 0, 0);
#else
hp_state = mmap(0, MEMORY, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, 0, 0);
#endif
if(hp_state == MAP_FAILED)
hp_state = NULL;
@@ -769,35 +680,6 @@ void cn_slow_hash_allocate_state(void)
hp_allocated = 0;
hp_state = (uint8_t *) malloc(MEMORY);
}
#if defined(_MSC_VER) || defined(__MINGW32__)
hp_jitfunc_memory = (uint8_t *) VirtualAlloc(hp_jitfunc_memory, 4096 + 4095,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
#else
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(__DragonFly__) || defined(__NetBSD__)
#ifdef __NetBSD__
#define RESERVED_FLAGS PROT_MPROTECT(PROT_EXEC)
#else
#define RESERVED_FLAGS 0
#endif
hp_jitfunc_memory = mmap(0, 4096 + 4096, PROT_READ | PROT_WRITE | RESERVED_FLAGS,
MAP_PRIVATE | MAP_ANON, -1, 0);
#else
hp_jitfunc_memory = mmap(0, 4096 + 4096, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#endif
if(hp_jitfunc_memory == MAP_FAILED)
hp_jitfunc_memory = NULL;
#endif
hp_jitfunc_allocated = 1;
if (hp_jitfunc_memory == NULL)
{
hp_jitfunc_allocated = 0;
hp_jitfunc_memory = malloc(4096 + 4095);
}
hp_jitfunc = (v4_random_math_JIT_func)((size_t)(hp_jitfunc_memory + 4095) & ~4095);
}
/**
@@ -820,22 +702,8 @@ void cn_slow_hash_free_state(void)
#endif
}
if(!hp_jitfunc_allocated)
free(hp_jitfunc_memory);
else
{
#if defined(_MSC_VER) || defined(__MINGW32__)
VirtualFree(hp_jitfunc_memory, 0, MEM_RELEASE);
#else
munmap(hp_jitfunc_memory, 4096 + 4095);
#endif
}
hp_state = NULL;
hp_allocated = 0;
hp_jitfunc = NULL;
hp_jitfunc_memory = NULL;
hp_jitfunc_allocated = 0;
}
/**
@@ -919,7 +787,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
{
aes_pseudo_round(text, text, expandedKey, INIT_SIZE_BLK);
memcpy(&local_hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
memcpy(&hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
}
}
else
@@ -931,7 +799,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
for(j = 0; j < INIT_SIZE_BLK; j++)
aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data);
memcpy(&local_hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
memcpy(&hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
}
}
@@ -979,7 +847,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
{
// add the xor to the pseudo round
aes_pseudo_round_xor(text, text, expandedKey, &local_hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK);
aes_pseudo_round_xor(text, text, expandedKey, &hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK);
}
}
else
@@ -989,7 +857,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
{
for(j = 0; j < INIT_SIZE_BLK; j++)
{
xor_blocks(&text[j * AES_BLOCK_SIZE], &local_hp_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]);
xor_blocks(&text[j * AES_BLOCK_SIZE], &hp_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]);
aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data);
}
}
@@ -1033,8 +901,6 @@ void cn_slow_hash_free_state(void)
#define U64(x) ((uint64_t *) (x))
#define hp_jitfunc ((v4_random_math_JIT_func)NULL)
STATIC INLINE void xor64(uint64_t *a, const uint64_t b)
{
*a ^= b;
@@ -1069,24 +935,24 @@ union cn_slow_hash_state
#define pre_aes() \
j = state_index(a); \
_c = vld1q_u8(&local_hp_state[j]); \
_c = vld1q_u8(&hp_state[j]); \
_a = vld1q_u8((const uint8_t *)a); \
#define post_aes() \
VARIANT2_SHUFFLE_ADD_NEON(local_hp_state, j); \
VARIANT2_SHUFFLE_ADD_NEON(hp_state, j); \
vst1q_u8((uint8_t *)c, _c); \
vst1q_u8(&local_hp_state[j], veorq_u8(_b, _c)); \
VARIANT1_1(&local_hp_state[j]); \
vst1q_u8(&hp_state[j], veorq_u8(_b, _c)); \
VARIANT1_1(&hp_state[j]); \
j = state_index(c); \
p = U64(&local_hp_state[j]); \
p = U64(&hp_state[j]); \
b[0] = p[0]; b[1] = p[1]; \
VARIANT2_PORTABLE_INTEGER_MATH(b, c); \
VARIANT4_RANDOM_MATH(a, b, r, &_b, &_b1); \
__mul(); \
VARIANT2_2(); \
VARIANT2_SHUFFLE_ADD_NEON(local_hp_state, j); \
VARIANT2_SHUFFLE_ADD_NEON(hp_state, j); \
a[0] += hi; a[1] += lo; \
p = U64(&local_hp_state[j]); \
p = U64(&hp_state[j]); \
p[0] = a[0]; p[1] = a[1]; \
a[0] ^= b[0]; a[1] ^= b[1]; \
VARIANT1_2(p + 1); \
@@ -1100,47 +966,47 @@ union cn_slow_hash_state
*/
static void aes_expand_key(const uint8_t *key, uint8_t *expandedKey) {
static const int rcon[] = {
0x01,0x01,0x01,0x01,
0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d, // rotate-n-splat
0x1b,0x1b,0x1b,0x1b };
0x01,0x01,0x01,0x01,
0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d, // rotate-n-splat
0x1b,0x1b,0x1b,0x1b };
__asm__(
" eor v0.16b,v0.16b,v0.16b\n"
" ld1 {v3.16b},[%0],#16\n"
" ld1 {v1.4s,v2.4s},[%2],#32\n"
" ld1 {v4.16b},[%0]\n"
" mov w2,#5\n"
" st1 {v3.4s},[%1],#16\n"
" eor v0.16b,v0.16b,v0.16b\n"
" ld1 {v3.16b},[%0],#16\n"
" ld1 {v1.4s,v2.4s},[%2],#32\n"
" ld1 {v4.16b},[%0]\n"
" mov w2,#5\n"
" st1 {v3.4s},[%1],#16\n"
"\n"
"1:\n"
" tbl v6.16b,{v4.16b},v2.16b\n"
" ext v5.16b,v0.16b,v3.16b,#12\n"
" st1 {v4.4s},[%1],#16\n"
" aese v6.16b,v0.16b\n"
" subs w2,w2,#1\n"
" tbl v6.16b,{v4.16b},v2.16b\n"
" ext v5.16b,v0.16b,v3.16b,#12\n"
" st1 {v4.4s},[%1],#16\n"
" aese v6.16b,v0.16b\n"
" subs w2,w2,#1\n"
"\n"
" eor v3.16b,v3.16b,v5.16b\n"
" ext v5.16b,v0.16b,v5.16b,#12\n"
" eor v3.16b,v3.16b,v5.16b\n"
" ext v5.16b,v0.16b,v5.16b,#12\n"
" eor v6.16b,v6.16b,v1.16b\n"
" eor v3.16b,v3.16b,v5.16b\n"
" shl v1.16b,v1.16b,#1\n"
" eor v3.16b,v3.16b,v6.16b\n"
" st1 {v3.4s},[%1],#16\n"
" b.eq 2f\n"
" eor v3.16b,v3.16b,v5.16b\n"
" ext v5.16b,v0.16b,v5.16b,#12\n"
" eor v3.16b,v3.16b,v5.16b\n"
" ext v5.16b,v0.16b,v5.16b,#12\n"
" eor v6.16b,v6.16b,v1.16b\n"
" eor v3.16b,v3.16b,v5.16b\n"
" shl v1.16b,v1.16b,#1\n"
" eor v3.16b,v3.16b,v6.16b\n"
" st1 {v3.4s},[%1],#16\n"
" b.eq 2f\n"
"\n"
" dup v6.4s,v3.s[3] // just splat\n"
" ext v5.16b,v0.16b,v4.16b,#12\n"
" aese v6.16b,v0.16b\n"
" dup v6.4s,v3.s[3] // just splat\n"
" ext v5.16b,v0.16b,v4.16b,#12\n"
" aese v6.16b,v0.16b\n"
"\n"
" eor v4.16b,v4.16b,v5.16b\n"
" ext v5.16b,v0.16b,v5.16b,#12\n"
" eor v4.16b,v4.16b,v5.16b\n"
" ext v5.16b,v0.16b,v5.16b,#12\n"
" eor v4.16b,v4.16b,v5.16b\n"
" eor v4.16b,v4.16b,v5.16b\n"
" ext v5.16b,v0.16b,v5.16b,#12\n"
" eor v4.16b,v4.16b,v5.16b\n"
" ext v5.16b,v0.16b,v5.16b,#12\n"
" eor v4.16b,v4.16b,v5.16b\n"
"\n"
" eor v4.16b,v4.16b,v6.16b\n"
" b 1b\n"
" eor v4.16b,v4.16b,v6.16b\n"
" b 1b\n"
"\n"
"2:\n" : : "r"(key), "r"(expandedKey), "r"(rcon));
}
@@ -1155,71 +1021,71 @@ __asm__(
*/
STATIC INLINE void aes_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey, int nblocks)
{
const uint8x16_t *k = (const uint8x16_t *)expandedKey, zero = {0};
uint8x16_t tmp;
int i;
const uint8x16_t *k = (const uint8x16_t *)expandedKey, zero = {0};
uint8x16_t tmp;
int i;
for (i=0; i<nblocks; i++)
{
uint8x16_t tmp = vld1q_u8(in + i * AES_BLOCK_SIZE);
tmp = vaeseq_u8(tmp, zero);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[0]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[1]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[2]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[3]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[4]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[5]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[6]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[7]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[8]);
tmp = vaesmcq_u8(tmp);
tmp = veorq_u8(tmp, k[9]);
vst1q_u8(out + i * AES_BLOCK_SIZE, tmp);
}
for (i=0; i<nblocks; i++)
{
uint8x16_t tmp = vld1q_u8(in + i * AES_BLOCK_SIZE);
tmp = vaeseq_u8(tmp, zero);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[0]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[1]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[2]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[3]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[4]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[5]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[6]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[7]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[8]);
tmp = vaesmcq_u8(tmp);
tmp = veorq_u8(tmp, k[9]);
vst1q_u8(out + i * AES_BLOCK_SIZE, tmp);
}
}
STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey, const uint8_t *xor, int nblocks)
{
const uint8x16_t *k = (const uint8x16_t *)expandedKey;
const uint8x16_t *x = (const uint8x16_t *)xor;
uint8x16_t tmp;
int i;
const uint8x16_t *k = (const uint8x16_t *)expandedKey;
const uint8x16_t *x = (const uint8x16_t *)xor;
uint8x16_t tmp;
int i;
for (i=0; i<nblocks; i++)
{
uint8x16_t tmp = vld1q_u8(in + i * AES_BLOCK_SIZE);
tmp = vaeseq_u8(tmp, x[i]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[0]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[1]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[2]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[3]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[4]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[5]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[6]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[7]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[8]);
tmp = vaesmcq_u8(tmp);
tmp = veorq_u8(tmp, k[9]);
vst1q_u8(out + i * AES_BLOCK_SIZE, tmp);
}
for (i=0; i<nblocks; i++)
{
uint8x16_t tmp = vld1q_u8(in + i * AES_BLOCK_SIZE);
tmp = vaeseq_u8(tmp, x[i]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[0]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[1]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[2]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[3]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[4]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[5]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[6]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[7]);
tmp = vaesmcq_u8(tmp);
tmp = vaeseq_u8(tmp, k[8]);
tmp = vaesmcq_u8(tmp);
tmp = veorq_u8(tmp, k[9]);
vst1q_u8(out + i * AES_BLOCK_SIZE, tmp);
}
}
#ifdef FORCE_USE_HEAP
@@ -1249,9 +1115,9 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
RDATA_ALIGN16 uint8_t expandedKey[240];
#ifndef FORCE_USE_HEAP
RDATA_ALIGN16 uint8_t local_hp_state[MEMORY];
RDATA_ALIGN16 uint8_t hp_state[MEMORY];
#else
uint8_t *local_hp_state = (uint8_t *)aligned_malloc(MEMORY,16);
uint8_t *hp_state = (uint8_t *)aligned_malloc(MEMORY,16);
#endif
uint8_t text[INIT_SIZE_BYTE];
@@ -1291,7 +1157,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
{
aes_pseudo_round(text, text, expandedKey, INIT_SIZE_BLK);
memcpy(&local_hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
memcpy(&hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE);
}
U64(a)[0] = U64(&state.k[0])[0] ^ U64(&state.k[32])[0];
@@ -1326,7 +1192,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++)
{
// add the xor to the pseudo round
aes_pseudo_round_xor(text, text, expandedKey, &local_hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK);
aes_pseudo_round_xor(text, text, expandedKey, &hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK);
}
/* CryptoNight Step 5: Apply Keccak to the state again, and then
@@ -1341,7 +1207,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
extra_hashes[state.hs.b[0] & 3](&state, 200, hash);
#ifdef FORCE_USE_HEAP
aligned_free(local_hp_state);
aligned_free(hp_state);
#endif
}
#else /* aarch64 && crypto */
@@ -1385,7 +1251,7 @@ void mul(const uint8_t *ca, const uint8_t *cb, uint8_t *cres) {
#else // !NO_OPTIMIZED_MULTIPLY_ON_ARM
#ifdef __aarch64__ /* ARM64, no crypto */
#define mul(a, b, c) cn_mul128((const uint64_t *)a, (const uint64_t *)b, (uint64_t *)c)
#define mul(a, b, c) cn_mul128((const uint64_t *)a, (const uint64_t *)b, (uint64_t *)c)
STATIC void cn_mul128(const uint64_t *a, const uint64_t *b, uint64_t *r)
{
uint64_t lo, hi;
@@ -1395,7 +1261,7 @@ STATIC void cn_mul128(const uint64_t *a, const uint64_t *b, uint64_t *r)
r[1] = lo;
}
#else /* ARM32 */
#define mul(a, b, c) cn_mul128((const uint32_t *)a, (const uint32_t *)b, (uint32_t *)c)
#define mul(a, b, c) cn_mul128((const uint32_t *)a, (const uint32_t *)b, (uint32_t *)c)
STATIC void cn_mul128(const uint32_t *aa, const uint32_t *bb, uint32_t *r)
{
uint32_t t0, t1, t2=0, t3=0;
@@ -1464,7 +1330,6 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
{
uint8_t text[INIT_SIZE_BYTE];
uint8_t a[AES_BLOCK_SIZE];
uint8_t a1[AES_BLOCK_SIZE];
uint8_t b[AES_BLOCK_SIZE * 2];
uint8_t c[AES_BLOCK_SIZE];
uint8_t c1[AES_BLOCK_SIZE];
@@ -1524,10 +1389,10 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
// Iteration 1
j = state_index(a);
p = &long_state[j];
aesb_single_round(p, c1, a);
aesb_single_round(p, p, a);
copy_block(c1, p);
VARIANT2_PORTABLE_SHUFFLE_ADD(c1, a, long_state, j);
copy_block(p, c1);
VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j);
xor_blocks(p, b);
VARIANT1_1(p);
@@ -1536,15 +1401,14 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
p = &long_state[j];
copy_block(c, p);
copy_block(a1, a);
VARIANT2_PORTABLE_INTEGER_MATH(c, c1);
VARIANT4_RANDOM_MATH(a1, c, r, b, b + AES_BLOCK_SIZE);
VARIANT4_RANDOM_MATH(a, c, r, b, b + AES_BLOCK_SIZE);
mul(c1, c, d);
VARIANT2_2_PORTABLE();
VARIANT2_PORTABLE_SHUFFLE_ADD(c1, a, long_state, j);
sum_half_blocks(a1, d);
swap_blocks(a1, c);
xor_blocks(a1, c);
VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j);
sum_half_blocks(a, d);
swap_blocks(a, c);
xor_blocks(a, c);
VARIANT1_2(U64(c) + 1);
copy_block(p, c);
@@ -1552,7 +1416,6 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
copy_block(b + AES_BLOCK_SIZE, b);
}
copy_block(b, c1);
copy_block(a, a1);
}
memcpy(text, state.init, INIT_SIZE_BYTE);
@@ -1580,9 +1443,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
#else
// Portable implementation as a fallback
#define hp_jitfunc ((v4_random_math_JIT_func)NULL)
void cn_slow_hash_allocate_state(void)
void slow_hash_allocate_state(void)
{
// Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c
return;
@@ -1675,7 +1536,6 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
union cn_slow_hash_state state;
uint8_t text[INIT_SIZE_BYTE];
uint8_t a[AES_BLOCK_SIZE];
uint8_t a1[AES_BLOCK_SIZE];
uint8_t b[AES_BLOCK_SIZE * 2];
uint8_t c1[AES_BLOCK_SIZE];
uint8_t c2[AES_BLOCK_SIZE];
@@ -1719,7 +1579,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
j = e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
copy_block(c1, &long_state[j]);
aesb_single_round(c1, c1, a);
VARIANT2_PORTABLE_SHUFFLE_ADD(c1, a, long_state, j);
VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j);
copy_block(&long_state[j], c1);
xor_blocks(&long_state[j], b);
assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE);
@@ -1727,22 +1587,23 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
/* Iteration 2 */
j = e2i(c1, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
copy_block(c2, &long_state[j]);
copy_block(a1, a);
VARIANT2_PORTABLE_INTEGER_MATH(c2, c1);
VARIANT4_RANDOM_MATH(a1, c2, r, b, b + AES_BLOCK_SIZE);
VARIANT4_RANDOM_MATH(a, c2, r, b, b + AES_BLOCK_SIZE);
mul(c1, c2, d);
VARIANT2_2_PORTABLE();
VARIANT2_PORTABLE_SHUFFLE_ADD(c1, a, long_state, j);
sum_half_blocks(a1, d);
swap_blocks(a1, c2);
xor_blocks(a1, c2);
VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j);
swap_blocks(a, c1);
sum_half_blocks(c1, d);
swap_blocks(c1, c2);
xor_blocks(c1, c2);
VARIANT1_2(c2 + 8);
copy_block(&long_state[j], c2);
assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE);
if (variant >= 2) {
copy_block(b + AES_BLOCK_SIZE, b);
}
copy_block(b, c1);
copy_block(a, a1);
copy_block(b, a);
copy_block(a, c1);
}
memcpy(text, state.init, INIT_SIZE_BYTE);

View File

@@ -10,11 +10,8 @@ enum V4_Settings
TOTAL_LATENCY = 15 * 3,
// Always generate at least 60 instructions
NUM_INSTRUCTIONS_MIN = 60,
// Never generate more than 70 instructions (final RET instruction doesn't count here)
NUM_INSTRUCTIONS_MAX = 70,
NUM_INSTRUCTIONS = 60,
// Available ALUs for MUL
// Modern CPUs typically have only 1 ALU which can do multiplications
ALU_COUNT_MUL = 1,
@@ -39,9 +36,10 @@ enum V4_InstructionList
// V4_InstructionDefinition is used to generate code from random data
// Every random sequence of bytes is a valid code
//
// There are 9 registers in total:
// There are 8 registers in total:
// - 4 variable registers
// - 5 constant registers initialized from loop variables
// - 4 constant registers initialized from loop variables
//
// This is why dst_index is 2 bits
enum V4_InstructionDefinition
{
@@ -59,9 +57,9 @@ struct V4_Instruction
};
#ifndef FORCEINLINE
#if defined(__GNUC__)
#ifdef __GNUC__
#define FORCEINLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#elif _MSC_VER
#define FORCEINLINE __forceinline
#else
#define FORCEINLINE inline
@@ -69,9 +67,9 @@ struct V4_Instruction
#endif
#ifndef UNREACHABLE_CODE
#if defined(__GNUC__)
#ifdef __GNUC__
#define UNREACHABLE_CODE __builtin_unreachable()
#elif defined(_MSC_VER)
#elif _MSC_VER
#define UNREACHABLE_CODE __assume(false)
#else
#define UNREACHABLE_CODE
@@ -143,16 +141,16 @@ static FORCEINLINE void v4_random_math(const struct V4_Instruction* code, v4_reg
// Generated program can have 60 + a few more (usually 2-3) instructions to achieve required latency
// I've checked all block heights < 10,000,000 and here is the distribution of program sizes:
//
// 60 27960
// 61 105054
// 62 2452759
// 63 5115997
// 64 1022269
// 65 1109635
// 66 153145
// 67 8550
// 68 4529
// 69 102
// 60 28495
// 61 106077
// 62 2455855
// 63 5114930
// 64 1020868
// 65 1109026
// 66 151756
// 67 8429
// 68 4477
// 69 87
// Unroll 70 instructions here
V4_EXEC_10(0); // instructions 0-9
@@ -178,7 +176,6 @@ static FORCEINLINE void check_data(size_t* data_index, const size_t bytes_needed
}
// Generates as many random math operations as possible with given latency and ALU restrictions
// "code" array must have space for NUM_INSTRUCTIONS_MAX+1 instructions
static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_t height)
{
// MUL is 3 cycles, 3-way addition and rotations are 2 cycles, SUB/XOR are 1 cycle
@@ -200,7 +197,6 @@ static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_
memset(data, 0, sizeof(data));
uint64_t tmp = SWAP64LE(height);
memcpy(data, &tmp, sizeof(uint64_t));
data[20] = -38; // change seed
// Set data_index past the last byte in data
// to trigger full data update with blake hash
@@ -208,22 +204,18 @@ static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_
size_t data_index = sizeof(data);
int code_size;
// There is a small chance (1.8%) that register R8 won't be used in the generated program
// So we keep track of it and try again if it's not used
bool r8_used;
do {
int latency[9];
int asic_latency[9];
int latency[8];
int asic_latency[8];
// Tracks previous instruction and value of the source operand for registers R0-R3 throughout code execution
// byte 0: current value of the destination register
// byte 1: instruction opcode
// byte 2: current value of the source register
//
// Registers R4-R8 are constant and are treated as having the same value because when we do
// Registers R4-R7 are constant and are treated as having the same value because when we do
// the same operation twice with two constant source registers, it can be optimized into a single operation
uint32_t inst_data[9] = { 0, 1, 2, 3, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF };
uint32_t inst_data[8] = { 0, 1, 2, 3, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF };
bool alu_busy[TOTAL_LATENCY + 1][ALU_COUNT];
bool is_rotation[V4_INSTRUCTION_COUNT];
@@ -242,7 +234,6 @@ static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_
code_size = 0;
int total_iterations = 0;
r8_used = false;
// Generate random code to achieve minimal required latency for our abstract CPU
// Try to get this latency for all 4 registers
@@ -286,9 +277,9 @@ static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_
// Don't do ADD/SUB/XOR with the same register
if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b))
{
// Use register R8 as source instead
b = 8;
src_index = 8;
// a is always < 4, so we don't need to check bounds here
b = a + 4;
src_index = b;
}
// Don't do rotation with the same destination twice because it's equal to a single rotation
@@ -368,11 +359,6 @@ static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_
code[code_size].src_index = src_index;
code[code_size].C = 0;
if (src_index == 8)
{
r8_used = true;
}
if (opcode == ADD)
{
// ADD instruction is implemented as two 1-cycle instructions on a real CPU, so mark ALU as busy for the next cycle too
@@ -387,7 +373,7 @@ static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_
}
++code_size;
if (code_size >= NUM_INSTRUCTIONS_MIN)
if (code_size >= NUM_INSTRUCTIONS)
{
break;
}
@@ -402,7 +388,7 @@ static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_
// We need to add a few more MUL and ROR instructions to achieve minimal required latency for ASIC
// Get this latency for at least 1 of the 4 registers
const int prev_code_size = code_size;
while ((code_size < NUM_INSTRUCTIONS_MAX) && (asic_latency[0] < TOTAL_LATENCY) && (asic_latency[1] < TOTAL_LATENCY) && (asic_latency[2] < TOTAL_LATENCY) && (asic_latency[3] < TOTAL_LATENCY))
while ((asic_latency[0] < TOTAL_LATENCY) && (asic_latency[1] < TOTAL_LATENCY) && (asic_latency[2] < TOTAL_LATENCY) && (asic_latency[3] < TOTAL_LATENCY))
{
int min_idx = 0;
int max_idx = 0;
@@ -424,11 +410,9 @@ static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_
++code_size;
}
// There is ~98.15% chance that loop condition is false, so this loop will execute only 1 iteration most of the time
// It never does more than 4 iterations for all block heights < 10,000,000
} while (!r8_used || (code_size < NUM_INSTRUCTIONS_MIN) || (code_size > NUM_INSTRUCTIONS_MAX));
// There is ~99.8% chance that code_size >= NUM_INSTRUCTIONS here, so second iteration is required rarely
} while (code_size < NUM_INSTRUCTIONS);
// It's guaranteed that NUM_INSTRUCTIONS_MIN <= code_size <= NUM_INSTRUCTIONS_MAX here
// Add final instruction to stop the interpreter
code[code_size].opcode = RET;
code[code_size].dst_index = 0;

View File

@@ -449,14 +449,26 @@ namespace cryptonote
uint8_t minor_version; // now used as a voting mechanism, rather than how this particular block is built
uint64_t timestamp;
crypto::hash prev_id;
uint32_t nonce;
uint64_t nonce;
BEGIN_SERIALIZE()
VARINT_FIELD(major_version)
VARINT_FIELD(minor_version)
VARINT_FIELD(timestamp)
FIELD(prev_id)
FIELD(nonce)
if (major_version >= HF_VERSION_SHA3_POW)
{
FIELD(nonce)
}
else
{
uint32_t nonce32;
if (typename Archive<W>::is_saving())
nonce32 = (uint32_t)nonce;
FIELD_N("nonce", nonce32);
if (!typename Archive<W>::is_saving())
nonce = nonce32;
}
END_SERIALIZE()
};

View File

@@ -88,7 +88,7 @@ namespace cryptonote {
const int emission_speed_factor = EMISSION_SPEED_FACTOR_PER_MINUTE - (target_minutes-1);
uint64_t base_reward = (MONEY_SUPPLY - already_generated_coins) >> emission_speed_factor;
if (base_reward < FINAL_SUBSIDY_PER_MINUTE*target_minutes)
if (base_reward <= FINAL_SUBSIDY_PER_MINUTE*target_minutes)
{
base_reward = FINAL_SUBSIDY_PER_MINUTE*target_minutes;
}

View File

@@ -295,7 +295,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2)
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimpleBulletproof)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -323,7 +323,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2)
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimpleBulletproof)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -337,7 +337,7 @@ namespace boost
if (x.p.rangeSigs.empty())
a & x.p.bulletproofs;
a & x.p.MGs;
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2)
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeSimpleBulletproof)
a & x.p.pseudoOuts;
}

View File

@@ -126,6 +126,20 @@ namespace cryptonote
namespace cryptonote
{
//---------------------------------------------------------------
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h, hw::device &hwdev)
{
hwdev.get_transaction_prefix_hash(tx,h);
}
//---------------------------------------------------------------
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx, hw::device &hwdev)
{
crypto::hash h = null_hash;
get_transaction_prefix_hash(tx, h, hwdev);
return h;
}
//---------------------------------------------------------------
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
{
std::ostringstream s;
@@ -146,6 +160,8 @@ namespace cryptonote
if (tx.version >= 2 && !is_coinbase(tx))
{
rct::rctSig &rv = tx.rct_signatures;
if (rv.type == rct::RCTTypeNull)
return true;
if (rv.outPk.size() != tx.vout.size())
{
LOG_PRINT_L1("Failed to parse transaction from blob, bad outPk size in tx " << get_transaction_hash(tx));
@@ -164,7 +180,7 @@ namespace cryptonote
if (!base_only)
{
const bool bulletproof = rct::is_rct_bulletproof(rv.type);
if (bulletproof)
if (rct::is_rct_new_bulletproof(rv.type))
{
if (rv.p.bulletproofs.size() != 1)
{
@@ -177,7 +193,7 @@ namespace cryptonote
return false;
}
const size_t max_outputs = 1 << (rv.p.bulletproofs[0].L.size() - 6);
if (max_outputs < tx.vout.size())
if (max_outputs < tx.vout.size() && rv.type == rct::RCTTypeBulletproof)
{
LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs max outputs in tx " << get_transaction_hash(tx));
return false;
@@ -188,6 +204,26 @@ namespace cryptonote
for (size_t i = 0; i < n_amounts; ++i)
rv.p.bulletproofs[0].V[i] = rct::scalarmultKey(rv.outPk[i].mask, rct::INV_EIGHT);
}
else if (bulletproof)
{
if (rct::n_bulletproof_v1_amounts(rv.p.bulletproofs) != tx.vout.size())
{
LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs size in tx " << get_transaction_hash(tx));
return false;
}
size_t idx = 0;
for (size_t n = 0; n < rv.outPk.size(); ++n)
{
//rv.p.bulletproofs[n].V.resize(1);
//rv.p.bulletproofs[n].V[0] = rv.outPk[n].mask;
CHECK_AND_ASSERT_MES(rv.p.bulletproofs[n].L.size() >= 6, false, "Bad bulletproofs L size"); // at least 64 bits
const size_t n_amounts = rct::n_bulletproof_v1_amounts(rv.p.bulletproofs[n]);
CHECK_AND_ASSERT_MES(idx + n_amounts <= rv.outPk.size(), false, "Internal error filling out V");
rv.p.bulletproofs[n].V.resize(n_amounts);
for (size_t i = 0; i < n_amounts; ++i)
rv.p.bulletproofs[n].V[i] = rv.outPk[idx++].mask;
}
}
}
}
return true;
@@ -410,6 +446,12 @@ namespace cryptonote
const rct::rctSig &rv = tx.rct_signatures;
if (!rct::is_rct_bulletproof(rv.type))
return blob_size;
const size_t n_outputs = tx.vout.size();
if (n_outputs <= 2)
return blob_size;
if (rct::is_rct_old_bulletproof(rv.type))
return blob_size;
const uint64_t bp_base = 368;
const size_t n_padded_outputs = rct::n_bulletproof_max_amounts(rv.p.bulletproofs);
uint64_t bp_clawback = get_transaction_weight_clawback(tx, n_padded_outputs);
CHECK_AND_ASSERT_THROW_MES_L1(bp_clawback <= std::numeric_limits<uint64_t>::max() - blob_size, "Weight overflow");
@@ -956,7 +998,7 @@ namespace cryptonote
{
switch (decimal_point)
{
case 12:
case 11:
case 9:
case 6:
case 3:
@@ -979,8 +1021,8 @@ namespace cryptonote
decimal_point = default_decimal_point;
switch (decimal_point)
{
case 12:
return "monero";
case 11:
return "wownero";
case 9:
return "millinero";
case 6:
@@ -1227,45 +1269,7 @@ namespace cryptonote
//---------------------------------------------------------------
bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob)
{
blobdata bd;
if (!blob)
{
bd = block_to_blob(b);
blob = &bd;
}
bool hash_result = get_object_hash(get_block_hashing_blob(b), res);
if (!hash_result)
return false;
if (b.miner_tx.vin.size() == 1 && b.miner_tx.vin[0].type() == typeid(cryptonote::txin_gen))
{
const cryptonote::txin_gen &txin_gen = boost::get<cryptonote::txin_gen>(b.miner_tx.vin[0]);
if (txin_gen.height != 202612)
return true;
}
// EXCEPTION FOR BLOCK 202612
const std::string correct_blob_hash_202612 = "3a8a2b3a29b50fc86ff73dd087ea43c6f0d6b8f936c849194d5c84c737903966";
const std::string existing_block_id_202612 = "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698";
crypto::hash block_blob_hash = get_blob_hash(*blob);
if (string_tools::pod_to_hex(block_blob_hash) == correct_blob_hash_202612)
{
string_tools::hex_to_pod(existing_block_id_202612, res);
return true;
}
{
// make sure that we aren't looking at a block with the 202612 block id but not the correct blobdata
if (string_tools::pod_to_hex(res) == existing_block_id_202612)
{
LOG_ERROR("Block with block id for 202612 but incorrect block blob hash found!");
res = null_hash;
return false;
}
}
return hash_result;
return get_object_hash(get_block_hashing_blob(b), res);
}
//---------------------------------------------------------------
bool get_block_hash(const block& b, crypto::hash& res)

View File

@@ -48,6 +48,8 @@ namespace epee
namespace cryptonote
{
//---------------------------------------------------------------
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h, hw::device &hwdev);
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx, hw::device &hwdev);
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
bool parse_and_validate_tx_prefix_from_blob(const blobdata& tx_blob, transaction_prefix& tx);

View File

@@ -33,6 +33,7 @@
#include <cstddef>
#include <cstdint>
#include <vector>
#include <boost/math/special_functions/round.hpp>
#include "int-util.h"
#include "crypto/hash.h"
@@ -254,4 +255,180 @@ namespace cryptonote {
return "0x" + s;
}
// LWMA difficulty algorithm
// Background: https://github.com/zawy12/difficulty-algorithms/issues/3
// Copyright (c) 2017-2018 Zawy
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
const int64_t T = static_cast<int64_t>(target_seconds);
size_t N = DIFFICULTY_WINDOW_V2;
if (timestamps.size() < 4) {
return 1;
} else if ( timestamps.size() < N+1 ) {
N = timestamps.size() - 1;
} else {
timestamps.resize(N+1);
cumulative_difficulties.resize(N+1);
}
const double adjust = 0.998;
const double k = N * (N + 1) / 2;
double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0);
int64_t solveTime(0);
uint64_t difficulty(0), next_difficulty(0);
for (size_t i = 1; i <= N; i++) {
solveTime = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i - 1]);
solveTime = std::min<int64_t>((T * 7), std::max<int64_t>(solveTime, (-7 * T)));
difficulty = static_cast<uint64_t>(cumulative_difficulties[i] - cumulative_difficulties[i - 1]);
LWMA += (int64_t)(solveTime * i) / k;
sum_inverse_D += 1 / static_cast<double>(difficulty);
}
harmonic_mean_D = N / sum_inverse_D;
if (static_cast<int64_t>(boost::math::round(LWMA)) < T / 20)
LWMA = static_cast<double>(T / 20);
nextDifficulty = harmonic_mean_D * T / LWMA * adjust;
next_difficulty = static_cast<uint64_t>(nextDifficulty);
return next_difficulty;
}
// LWMA-2
difficulty_type next_difficulty_v3(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties) {
int64_t T = DIFFICULTY_TARGET_V2;
int64_t N = DIFFICULTY_WINDOW_V2;
int64_t L(0), ST, sum_3_ST(0), next_D, prev_D;
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= static_cast<uint64_t>(N+1) );
for ( int64_t i = 1; i <= N; i++ ) {
ST = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i-1]);
ST = std::max(-4*T, std::min(ST, 6*T));
L += ST * i ;
if ( i > N-3 ) {
sum_3_ST += ST;
}
}
next_D = (static_cast<int64_t>(cumulative_difficulties[N] - cumulative_difficulties[0])*T*(N+1)*99)/(100*2*L);
prev_D = static_cast<int64_t>(cumulative_difficulties[N] - cumulative_difficulties[N-1]);
next_D = std::max((prev_D*67)/100, std::min(next_D, (prev_D*150)/100));
if ( sum_3_ST < (8*T)/10) {
next_D = std::max(next_D,(prev_D*108)/100);
}
return static_cast<uint64_t>(next_D);
}
// LWMA-4
difficulty_type next_difficulty_v4(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t height) {
uint64_t T = DIFFICULTY_TARGET_V2;
uint64_t N = DIFFICULTY_WINDOW_V2;
uint64_t L(0), ST(0), next_D, prev_D, avg_D, i;
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= N+1 );
if ( height <= 63469 + 1 ) { return 100000069; }
std::vector<uint64_t>TS(N+1);
TS[0] = timestamps[0];
for ( i = 1; i <= N; i++) {
if ( timestamps[i] > TS[i-1] ) { TS[i] = timestamps[i]; }
else { TS[i] = TS[i-1]; }
}
for ( i = 1; i <= N; i++) {
if ( i > 4 && TS[i]-TS[i-1] > 5*T && TS[i-1] - TS[i-4] < (14*T)/10 ) { ST = 2*T; }
else if ( i > 7 && TS[i]-TS[i-1] > 5*T && TS[i-1] - TS[i-7] < 4*T ) { ST = 2*T; }
else {
ST = std::min(5*T ,TS[i] - TS[i-1]);
}
L += ST * i ;
}
if (L < N*N*T/20 ) { L = N*N*T/20; }
avg_D = static_cast<uint64_t>(( cumulative_difficulties[N] - cumulative_difficulties[0] )/ N);
if (avg_D > 2000000*N*N*T) {
next_D = (avg_D/(200*L))*(N*(N+1)*T*97);
}
else { next_D = (avg_D*N*(N+1)*T*97)/(200*L); }
prev_D = static_cast<uint64_t>(cumulative_difficulties[N] - cumulative_difficulties[N-1]);
if ( ( TS[N] - TS[N-1] < (2*T)/10 ) ||
( TS[N] - TS[N-2] < (5*T)/10 ) ||
( TS[N] - TS[N-3] < (8*T)/10 ) )
{
next_D = std::max( next_D, std::min( (prev_D*110)/100, (105*avg_D)/100 ) );
}
i = 1000000000;
while (i > 1) {
if ( next_D > i*100 ) { next_D = ((next_D+i/2)/i)*i; break; }
else { i /= 10; }
}
if ( next_D > 100000 ) {
next_D = ((next_D+500)/1000)*1000 + std::min(static_cast<uint64_t>(999), (TS[N]-TS[N-10])/10);
}
return static_cast<uint64_t>(next_D);
}
// LWMA-1 difficulty algorithm
// Copyright (c) 2017-2019 Zawy, MIT License
// https://github.com/zawy12/difficulty-algorithms/issues/3
difficulty_type next_difficulty_v5(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t T, uint64_t N, uint64_t HEIGHT) {
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= N+1 );
if (HEIGHT >= 81769 && HEIGHT < 81769 + N) { return 10000000; }
assert(timestamps.size() == N+1);
uint64_t L(0), next_D, i, this_timestamp(0), previous_timestamp(0), avg_D;
previous_timestamp = timestamps[0]-T;
for ( i = 1; i <= N; i++) {
// Safely prevent out-of-sequence timestamps
if ( timestamps[i] > previous_timestamp ) { this_timestamp = timestamps[i]; }
else { this_timestamp = previous_timestamp+1; }
L += i*std::min(6*T ,this_timestamp - previous_timestamp);
previous_timestamp = this_timestamp;
}
if (L < N*N*T/20 ) { L = N*N*T/20; }
avg_D = static_cast<uint64_t>(( cumulative_difficulties[N] - cumulative_difficulties[0] )/ N);
// Prevent round off error for small D and overflow for large D.
if (avg_D > 2000000*N*N*T) {
next_D = (avg_D/(200*L))*(N*(N+1)*T*99);
}
else { next_D = (avg_D*N*(N+1)*T*99)/(200*L); }
// Make all insignificant digits zero for easy reading.
i = 1000000000;
while (i > 1) {
if ( next_D > i*100 ) { next_D = ((next_D+i/2)/i)*i; break; }
else { i /= 10; }
}
return next_D;
}
difficulty_type next_difficulty_test(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t T, uint64_t N, uint64_t HEIGHT) {
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= N+1 );
if (HEIGHT < N) { return 1337; }
assert(timestamps.size() == N+1);
uint64_t L(0), next_D, i, this_timestamp(0), previous_timestamp(0), avg_D;
previous_timestamp = timestamps[0]-T;
for ( i = 1; i <= N; i++) {
// Safely prevent out-of-sequence timestamps
if ( timestamps[i] > previous_timestamp ) { this_timestamp = timestamps[i]; }
else { this_timestamp = previous_timestamp+1; }
L += i*std::min(6*T ,this_timestamp - previous_timestamp);
previous_timestamp = this_timestamp;
}
if (L < N*N*T/20 ) { L = N*N*T/20; }
avg_D = static_cast<uint64_t>(( cumulative_difficulties[N] - cumulative_difficulties[0] )/ N);
// Prevent round off error for small D and overflow for large D.
if (avg_D > 2000000*N*N*T) {
next_D = (avg_D/(200*L))*(N*(N+1)*T*99);
}
else { next_D = (avg_D*N*(N+1)*T*99)/(200*L); }
// Make all insignificant digits zero for easy reading.
i = 1000000000;
while (i > 1) {
if ( next_D > i*100 ) { next_D = ((next_D+i/2)/i)*i; break; }
else { i /= 10; }
}
return next_D;
}
}

View File

@@ -58,6 +58,11 @@ namespace cryptonote
bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty);
bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
difficulty_type next_difficulty_v3(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties);
difficulty_type next_difficulty_v4(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t height);
difficulty_type next_difficulty_v5(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t T, uint64_t N, uint64_t HEIGHT);
difficulty_type next_difficulty_test(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t T, uint64_t N, uint64_t HEIGHT);
std::string hex(difficulty_type v);
}

View File

@@ -144,7 +144,7 @@ namespace cryptonote
m_height = height;
m_block_reward = block_reward;
++m_template_no;
m_starter_nonce = crypto::rand<uint32_t>();
m_starter_nonce = crypto::rand<uint64_t>();
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -375,7 +375,7 @@ namespace cryptonote
m_threads_autodetect.push_back({epee::misc_utils::get_ns_count(), m_total_hashes});
m_threads_total = 1;
}
m_starter_nonce = crypto::rand<uint32_t>();
m_starter_nonce = crypto::rand<uint64_t>();
CRITICAL_REGION_LOCAL(m_threads_lock);
if(is_mining())
{
@@ -473,7 +473,7 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------------
bool miner::find_nonce_for_given_block(const get_block_hash_t &gbh, block& bl, const difficulty_type& diffic, uint64_t height)
{
for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
for(; bl.nonce != std::numeric_limits<uint64_t>::max(); bl.nonce++)
{
crypto::hash h;
gbh(bl, height, diffic <= 100 ? 0 : tools::get_max_concurrency(), h);
@@ -524,7 +524,7 @@ namespace cryptonote
uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
MLOG_SET_THREAD_NAME(std::string("[miner ") + std::to_string(th_local_index) + "]");
MGINFO("Miner thread was started ["<< th_local_index << "]");
uint32_t nonce = m_starter_nonce + th_local_index;
uint64_t nonce = m_starter_nonce + th_local_index;
uint64_t height = 0;
difficulty_type local_diff = 0;
uint32_t local_template_ver = 0;

View File

@@ -123,7 +123,7 @@ namespace cryptonote
epee::critical_section m_template_lock;
block m_template;
std::atomic<uint32_t> m_template_no;
std::atomic<uint32_t> m_starter_nonce;
std::atomic<uint64_t> m_starter_nonce;
difficulty_type m_diffic;
uint64_t m_height;
volatile uint32_t m_thread_index;

View File

@@ -29,6 +29,9 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include "cryptonote_protocol/enums.h"
namespace cryptonote
{
/************************************************************************/
@@ -36,7 +39,9 @@ namespace cryptonote
/************************************************************************/
struct tx_verification_context
{
bool m_should_be_relayed;
static_assert(unsigned(relay_method::none) == 0, "default m_relay initialization is not to relay_method::none");
relay_method m_relay; // gives indication on how tx should be relayed (if at all)
bool m_verifivation_failed; //bad tx, should drop connection
bool m_verifivation_impossible; //the transaction is related with an alternative blockchain
bool m_added_to_pool;

View File

@@ -43,17 +43,19 @@
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
#define CURRENT_TRANSACTION_VERSION 2
#define CURRENT_BLOCK_MAJOR_VERSION 1
#define CURRENT_BLOCK_MINOR_VERSION 0
#define CURRENT_BLOCK_MAJOR_VERSION 7
#define CURRENT_BLOCK_MINOR_VERSION 7
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V2 300*2
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE 10
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE 4
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V2 11
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW 60
// MONEY_SUPPLY - total number coins to be generated
#define MONEY_SUPPLY ((uint64_t)(-1))
#define EMISSION_SPEED_FACTOR_PER_MINUTE (20)
#define FINAL_SUBSIDY_PER_MINUTE ((uint64_t)300000000000) // 3 * pow(10, 11)
#define EMISSION_SPEED_FACTOR_PER_MINUTE (24)
#define FINAL_SUBSIDY_PER_MINUTE ((uint64_t)(0))
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW 100
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 60000 //size of block (bytes) after which reward for block calculated using block size
@@ -62,9 +64,9 @@
#define CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE 100000 // size in blocks of the long term block weight median window
#define CRYPTONOTE_SHORT_TERM_BLOCK_WEIGHT_SURGE_FACTOR 50
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE 600
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT 12
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT 11
// COIN - number of smallest units in one coin
#define COIN ((uint64_t)1000000000000) // pow(10, 12)
#define COIN ((uint64_t)100000000000) // pow(10, 11)
#define FEE_PER_KB_OLD ((uint64_t)10000000000) // pow(10, 10)
#define FEE_PER_KB ((uint64_t)2000000000) // 2 * pow(10, 9)
@@ -77,14 +79,17 @@
#define ORPHANED_BLOCKS_MAX_COUNT 100
#define DIFFICULTY_TARGET_V2 120 // seconds
#define DIFFICULTY_TARGET_V1 60 // seconds - before first fork
#define DIFFICULTY_TARGET_V2 300
#define DIFFICULTY_TARGET_V1 300
#define DIFFICULTY_WINDOW_V3 144
#define DIFFICULTY_WINDOW_V2 60
#define DIFFICULTY_WINDOW 720 // blocks
#define DIFFICULTY_LAG 15 // !!!
#define DIFFICULTY_CUT 60 // timestamps to cut after sorting
#define DIFFICULTY_BLOCKS_COUNT_V3 DIFFICULTY_WINDOW_V3 + 1 // added +1 to make N=N
#define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2 + 1 // added +1 to make N=N
#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 DIFFICULTY_TARGET_V1 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 DIFFICULTY_TARGET_V2 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS 1
@@ -102,7 +107,12 @@
#define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week
#define CRYPTONOTE_DANDELIONPP_FLUSH_AVERAGE 5 // seconds
#define CRYPTONOTE_DANDELIONPP_STEMS 2 // number of outgoing stem connections per epoch
#define CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY 10 // out of 100
#define CRYPTONOTE_DANDELIONPP_MIN_EPOCH 10 // minutes
#define CRYPTONOTE_DANDELIONPP_EPOCH_RANGE 30 // seconds
#define CRYPTONOTE_DANDELIONPP_FLUSH_AVERAGE 5 // seconds average for poisson distributed fluff flush
#define CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE 173 // seconds (see tx_pool.cpp for more info)
// see src/cryptonote_protocol/levin_notify.cpp
#define CRYPTONOTE_NOISE_MIN_EPOCH 5 // minutes
@@ -144,7 +154,7 @@
#define RPC_IP_FAILS_BEFORE_BLOCK 3
#define CRYPTONOTE_NAME "bitmonero"
#define CRYPTONOTE_NAME "wownero"
#define CRYPTONOTE_POOLDATA_FILENAME "poolstate.bin"
#define CRYPTONOTE_BLOCKCHAINDATA_FILENAME "data.mdb"
#define CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME "lock.mdb"
@@ -156,18 +166,19 @@
#define HF_VERSION_DYNAMIC_FEE 4
#define HF_VERSION_MIN_MIXIN_4 6
#define HF_VERSION_MIN_MIXIN_6 7
#define HF_VERSION_MIN_MIXIN_10 8
#define HF_VERSION_MIN_MIXIN_7 7
#define HF_VERSION_MIN_MIXIN_21 9
#define HF_VERSION_ENFORCE_RCT 6
#define HF_VERSION_PER_BYTE_FEE 8
#define HF_VERSION_SMALLER_BP 10
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT 10
#define HF_VERSION_MIN_2_OUTPUTS 12
#define HF_VERSION_MIN_V2_COINBASE_TX 12
#define HF_VERSION_SAME_MIXIN 12
#define HF_VERSION_REJECT_SIGS_IN_COINBASE 12
#define HF_VERSION_ENFORCE_MIN_AGE 12
#define HF_VERSION_EFFECTIVE_SHORT_TERM_MEDIAN_IN_PENALTY 12
#define HF_VERSION_PER_BYTE_FEE 12
#define HF_VERSION_SMALLER_BP 13
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT 13
#define HF_VERSION_MIN_2_OUTPUTS 15
#define HF_VERSION_MIN_V2_COINBASE_TX 15
#define HF_VERSION_SAME_MIXIN 15
#define HF_VERSION_REJECT_SIGS_IN_COINBASE 15
#define HF_VERSION_ENFORCE_MIN_AGE 15
#define HF_VERSION_EFFECTIVE_SHORT_TERM_MEDIAN_IN_PENALTY 15
#define HF_VERSION_SHA3_POW 16 // Block 288,888 ~8 February 2021, depends on availability of open source sha-3 fpga designs
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
@@ -192,17 +203,17 @@ namespace config
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)
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 18;
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 19;
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 42;
uint16_t const P2P_DEFAULT_PORT = 18080;
uint16_t const RPC_DEFAULT_PORT = 18081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 18082;
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 4146;
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 6810;
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 12208;
uint16_t const P2P_DEFAULT_PORT = 34567;
uint16_t const RPC_DEFAULT_PORT = 34568;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 34569;
boost::uuids::uuid const NETWORK_ID = { {
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10
0x11, 0x33, 0xFF, 0x77 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10
} }; // Bender's nightmare
std::string const GENESIS_TX = "013c01ff0001ffffffffffff03029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121017767aafcde9be00dcfd098715ebcf7f410daebc582fda69d24a28e9d0bc890d1";
uint32_t const GENESIS_NONCE = 10000;
std::string const GENESIS_TX = "013c01ff0001ffffffffff1f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121012a1a936be5d91c01ee876e38c13fab0ee11cbe86011a2bf7740fb5ebd39d267d";
uint32_t const GENESIS_NONCE = 70;
// Hash domain separators
const char HASH_KEY_BULLETPROOF_EXPONENT[] = "bulletproof";
@@ -220,14 +231,14 @@ namespace config
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 53;
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 54;
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 63;
uint16_t const P2P_DEFAULT_PORT = 28080;
uint16_t const RPC_DEFAULT_PORT = 28081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 28082;
uint16_t const P2P_DEFAULT_PORT = 11180;
uint16_t const RPC_DEFAULT_PORT = 11181;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 11182;
boost::uuids::uuid const NETWORK_ID = { {
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x11
0x11, 0x33, 0xFF, 0x77 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x11
} }; // Bender's daydream
std::string const GENESIS_TX = "013c01ff0001ffffffffffff03029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121017767aafcde9be00dcfd098715ebcf7f410daebc582fda69d24a28e9d0bc890d1";
uint32_t const GENESIS_NONCE = 10001;
std::string const GENESIS_TX = "013c01ff0001ffffffffff1f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd088071210160eb755f618a2336055dee60f307fe0ded81c5b37b53d310175ca9ee69b0c8ad";
uint32_t const GENESIS_NONCE = 70;
}
namespace stagenet

View File

@@ -86,7 +86,7 @@ DISABLE_VS_WARNINGS(4267)
//------------------------------------------------------------------
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_weight_limit(0), m_current_block_cumul_weight_median(0),
m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_reset_timestamps_and_difficulties_height(true), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0),
m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false),
m_long_term_block_weights_window(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
m_long_term_effective_median_block_weight(0),
@@ -305,9 +305,9 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
if (m_nettype == FAKECHAIN || m_nettype == STAGENET)
m_hardfork = new HardFork(*db, 1, 0);
else if (m_nettype == TESTNET)
m_hardfork = new HardFork(*db, 1, testnet_hard_fork_version_1_till);
m_hardfork = new HardFork(*db, 1, 0);
else
m_hardfork = new HardFork(*db, 1, mainnet_hard_fork_version_1_till);
m_hardfork = new HardFork(*db, 1, 0);
}
if (m_nettype == FAKECHAIN)
{
@@ -365,9 +365,9 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
uint64_t top_block_timestamp = m_db->get_top_block_timestamp();
uint64_t timestamp_diff = time(NULL) - top_block_timestamp;
// genesis block has no timestamp, could probably change it to have timestamp of 1397818133...
// genesis block has no timestamp, could probably change it to have timestamp of 1522624244 (2018-04-01 23:10:44, block 1)...
if(!top_block_timestamp)
timestamp_diff = time(NULL) - 1397818133;
timestamp_diff = time(NULL) - 1522624244;
// create general purpose async service queue
@@ -427,6 +427,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
if (num_popped_blocks > 0)
{
m_timestamps_and_difficulties_height = 0;
m_reset_timestamps_and_difficulties_height = true;
m_hardfork->reorganize_from_chain_height(get_current_blockchain_height());
uint64_t top_block_height;
crypto::hash top_block_hash = get_tail_id(top_block_height);
@@ -567,6 +568,7 @@ block Blockchain::pop_block_from_blockchain()
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
m_reset_timestamps_and_difficulties_height = true;
block popped_block;
std::vector<transaction> popped_txs;
@@ -644,6 +646,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
m_reset_timestamps_and_difficulties_height = true;
invalidate_block_template_cache();
m_db->reset();
m_db->drop_alt_blocks();
@@ -812,12 +815,20 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
// less blocks than desired if there aren't enough.
difficulty_type Blockchain::get_difficulty_for_next_block()
{
LOG_PRINT_L3("Blockchain::" << __func__);
std::stringstream ss;
bool print = false;
int done = 0;
ss << "get_difficulty_for_next_block: height " << m_db->height() << std::endl;
if (m_fixed_difficulty)
{
return m_db->height() ? m_fixed_difficulty : 1;
}
LOG_PRINT_L3("Blockchain::" << __func__);
start:
difficulty_type D = 0;
crypto::hash top_hash = get_tail_id();
{
@@ -826,39 +837,56 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
// something a bit out of date, but that's fine since anything which
// requires the blockchain lock will have acquired it in the first place,
// and it will be unlocked only when called from the getinfo RPC
ss << "Locked, tail id " << top_hash << ", cached is " << m_difficulty_for_next_block_top_hash << std::endl;
if (top_hash == m_difficulty_for_next_block_top_hash)
return m_difficulty_for_next_block;
{
ss << "Same, using cached diff " << m_difficulty_for_next_block << std::endl;
D = m_difficulty_for_next_block;
}
}
CRITICAL_REGION_LOCAL(m_blockchain_lock);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties;
uint64_t height;
top_hash = get_tail_id(height); // get it again now that we have the lock
++height; // top block height to blockchain height
auto new_top_hash = get_tail_id(height); // get it again now that we have the lock
++height;
uint8_t version = get_current_hard_fork_version();
uint64_t difficulty_blocks_count = version >= 11 ? DIFFICULTY_BLOCKS_COUNT_V3 : version <= 10 && version >= 8 ? DIFFICULTY_BLOCKS_COUNT_V2 : DIFFICULTY_BLOCKS_COUNT;
if (!(new_top_hash == top_hash)) D=0;
ss << "Re-locked, height " << height << ", tail id " << new_top_hash << (new_top_hash == top_hash ? "" : " (different)") << std::endl;
top_hash = new_top_hash;
// ND: Speedup
// 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
// then when the next block difficulty is queried, push the latest height data and
// pop the oldest one from the list. This only requires 1x read per height instead
// of doing 735 (DIFFICULTY_BLOCKS_COUNT).
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= DIFFICULTY_BLOCKS_COUNT)
bool check = false;
if (m_reset_timestamps_and_difficulties_height)
m_timestamps_and_difficulties_height = 0;
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficulty_blocks_count)
{
uint64_t index = height - 1;
m_timestamps.push_back(m_db->get_block_timestamp(index));
m_difficulties.push_back(m_db->get_block_cumulative_difficulty(index));
while (m_timestamps.size() > DIFFICULTY_BLOCKS_COUNT)
while (m_timestamps.size() > difficulty_blocks_count)
m_timestamps.erase(m_timestamps.begin());
while (m_difficulties.size() > DIFFICULTY_BLOCKS_COUNT)
while (m_difficulties.size() > difficulty_blocks_count)
m_difficulties.erase(m_difficulties.begin());
m_timestamps_and_difficulties_height = height;
timestamps = m_timestamps;
difficulties = m_difficulties;
check = true;
}
else
//else
std::vector<uint64_t> timestamps_from_cache = timestamps;
std::vector<difficulty_type> difficulties_from_cache = difficulties;
{
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(DIFFICULTY_BLOCKS_COUNT));
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(difficulty_blocks_count));
if (offset == 0)
++offset;
@@ -869,27 +897,96 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
timestamps.reserve(height - offset);
difficulties.reserve(height - offset);
}
ss << "Looking up " << (height - offset) << " from " << offset << std::endl;
for (; offset < height; offset++)
{
timestamps.push_back(m_db->get_block_timestamp(offset));
difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
}
if (check) if (timestamps != timestamps_from_cache || difficulties !=difficulties_from_cache)
{
ss << "Inconsistency XXX:" << std::endl;
ss << "top hash: "<<top_hash << std::endl;
ss << "timestamps: " << timestamps_from_cache.size() << " from cache, but " << timestamps.size() << " without" << std::endl;
ss << "difficulties: " << difficulties_from_cache.size() << " from cache, but " << difficulties.size() << " without" << std::endl;
ss << "timestamps_from_cache:" << std::endl; for (const auto &v :timestamps_from_cache) ss << " " << v << std::endl;
ss << "timestamps:" << std::endl; for (const auto &v :timestamps) ss << " " << v << std::endl;
ss << "difficulties_from_cache:" << std::endl; for (const auto &v :difficulties_from_cache) ss << " " << v << std::endl;
ss << "difficulties:" << std::endl; for (const auto &v :difficulties) ss << " " << v << std::endl;
uint64_t dbh = m_db->height();
uint64_t sh = dbh < 10000 ? 0 : dbh - 10000;
ss << "History from -10k at :" << dbh << ", from " << sh << std::endl;
for (uint64_t h = sh; h < dbh; ++h)
{
uint64_t ts = m_db->get_block_timestamp(h);
difficulty_type d = m_db->get_block_cumulative_difficulty(h);
ss << " " << h << " " << ts << " " << d << std::endl;
}
print = true;
}
m_timestamps_and_difficulties_height = height;
m_timestamps = timestamps;
m_difficulties = difficulties;
}
size_t target = get_difficulty_target();
uint64_t T = DIFFICULTY_TARGET_V2;
uint64_t N = DIFFICULTY_WINDOW_V3;
uint64_t HEIGHT = m_db->height();
difficulty_type diff = next_difficulty(timestamps, difficulties, target);
if (m_nettype == MAINNET) {
if (version >= 11) {
diff = next_difficulty_v5(timestamps, difficulties, T, N, HEIGHT);
} else if (version == 10) {
diff = next_difficulty_v4(timestamps, difficulties, height);
} else if (version == 9) {
diff = next_difficulty_v3(timestamps, difficulties);
} else if (version == 8) {
diff = next_difficulty_v2(timestamps, difficulties, target);
} else {
diff = next_difficulty(timestamps, difficulties, target);
}
}
if (m_nettype == TESTNET) {
diff = next_difficulty_test(timestamps, difficulties, T, N, HEIGHT);
}
CRITICAL_REGION_LOCAL1(m_difficulty_lock);
m_difficulty_for_next_block_top_hash = top_hash;
m_difficulty_for_next_block = diff;
if (D && D != diff)
{
ss << "XXX Mismatch at " << height << "/" << top_hash << "/" << get_tail_id() << ": cached " << D << ", real " << diff << std::endl;
print = true;
}
++done;
if (done == 1 && D && D != diff)
{
print = true;
ss << "Might be a race. Let's see what happens if we try again..." << std::endl;
epee::misc_utils::sleep_no_w(100);
goto start;
}
ss << "Diff for " << top_hash << ": " << diff << std::endl;
if (print)
{
MGINFO("START DUMP");
MGINFO(ss.str());
MGINFO("END DUMP");
MGINFO("Please send moneromooo on Freenode the contents of this log, from a couple dozen lines before START DUMP to END DUMP");
}
return diff;
}
//------------------------------------------------------------------
std::vector<time_t> Blockchain::get_last_block_timestamps(unsigned int blocks) const
{
CRITICAL_REGION_LOCAL(m_blockchain_lock);
uint64_t height = m_db->height();
if (blocks > height)
blocks = height;
@@ -914,6 +1011,7 @@ bool Blockchain::rollback_blockchain_switching(std::list<block>& original_chain,
}
m_timestamps_and_difficulties_height = 0;
m_reset_timestamps_and_difficulties_height = true;
// remove blocks from blockchain until we get back to where we should be.
while (m_db->height() != rollback_height)
@@ -950,6 +1048,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
m_reset_timestamps_and_difficulties_height = true;
// if empty alt chain passed (not sure how that could happen), return false
CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed");
@@ -1066,15 +1165,19 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> cumulative_difficulties;
uint8_t version = get_current_hard_fork_version();
size_t height = m_db->height();
size_t difficulty_blocks_count = version >= 11 ? DIFFICULTY_BLOCKS_COUNT_V3 : version <= 10 && version >= 8 ? DIFFICULTY_BLOCKS_COUNT_V2 : DIFFICULTY_BLOCKS_COUNT;
// if the alt chain isn't long enough to calculate the difficulty target
// based on its blocks alone, need to get more blocks from the main chain
if(alt_chain.size()< DIFFICULTY_BLOCKS_COUNT)
if(alt_chain.size()< difficulty_blocks_count)
{
CRITICAL_REGION_LOCAL(m_blockchain_lock);
// Figure out start and stop offsets for main chain blocks
size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front().height : bei.height;
size_t main_chain_count = DIFFICULTY_BLOCKS_COUNT - std::min(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT), alt_chain.size());
size_t main_chain_count = difficulty_blocks_count - std::min(static_cast<size_t>(difficulty_blocks_count), alt_chain.size());
main_chain_count = std::min(main_chain_count, main_chain_stop_offset);
size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count;
@@ -1089,7 +1192,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
}
// make sure we haven't accidentally grabbed too many blocks...maybe don't need this check?
CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= DIFFICULTY_BLOCKS_COUNT, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << DIFFICULTY_BLOCKS_COUNT);
CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= difficulty_blocks_count, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << difficulty_blocks_count);
for (const auto &bei : alt_chain)
{
@@ -1101,8 +1204,8 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
// and timestamps from it alone
else
{
timestamps.resize(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT));
cumulative_difficulties.resize(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT));
timestamps.resize(static_cast<size_t>(difficulty_blocks_count));
cumulative_difficulties.resize(static_cast<size_t>(difficulty_blocks_count));
size_t count = 0;
size_t max_i = timestamps.size()-1;
// get difficulties and timestamps from most recent blocks in alt chain
@@ -1111,16 +1214,35 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
timestamps[max_i - count] = bei.bl.timestamp;
cumulative_difficulties[max_i - count] = bei.cumulative_difficulty;
count++;
if(count >= DIFFICULTY_BLOCKS_COUNT)
if(count >= difficulty_blocks_count)
break;
}
}
// FIXME: This will fail if fork activation heights are subject to voting
size_t target = get_ideal_hard_fork_version(bei.height) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
uint64_t T = DIFFICULTY_TARGET_V2;
uint64_t N = DIFFICULTY_WINDOW_V3;
uint64_t HEIGHT = m_db->height();
// calculate the difficulty target for the block and return it
return next_difficulty(timestamps, cumulative_difficulties, target);
if (m_nettype == MAINNET) {
if (version >= 11) {
return next_difficulty_v5(timestamps, cumulative_difficulties, T, N, HEIGHT);
} else if (version == 10) {
return next_difficulty_v4(timestamps, cumulative_difficulties, height);
} else if (version == 9) {
return next_difficulty_v3(timestamps, cumulative_difficulties);
} else if (version == 8) {
return next_difficulty_v2(timestamps, cumulative_difficulties, target);
} else {
return next_difficulty(timestamps, cumulative_difficulties, target);
}
}
if (m_nettype == TESTNET) {
return next_difficulty_test(timestamps, cumulative_difficulties, T, N, HEIGHT);
}
}
//------------------------------------------------------------------
// This function does a sanity check on basic things that all miner
@@ -1556,12 +1678,13 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
bool Blockchain::complete_timestamps_vector(uint64_t start_top_height, std::vector<uint64_t>& timestamps) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
if(timestamps.size() >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
uint8_t version = get_current_hard_fork_version();
size_t blockchain_timestamp_check_window = version >= 10 ? BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V2 : BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
if(timestamps.size() >= blockchain_timestamp_check_window)
return true;
CRITICAL_REGION_LOCAL(m_blockchain_lock);
size_t need_elements = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - timestamps.size();
size_t need_elements = blockchain_timestamp_check_window - timestamps.size();
CHECK_AND_ASSERT_MES(start_top_height < m_db->height(), false, "internal error: passed start_height not < " << " m_db->height() -- " << start_top_height << " >= " << m_db->height());
size_t stop_offset = start_top_height > need_elements ? start_top_height - need_elements : 0;
timestamps.reserve(timestamps.size() + start_top_height - stop_offset);
@@ -1639,6 +1762,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0;
m_reset_timestamps_and_difficulties_height = true;
uint64_t block_height = get_block_height(b);
if(0 == block_height)
{
@@ -1710,7 +1834,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!");
crypto::hash proof_of_work;
memset(proof_of_work.data, 0xff, sizeof(proof_of_work.data));
if (b.major_version >= RX_BLOCK_VERSION)
if (b.major_version >= RX_BLOCK_VERSION && b.major_version < HF_VERSION_SHA3_POW)
{
crypto::hash seedhash = null_hash;
uint64_t seedheight = rx_seedheight(bei.height);
@@ -2494,37 +2618,10 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
db_rtxn_guard rtxn_guard(m_db);
total_height = get_current_blockchain_height();
size_t count = 0, size = 0;
blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height)));
for(uint64_t i = start_height; i < total_height && count < max_count && (size < FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE || count < 3); i++, count++)
{
blocks.resize(blocks.size()+1);
blocks.back().first.first = m_db->get_block_blob_from_height(i);
block b;
CHECK_AND_ASSERT_MES(parse_and_validate_block_from_blob(blocks.back().first.first, b), false, "internal error, invalid block");
blocks.back().first.second = get_miner_tx_hash ? cryptonote::get_transaction_hash(b.miner_tx) : crypto::null_hash;
std::vector<cryptonote::blobdata> txs;
if (pruned)
{
CHECK_AND_ASSERT_MES(m_db->get_pruned_tx_blobs_from(b.tx_hashes.front(), b.tx_hashes.size(), txs), false, "Failed to retrieve all transactions needed");
}
else
{
std::vector<crypto::hash> mis;
get_transactions_blobs(b.tx_hashes, txs, mis, pruned);
CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found");
}
size += blocks.back().first.first.size();
for (const auto &t: txs)
size += t.size();
CHECK_AND_ASSERT_MES(m_db->get_blocks_from(start_height, 3, max_count, FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE, blocks, pruned, true, get_miner_tx_hash),
false, "Error getting blocks");
CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size(), false, "mismatched sizes of b.tx_hashes and txs");
blocks.back().second.reserve(txs.size());
for (size_t i = 0; i < txs.size(); ++i)
{
blocks.back().second.push_back(std::make_pair(b.tx_hashes[i], std::move(txs[i])));
}
}
return true;
}
//------------------------------------------------------------------
@@ -2802,27 +2899,27 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type);
if (bulletproof || !tx.rct_signatures.p.bulletproofs.empty())
{
MERROR_VER("Bulletproofs are not allowed before v8");
MERROR_VER("New Bulletproofs are not allowed before v8");
tvc.m_invalid_output = true;
return false;
}
}
}
// from v9, forbid borromean range proofs
if (hf_version > 8) {
// from v12, forbid borromean range proofs
if (hf_version > 11) {
if (tx.version >= 2) {
const bool borromean = rct::is_rct_borromean(tx.rct_signatures.type);
if (borromean)
{
MERROR_VER("Borromean range proofs are not allowed after v8");
MERROR_VER("Borromean range proofs are not allowed after v11");
tvc.m_invalid_output = true;
return false;
}
}
}
// from v10, allow bulletproofs v2
// from v13, allow bulletproofs v2
if (hf_version < HF_VERSION_SMALLER_BP) {
if (tx.version >= 2) {
if (tx.rct_signatures.type == rct::RCTTypeBulletproof2)
@@ -2834,7 +2931,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
// from v11, allow only bulletproofs v2
// from v14, allow only bulletproofs v2
if (hf_version > HF_VERSION_SMALLER_BP) {
if (tx.version >= 2) {
if (tx.rct_signatures.type == rct::RCTTypeBulletproof)
@@ -2846,6 +2943,19 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
// from v12, forbid old bulletproofs
if (hf_version > 11) {
if (tx.version >= 2) {
const bool old_bulletproof = rct::is_rct_old_bulletproof(tx.rct_signatures.type);
if (old_bulletproof)
{
MERROR_VER("Old Bulletproofs are not allowed after v11");
tvc.m_invalid_output = true;
return false;
}
}
}
return true;
}
//------------------------------------------------------------------
@@ -2871,7 +2981,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
rv.message = rct::hash2rct(tx_prefix_hash);
// mixRing - full and simple store it in opposite ways
if (rv.type == rct::RCTTypeFull)
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
{
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys[0].size());
@@ -2886,7 +2996,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
}
}
}
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2)
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeSimpleBulletproof)
{
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys.size());
@@ -2905,7 +3015,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
}
// II
if (rv.type == rct::RCTTypeFull)
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
{
if (!tx.pruned)
{
@@ -2915,7 +3025,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
}
}
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2)
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeSimpleBulletproof)
{
if (!tx.pruned)
{
@@ -2978,7 +3088,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
size_t n_unmixable = 0, n_mixable = 0;
size_t min_actual_mixin = std::numeric_limits<size_t>::max();
size_t max_actual_mixin = 0;
const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_10 ? 10 : hf_version >= HF_VERSION_MIN_MIXIN_6 ? 6 : hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 2;
const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_21 ? 21 : hf_version >= HF_VERSION_MIN_MIXIN_7 ? 7 : hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 2;
for (const auto& txin : tx.vin)
{
// non txin_to_key inputs will be rejected below
@@ -3021,9 +3131,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
if (((hf_version == HF_VERSION_MIN_MIXIN_10 || hf_version == HF_VERSION_MIN_MIXIN_10+1) && min_actual_mixin != 10) || (hf_version >= HF_VERSION_MIN_MIXIN_10+2 && min_actual_mixin > 10))
if (((hf_version == HF_VERSION_MIN_MIXIN_21 || hf_version == HF_VERSION_MIN_MIXIN_21+1) && min_actual_mixin != 21) || (hf_version >= HF_VERSION_MIN_MIXIN_21+2 && min_actual_mixin > 21))
{
MERROR_VER("Tx " << get_transaction_hash(tx) << " has invalid ring size (" << (min_actual_mixin + 1) << "), it should be 11");
MERROR_VER("Tx " << get_transaction_hash(tx) << " has invalid ring size (" << (min_actual_mixin + 1) << "), it should be 22");
tvc.m_low_mixin = true;
return false;
}
@@ -3206,6 +3316,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
return false;
}
case rct::RCTTypeSimple:
case rct::RCTTypeSimpleBulletproof:
case rct::RCTTypeBulletproof:
case rct::RCTTypeBulletproof2:
{
@@ -3265,6 +3376,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
break;
}
case rct::RCTTypeFull:
case rct::RCTTypeFullBulletproof:
{
// check all this, either reconstructed (so should really pass), or not
{
@@ -3600,10 +3712,11 @@ bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const
{
LOG_PRINT_L3("Blockchain::" << __func__);
median_ts = epee::misc_utils::median(timestamps);
uint8_t version = get_current_hard_fork_version();
size_t blockchain_timestamp_check_window = version >= 10 ? BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V2 : BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
if(b.timestamp < median_ts)
{
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", less than median of last " << BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW << " blocks, " << median_ts);
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", less than median of last " << blockchain_timestamp_check_window << " blocks, " << median_ts);
return false;
}
@@ -3620,16 +3733,20 @@ bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const
bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
if(b.timestamp > get_adjusted_time() + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT)
uint8_t version = get_current_hard_fork_version();
uint64_t cryptonote_block_future_time_limit = version >= 8 ? CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V2 : CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT;
size_t blockchain_timestamp_check_window = version >= 10 ? BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V2 : BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
if(b.timestamp > get_adjusted_time() + cryptonote_block_future_time_limit)
{
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + 2 hours");
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + 10 minutes");
return false;
}
const auto h = m_db->height();
// if not enough blocks, no proper median yet, return true
if(h < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
if(h < blockchain_timestamp_check_window)
{
return true;
}
@@ -3637,7 +3754,7 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons
std::vector<uint64_t> timestamps;
// need most recent 60 blocks, get index of first of those
size_t offset = h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
size_t offset = h - blockchain_timestamp_check_window;
timestamps.reserve(h - offset);
for(;offset < h; ++offset)
{
@@ -4345,7 +4462,14 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
try
{
if (m_batch_success)
{
m_db->batch_stop();
if (m_reset_timestamps_and_difficulties_height)
{
m_timestamps_and_difficulties_height = 0;
m_reset_timestamps_and_difficulties_height = false;
}
}
else
m_db->batch_abort();
success = true;
@@ -5056,7 +5180,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "fce1dc7c17f7679f5f447df206b8f5fe2ef6b1a2845e59f650850a0ef00d265f";
static const char expected_block_hashes_hash[] = "45e9e49daeeca39726379eb3f5f4be17c9a2fe9eb1228249b30c00c276fad68a";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)

View File

@@ -1067,6 +1067,7 @@ namespace cryptonote
std::vector<uint64_t> m_timestamps;
std::vector<difficulty_type> m_difficulties;
uint64_t m_timestamps_and_difficulties_height;
bool m_reset_timestamps_and_difficulties_height;
uint64_t m_long_term_block_weights_window;
uint64_t m_long_term_effective_median_block_weight;
mutable crypto::hash m_long_term_block_weights_cache_tip_hash;

View File

@@ -263,14 +263,14 @@ namespace cryptonote
m_blockchain_storage.set_enforce_dns_checkpoints(enforce_dns);
}
//-----------------------------------------------------------------------------------------------
bool core::update_checkpoints()
bool core::update_checkpoints(const bool skip_dns /* = false */)
{
if (m_nettype != MAINNET || m_disable_dns_checkpoints) return true;
if (m_checkpoints_updating.test_and_set()) return true;
bool res = true;
if (time(NULL) - m_last_dns_checkpoints_update >= 3600)
if (!skip_dns && time(NULL) - m_last_dns_checkpoints_update >= 3600)
{
res = m_blockchain_storage.update_checkpoints(m_checkpoints_path, true);
m_last_dns_checkpoints_update = time(NULL);
@@ -428,9 +428,9 @@ namespace cryptonote
return m_blockchain_storage.get_split_transactions_blobs(txs_ids, txs, missed_txs);
}
//-----------------------------------------------------------------------------------------------
bool core::get_txpool_backlog(std::vector<tx_backlog_entry>& backlog) const
bool core::get_txpool_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive_txes) const
{
m_mempool.get_transaction_backlog(backlog);
m_mempool.get_transaction_backlog(backlog, include_sensitive_txes);
return true;
}
//-----------------------------------------------------------------------------------------------
@@ -486,8 +486,8 @@ namespace cryptonote
if (boost::filesystem::exists(old_files / "blockchain.bin"))
{
MWARNING("Found old-style blockchain.bin in " << old_files.string());
MWARNING("Monero now uses a new format. You can either remove blockchain.bin to start syncing");
MWARNING("the blockchain anew, or use monero-blockchain-export and monero-blockchain-import to");
MWARNING("Wownero now uses a new format. You can either remove blockchain.bin to start syncing");
MWARNING("the blockchain anew, or use wownero-blockchain-export and wownero-blockchain-import to");
MWARNING("convert your existing blockchain.bin to the new format. See README.md for instructions.");
return false;
}
@@ -650,7 +650,7 @@ namespace cryptonote
r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty, get_checkpoints);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
r = m_mempool.init(max_txpool_weight);
r = m_mempool.init(max_txpool_weight, m_nettype == FAKECHAIN);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
// now that we have a valid m_blockchain_storage, we can clean out any
@@ -669,7 +669,8 @@ namespace cryptonote
// 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.");
const bool skip_dns_checkpoints = !command_line::get_arg(vm, arg_dns_checkpoints);
CHECK_AND_ASSERT_MES(update_checkpoints(skip_dns_checkpoints), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
// DNS versions checking
if (check_updates_string == "disabled")
@@ -826,6 +827,44 @@ namespace cryptonote
return false;
}
// resolve outPk references in rct txes
// outPk aren't the only thing that need resolving for a fully resolved tx,
// but outPk (1) are needed now to check range proof semantics, and
// (2) do not need access to the blockchain to find data
if (tx.version >= 2)
{
rct::rctSig &rv = tx.rct_signatures;
if (!rct::is_rct_new_bulletproof(rv.type)){
if (rv.outPk.size() != tx.vout.size())
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad outPk size in tx " << tx_hash << ", rejected");
tvc.m_verifivation_failed = true;
return false;
}
for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
const bool bulletproof = rct::is_rct_bulletproof(rv.type);
if (bulletproof)
{
if (rct::n_bulletproof_v1_amounts(rv.p.bulletproofs) != tx.vout.size())
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad bulletproofs size in tx " << tx_hash << ", rejected");
tvc.m_verifivation_failed = true;
return false;
}
size_t idx = 0;
for (size_t n = 0; n < rv.p.bulletproofs.size(); ++n)
{
CHECK_AND_ASSERT_MES(rv.p.bulletproofs[n].L.size() >= 6, false, "Bad bulletproofs L size"); // at least 64 bits
const size_t n_amounts = rct::n_bulletproof_v1_amounts(rv.p.bulletproofs[n]);
CHECK_AND_ASSERT_MES(idx + n_amounts <= rv.outPk.size(), false, "Internal error filling out V");
rv.p.bulletproofs[n].V.clear();
for (size_t i = 0; i < n_amounts; ++i)
rv.p.bulletproofs[n].V.push_back(rv.outPk[idx++].mask);
}
}
}
}
return true;
}
//-----------------------------------------------------------------------------------------------
@@ -884,6 +923,7 @@ namespace cryptonote
tx_info[n].result = false;
break;
case rct::RCTTypeSimple:
case rct::RCTTypeSimpleBulletproof:
if (!rct::verRctSemanticsSimple(rv))
{
MERROR_VER("rct signature semantics check failed");
@@ -894,6 +934,7 @@ namespace cryptonote
}
break;
case rct::RCTTypeFull:
case rct::RCTTypeFullBulletproof:
if (!rct::verRct(rv, true))
{
MERROR_VER("rct signature semantics check failed");
@@ -1149,7 +1190,7 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
size_t core::get_block_sync_size(uint64_t height) const
{
static const uint64_t quick_height = m_nettype == TESTNET ? 801219 : m_nettype == MAINNET ? 1220516 : 0;
static const uint64_t quick_height = m_nettype == TESTNET ? 801219 : m_nettype == MAINNET ? 53666 : 0;
if (block_sync_size > 0)
return block_sync_size;
if (height >= quick_height)
@@ -1284,6 +1325,7 @@ namespace cryptonote
break;
case relay_method::block:
case relay_method::fluff:
case relay_method::stem:
public_req.txs.push_back(std::move(std::get<1>(tx)));
break;
}
@@ -1295,9 +1337,9 @@ namespace cryptonote
re-relaying public and private _should_ be acceptable here. */
const boost::uuids::uuid source = boost::uuids::nil_uuid();
if (!public_req.txs.empty())
get_protocol()->relay_transactions(public_req, source, epee::net_utils::zone::public_);
get_protocol()->relay_transactions(public_req, source, epee::net_utils::zone::public_, relay_method::fluff);
if (!private_req.txs.empty())
get_protocol()->relay_transactions(private_req, source, epee::net_utils::zone::invalid);
get_protocol()->relay_transactions(private_req, source, epee::net_utils::zone::invalid, relay_method::local);
}
return true;
}
@@ -1307,9 +1349,9 @@ namespace cryptonote
std::vector<crypto::hash> tx_hashes{};
tx_hashes.resize(tx_blobs.size());
cryptonote::transaction tx{};
for (std::size_t i = 0; i < tx_blobs.size(); ++i)
{
cryptonote::transaction tx{};
if (!parse_and_validate_tx_from_blob(tx_blobs[i], tx, tx_hashes[i]))
{
LOG_ERROR("Failed to parse relayed transaction");
@@ -1543,9 +1585,9 @@ namespace cryptonote
return m_blockchain_storage.get_db().get_block_cumulative_difficulty(height);
}
//-----------------------------------------------------------------------------------------------
size_t core::get_pool_transactions_count() const
size_t core::get_pool_transactions_count(bool include_sensitive_txes) const
{
return m_mempool.get_transactions_count();
return m_mempool.get_transactions_count(include_sensitive_txes);
}
//-----------------------------------------------------------------------------------------------
bool core::have_block(const crypto::hash& id) const
@@ -1641,9 +1683,34 @@ namespace cryptonote
main_message = "The daemon is running offline and will not attempt to sync to the Monero network.";
else
main_message = "The daemon will start synchronizing with the network. This may take a long time to complete.";
MGINFO_GREEN(ENDL <<
"\n \n"
" ,'``.._ ,'``. \n"
" :,--._:)|,:,._,.: All Glory to \n"
" :`--,'' :`...';| the HYPNO TOAD! \n"
" `,' `---' `. \n"
" / : \n"
" / | \n"
" ,' :|.___,-. \n"
" `...,---'``````-..._ |: | \n"
" ( ) ;: ) | _,-. \n"
" `. ( // `' | \n"
" : `.// ) ) , ; \n"
" ,-|`. _,'/ ) ) ,' ,' \n"
" ( :`.`-..____..=:.-': . _,' ,' \n"
" `,'| ``--....-)=' `._, | ,') _ '``._ \n"
" _.-/ _ `. (WOW) / )' ; / | |`-.' \n"
"`--( `-:`. `' ___..' _,-' |/ `.) \n"
" `-. `.`.``-----``--, .' \n"
" |/`.|`' ,','); \n"
" ` (/ (/ \n"
"\n \n" << ENDL);
MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
<< main_message << ENDL
<< ENDL
<< "Caution: Wownero is highly experimental software compiled by a ragtag team of stoners with as much" << ENDL
<< "skill as Verge developers. Storing your life savings in WOW is probably not a good idea." << ENDL
<< ENDL
<< "You can set the level of process detailization through \"set_log <level|categories>\" command," << ENDL
<< "where <level> is between 0 (no details) and 4 (very verbose), or custom category based levels (eg, *:WARNING)." << ENDL
<< ENDL
@@ -1654,7 +1721,6 @@ namespace cryptonote
m_starter_message_showed = true;
}
m_fork_moaner.do_call(boost::bind(&core::check_fork_time, this));
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
@@ -1665,31 +1731,6 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
bool core::check_fork_time()
{
if (m_nettype == FAKECHAIN)
return true;
HardFork::State state = m_blockchain_storage.get_hard_fork_state();
el::Level level;
switch (state) {
case HardFork::LikelyForked:
level = el::Level::Warning;
MCLOG_RED(level, "global", "**********************************************************************");
MCLOG_RED(level, "global", "Last scheduled hard fork is too far in the past.");
MCLOG_RED(level, "global", "We are most likely forked from the network. Daemon update needed now.");
MCLOG_RED(level, "global", "**********************************************************************");
break;
case HardFork::UpdateNeeded:
level = el::Level::Info;
MCLOG(level, "global", el::Color::Default, "Last scheduled hard fork time suggests a daemon update will be released within the next couple months.");
break;
default:
break;
}
return true;
}
//-----------------------------------------------------------------------------------------------
uint8_t core::get_ideal_hard_fork_version() const
{
return get_blockchain_storage().get_ideal_hard_fork_version();
@@ -1907,7 +1948,7 @@ namespace cryptonote
MDEBUG("blocks in the last " << seconds[n] / 60 << " minutes: " << b << " (probability " << p << ")");
if (p < threshold)
{
MWARNING("There were " << b << (b == max_blocks_checked ? " or more" : "") << " blocks in the last " << seconds[n] / 60 << " minutes, there might be large hash rate changes, or we might be partitioned, cut off from the Monero network or under attack, or your computer's time is off. Or it could be just sheer bad luck.");
MDEBUG("There were " << b << (b == max_blocks_checked ? " or more" : "") << " blocks in the last " << seconds[n] / 60 << " minutes, there might be large hash rate changes, or we might be partitioned, cut off from the Wownero network or under attack, or your computer's time is off. Or it could be just sheer bad luck.");
std::shared_ptr<tools::Notify> block_rate_notify = m_block_rate_notify;
if (block_rate_notify)

View File

@@ -469,10 +469,11 @@ namespace cryptonote
/**
* @copydoc tx_memory_pool::get_txpool_backlog
* @param include_sensitive_txes include private transactions
*
* @note see tx_memory_pool::get_txpool_backlog
*/
bool get_txpool_backlog(std::vector<tx_backlog_entry>& backlog) const;
bool get_txpool_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive_txes = false) const;
/**
* @copydoc tx_memory_pool::get_transactions
@@ -514,10 +515,11 @@ namespace cryptonote
/**
* @copydoc tx_memory_pool::get_transactions_count
* @param include_sensitive_txes include private transactions
*
* @note see tx_memory_pool::get_transactions_count
*/
size_t get_pool_transactions_count() const;
size_t get_pool_transactions_count(bool include_sensitive_txes = false) const;
/**
* @copydoc Blockchain::get_total_transactions
@@ -697,7 +699,7 @@ namespace cryptonote
*
* @note see Blockchain::update_checkpoints()
*/
bool update_checkpoints();
bool update_checkpoints(const bool skip_dns = false);
/**
* @brief tells the daemon to wind down operations and stop running
@@ -998,18 +1000,6 @@ namespace cryptonote
*/
bool check_tx_inputs_keyimages_domain(const transaction& tx) const;
/**
* @brief checks HardFork status and prints messages about it
*
* Checks the status of HardFork and logs/prints if an update to
* the daemon is necessary.
*
* @note see Blockchain::get_hard_fork_state and HardFork::State
*
* @return true
*/
bool check_fork_time();
/**
* @brief attempts to relay any transactions in the mempool which need it
*

View File

@@ -590,9 +590,11 @@ namespace cryptonote
tx.vout[i].amount = 0;
crypto::hash tx_prefix_hash;
get_transaction_prefix_hash(tx, tx_prefix_hash);
get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev);
rct::ctkeyV outSk;
if (use_simple_rct)
if (rct_config.range_proof_type != rct::RangeProofPaddedBulletproof && use_simple_rct)
tx.rct_signatures = rct::genRctSimple_old(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, rct_config, hwdev);
else if (use_simple_rct && rct_config.range_proof_type == rct::RangeProofPaddedBulletproof)
tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, rct_config, hwdev);
else
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption
@@ -678,15 +680,12 @@ namespace cryptonote
bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const int miners)
{
// block 202612 bug workaround
if (height == 202612)
{
static const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000";
epee::string_tools::hex_to_pod(longhash_202612, res);
return true;
}
blobdata bd = get_block_hashing_blob(b);
if (b.major_version >= RX_BLOCK_VERSION)
if (b.major_version >= HF_VERSION_SHA3_POW)
{
crypto::sha3(bd.data(), bd.size(), res);
}
else if (b.major_version >= RX_BLOCK_VERSION && b.major_version < HF_VERSION_SHA3_POW)
{
uint64_t seed_height, main_height;
crypto::hash hash;
@@ -703,7 +702,7 @@ namespace cryptonote
}
rx_slow_hash(main_height, seed_height, hash.data, bd.data(), bd.size(), res.data, miners, 0);
} else {
const int pow_variant = b.major_version >= 7 ? b.major_version - 6 : 0;
const int pow_variant = b.major_version >= 11 ? 4 : b.major_version >= 9 ? 2 : 1;
crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant, height);
}
return true;

View File

@@ -46,6 +46,7 @@
#include "warnings.h"
#include "common/perf_timer.h"
#include "crypto/hash.h"
#include "crypto/duration.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "txpool"
@@ -58,6 +59,29 @@ namespace cryptonote
{
namespace
{
/*! The Dandelion++ has formula for calculating the average embargo timeout:
(-k*(k-1)*hop)/(2*log(1-ep))
where k is the number of hops before this node and ep is the probability
that one of the k hops hits their embargo timer, and hop is the average
time taken between hops. So decreasing ep will make it more probable
that "this" node is the first to expire the embargo timer. Increasing k
will increase the number of nodes that will be "hidden" as a prior
recipient of the tx.
As example, k=5 and ep=0.1 means "this" embargo timer has a 90%
probability of being the first to expire amongst 5 nodes that saw the
tx before "this" one. These values are independent to the fluff
probability, but setting a low k with a low p (fluff probability) is
not ideal since a blackhole is more likely to reveal earlier nodes in
the chain.
This value was calculated with k=10, ep=0.10, and hop = 175 ms. A
testrun from a recent Intel laptop took ~80ms to
receive+parse+proces+send transaction. At least 50ms will be added to
the latency if crossing an ocean. So 175ms is the fudge factor for
a single hop with 173s being the embargo timer. */
constexpr const std::chrono::seconds dandelionpp_embargo_average{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE};
//TODO: constants such as these should at least be in the header,
// but probably somewhere more accessible to the rest of the
// codebase. As it stands, it is at best nontrivial to test
@@ -83,8 +107,8 @@ namespace cryptonote
uint64_t get_transaction_weight_limit(uint8_t version)
{
// from v8, limit a tx to 50% of the minimum block weight
if (version >= 8)
// from v12, limit a tx to 50% of the minimum block weight
if (version >= 12)
return get_min_block_weight(version) / 2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
else
return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
@@ -92,7 +116,7 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_cookie(0)
tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false)
{
}
@@ -186,7 +210,7 @@ namespace cryptonote
// TODO: Investigate why not?
if(!kept_by_block)
{
if(have_tx_keyimges_as_spent(tx))
if(have_tx_keyimges_as_spent(tx, id))
{
mark_double_spend(tx);
LOG_PRINT_L1("Transaction with id= "<< id << " used already spent key images");
@@ -229,7 +253,7 @@ namespace cryptonote
meta.last_relayed_time = time(NULL);
meta.relayed = relayed;
meta.set_relay_method(tx_relay);
meta.double_spend_seen = have_tx_keyimges_as_spent(tx);
meta.double_spend_seen = have_tx_keyimges_as_spent(tx, id);
meta.pruned = tx.pruned;
meta.bf_padding = 0;
memset(meta.padding, 0, sizeof(meta.padding));
@@ -262,34 +286,51 @@ namespace cryptonote
}
}else
{
//update transactions container
meta.weight = tx_weight;
meta.fee = fee;
meta.max_used_block_id = max_used_block_id;
meta.max_used_block_height = max_used_block_height;
meta.last_failed_height = 0;
meta.last_failed_id = null_hash;
meta.receive_time = receive_time;
meta.last_relayed_time = time(NULL);
meta.relayed = relayed;
meta.set_relay_method(tx_relay);
meta.double_spend_seen = false;
meta.pruned = tx.pruned;
meta.bf_padding = 0;
memset(meta.padding, 0, sizeof(meta.padding));
try
{
if (kept_by_block)
m_parsed_tx_cache.insert(std::make_pair(id, tx));
CRITICAL_REGION_LOCAL1(m_blockchain);
LockedTXN lock(m_blockchain.get_db());
m_blockchain.remove_txpool_tx(id);
if (!insert_key_images(tx, id, tx_relay))
return false;
m_blockchain.add_txpool_tx(id, blob, meta);
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)(tx_weight ? tx_weight : 1), receive_time), id);
const bool existing_tx = m_blockchain.get_txpool_tx_meta(id, meta);
if (existing_tx)
{
/* If Dandelion++ loop. Do not use txes in the `local` state in the
loop detection - txes in that state should be outgoing over i2p/tor
then routed back via public dandelion++ stem. Pretend to be
another stem node in that situation, a loop over the public
network hasn't been hit yet. */
if (tx_relay == relay_method::stem && meta.dandelionpp_stem)
tx_relay = relay_method::fluff;
}
else
meta.set_relay_method(relay_method::none);
if (meta.upgrade_relay_method(tx_relay) || !existing_tx) // synchronize with embargo timer or stem/fluff out-of-order messages
{
//update transactions container
meta.last_relayed_time = std::numeric_limits<decltype(meta.last_relayed_time)>::max();
meta.receive_time = receive_time;
meta.weight = tx_weight;
meta.fee = fee;
meta.max_used_block_id = max_used_block_id;
meta.max_used_block_height = max_used_block_height;
meta.last_failed_height = 0;
meta.last_failed_id = null_hash;
meta.relayed = relayed;
meta.double_spend_seen = false;
meta.pruned = tx.pruned;
meta.bf_padding = 0;
memset(meta.padding, 0, sizeof(meta.padding));
if (!insert_key_images(tx, id, tx_relay))
return false;
m_blockchain.remove_txpool_tx(id);
m_blockchain.add_txpool_tx(id, blob, meta);
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)(tx_weight ? tx_weight : 1), receive_time), id);
}
lock.commit();
}
catch (const std::exception &e)
@@ -299,8 +340,9 @@ namespace cryptonote
}
tvc.m_added_to_pool = true;
if(meta.fee > 0 && tx_relay != relay_method::none)
tvc.m_should_be_relayed = true;
static_assert(unsigned(relay_method::none) == 0, "expected relay_method::none value to be zero");
if(meta.fee > 0)
tvc.m_relay = tx_relay;
}
tvc.m_verifivation_failed = false;
@@ -404,27 +446,18 @@ namespace cryptonote
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
/* If any existing key-image in the set is publicly visible AND this is
not forcibly "kept_by_block", then fail (duplicate key image). If all
existing key images are supposed to be hidden, we silently allow so
that the node doesn't leak knowledge of a local/stem tx. */
bool visible = false;
// Only allow multiple txes per key-image if kept-by-block. Only allow
// the same txid if going from local/stem->fluff.
if (tx_relay != relay_method::block)
{
for (const crypto::hash& other_id : kei_image_set)
visible |= m_blockchain.txpool_tx_matches_category(other_id, relay_category::legacy);
}
CHECK_AND_ASSERT_MES(!visible, false, "internal error: tx_relay=" << unsigned(tx_relay)
const bool one_txid =
(kei_image_set.empty() || (kei_image_set.size() == 1 && *(kei_image_set.cbegin()) == id));
CHECK_AND_ASSERT_MES(one_txid, false, "internal error: tx_relay=" << unsigned(tx_relay)
<< ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
<< "tx_id=" << id);
}
/* If adding a tx (hash) that already exists, fail only if the tx has
been publicly "broadcast" previously. This way, when a private tx is
received for the first time from a remote node, "this" node will
respond as-if it were seen for the first time. LMDB does the
"hard-check" on key-images, so the effect is overwriting the existing
tx_pool metadata and "first seen" time. */
const bool new_or_previously_private =
kei_image_set.insert(id).second ||
!m_blockchain.txpool_tx_matches_category(id, relay_category::legacy);
@@ -562,7 +595,7 @@ namespace cryptonote
td.last_failed_height = meta.last_failed_height;
td.last_failed_id = meta.last_failed_id;
td.receive_time = meta.receive_time;
td.last_relayed_time = meta.last_relayed_time;
td.last_relayed_time = meta.dandelionpp_stem ? 0 : meta.last_relayed_time;
td.relayed = meta.relayed;
td.do_not_relay = meta.do_not_relay;
td.double_spend_seen = meta.double_spend_seen;
@@ -582,8 +615,8 @@ namespace cryptonote
CRITICAL_REGION_LOCAL1(m_blockchain);
m_blockchain.for_all_txpool_txes([this, &hashes, &txes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
const auto relay_method = meta.get_relay_method();
if (relay_method != relay_method::block && relay_method != relay_method::fluff)
const auto tx_relay_method = meta.get_relay_method();
if (tx_relay_method != relay_method::block && tx_relay_method != relay_method::fluff)
return true;
const auto i = std::find(hashes.begin(), hashes.end(), txid);
if (i == hashes.end())
@@ -695,8 +728,13 @@ namespace cryptonote
txs.reserve(m_blockchain.get_txpool_tx_count());
m_blockchain.for_all_txpool_txes([this, now, &txs](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *){
// 0 fee transactions are never relayed
if(!meta.pruned && meta.fee > 0 && !meta.do_not_relay && now - meta.last_relayed_time > get_relay_delay(now, meta.receive_time))
if(!meta.pruned && meta.fee > 0 && !meta.do_not_relay)
{
if (!meta.dandelionpp_stem && now - meta.last_relayed_time <= get_relay_delay(now, meta.receive_time))
return true;
if (meta.dandelionpp_stem && meta.last_relayed_time < now) // for dandelion++ stem, this value is the embargo timeout
return true;
// if the tx is older than half the max lifetime, we don't re-relay it, to avoid a problem
// mentioned by smooth where nodes would flush txes at slightly different times, causing
// flushed txes to be re-added when received from a node which was just about to flush it
@@ -721,9 +759,11 @@ namespace cryptonote
//---------------------------------------------------------------------------------
void tx_memory_pool::set_relayed(const epee::span<const crypto::hash> hashes, const relay_method method)
{
crypto::random_poisson_seconds embargo_duration{dandelionpp_embargo_average};
const auto now = std::chrono::system_clock::now();
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
const time_t now = time(NULL);
LockedTXN lock(m_blockchain.get_db());
for (const auto& hash : hashes)
{
@@ -732,9 +772,15 @@ namespace cryptonote
txpool_tx_meta_t meta;
if (m_blockchain.get_txpool_tx_meta(hash, meta))
{
// txes can be received as "stem" or "fluff" in either order
meta.upgrade_relay_method(method);
meta.relayed = true;
meta.last_relayed_time = now;
meta.set_relay_method(method);
if (meta.dandelionpp_stem)
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now + embargo_duration());
else
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now);
m_blockchain.update_txpool_tx(hash, meta);
}
}
@@ -919,7 +965,7 @@ namespace cryptonote
txi.receive_time = include_sensitive_data ? meta.receive_time : 0;
txi.relayed = meta.relayed;
// In restricted mode we do not include this data:
txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0;
txi.last_relayed_time = (include_sensitive_data && !meta.dandelionpp_stem) ? meta.last_relayed_time : 0;
txi.do_not_relay = meta.do_not_relay;
txi.double_spend_seen = meta.double_spend_seen;
tx_infos.push_back(std::move(txi));
@@ -971,7 +1017,7 @@ namespace cryptonote
txi.last_failed_block_hash = meta.last_failed_id;
txi.receive_time = meta.receive_time;
txi.relayed = meta.relayed;
txi.last_relayed_time = meta.last_relayed_time;
txi.last_relayed_time = meta.dandelionpp_stem ? 0 : meta.last_relayed_time;
txi.do_not_relay = meta.do_not_relay;
txi.double_spend_seen = meta.double_spend_seen;
tx_infos.push_back(txi);
@@ -1052,30 +1098,32 @@ namespace cryptonote
return m_blockchain.get_db().txpool_has_tx(id, tx_category);
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx) const
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx, const crypto::hash& txid) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
for(const auto& in: tx.vin)
{
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail
if(have_tx_keyimg_as_spent(tokey_in.k_image))
if(have_tx_keyimg_as_spent(tokey_in.k_image, txid))
return true;
}
return false;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im, const crypto::hash& txid) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
bool spent = false;
const auto found = m_spent_key_images.find(key_im);
if (found != m_spent_key_images.end())
if (found != m_spent_key_images.end() && !found->second.empty())
{
for (const crypto::hash& tx_hash : found->second)
spent |= m_blockchain.txpool_tx_matches_category(tx_hash, relay_category::broadcasted);
// If another tx is using the key image, always return as spent.
// See `insert_key_images`.
if (1 < found->second.size() || *(found->second.cbegin()) != txid)
return true;
return m_blockchain.txpool_tx_matches_category(txid, relay_category::legacy);
}
return spent;
return false;
}
//---------------------------------------------------------------------------------
void tx_memory_pool::lock() const
@@ -1303,13 +1351,18 @@ namespace cryptonote
for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
{
txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta) && !meta.matches(relay_category::legacy))
if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
{
MERROR(" failed to find tx meta");
continue;
}
LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase));
LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method());
if (!meta.matches(relay_category::legacy) && !(m_mine_stem_txes && meta.get_relay_method() == relay_method::stem))
{
LOG_PRINT_L2(" tx relay method is " << (unsigned)meta.get_relay_method());
continue;
}
if (meta.pruned)
{
LOG_PRINT_L2(" tx is pruned");
@@ -1474,7 +1527,7 @@ namespace cryptonote
return n_removed;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::init(size_t max_txpool_weight)
bool tx_memory_pool::init(size_t max_txpool_weight, bool mine_stem_txes)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
@@ -1530,6 +1583,7 @@ namespace cryptonote
lock.commit();
}
m_mine_stem_txes = mine_stem_txes;
m_cookie = 0;
// Ignore deserialization error

View File

@@ -205,10 +205,11 @@ namespace cryptonote
* @brief loads pool state (if any) from disk, and initializes pool
*
* @param max_txpool_weight the max weight in bytes
* @param mine_stem_txes whether to mine txes in stem relay mode
*
* @return true
*/
bool init(size_t max_txpool_weight = 0);
bool init(size_t max_txpool_weight = 0, bool mine_stem_txes = false);
/**
* @brief attempts to save the transaction pool state to disk
@@ -470,10 +471,11 @@ namespace cryptonote
* @brief check if a transaction in the pool has a given spent key image
*
* @param key_im the spent key image to look for
* @param txid hash of the new transaction where `key_im` was seen.
*
* @return true if the spent key image is present, otherwise false
*/
bool have_tx_keyimg_as_spent(const crypto::key_image& key_im) const;
bool have_tx_keyimg_as_spent(const crypto::key_image& key_im, const crypto::hash& txid) const;
/**
* @brief check if any spent key image in a transaction is in the pool
@@ -484,10 +486,11 @@ namespace cryptonote
* @note see tx_pool::have_tx_keyimg_as_spent
*
* @param tx the transaction to check spent key images of
* @param txid hash of `tx`.
*
* @return true if any spent key images are present in the pool, otherwise false
*/
bool have_tx_keyimges_as_spent(const transaction& tx) const;
bool have_tx_keyimges_as_spent(const transaction& tx, const crypto::hash& txid) const;
/**
* @brief forget a transaction's spent key images
@@ -601,6 +604,7 @@ private:
size_t m_txpool_max_weight;
size_t m_txpool_weight;
bool m_mine_stem_txes;
mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache;

Some files were not shown because too many files have changed in this diff Show More