Compare commits

..

114 Commits

Author SHA1 Message Date
c04ab0b3b8 Use local RandomWOW
All checks were successful
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (aarch64-apple-darwin11) (push) Successful in 11m57s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (aarch64-linux-gnu) (push) Successful in 8m39s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (riscv64-linux-gnu) (push) Successful in 12m11s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (x86_64-apple-darwin11) (push) Successful in 12m9s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (x86_64-linux-gnu) (push) Successful in 8m24s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (x86_64-w64-mingw32) (push) Successful in 9m40s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / release (push) Successful in 33s
2026-01-24 10:38:42 -05:00
115cc7199b Inject newer CMake
Some checks failed
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (aarch64-apple-darwin11) (push) Successful in 12m47s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (aarch64-linux-gnu) (push) Successful in 8m48s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (riscv64-linux-gnu) (push) Successful in 11m17s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (x86_64-apple-darwin11) (push) Successful in 12m6s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (x86_64-linux-gnu) (push) Failing after 33s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / build-all (x86_64-w64-mingw32) (push) Failing after 47s
Build Wownero Core (Clean / Boost 1.90 / CMake 3.28) / release (push) Has been skipped
2026-01-24 09:45:17 -05:00
c91af646d6 Add context and coroutine for LWS 2026-01-24 09:44:41 -05:00
48935978f7 fix: indent/space breaking build
Some checks failed
Build Wownero Core (Clean / Boost 1.90) / build-all (aarch64-apple-darwin11) (push) Failing after 9m36s
Build Wownero Core (Clean / Boost 1.90) / build-all (aarch64-linux-gnu) (push) Has been cancelled
Build Wownero Core (Clean / Boost 1.90) / build-all (riscv64-linux-gnu) (push) Has been cancelled
Build Wownero Core (Clean / Boost 1.90) / build-all (x86_64-apple-darwin11) (push) Has been cancelled
Build Wownero Core (Clean / Boost 1.90) / build-all (x86_64-linux-gnu) (push) Has been cancelled
Build Wownero Core (Clean / Boost 1.90) / build-all (x86_64-w64-mingw32) (push) Has been cancelled
Build Wownero Core (Clean / Boost 1.90) / release (push) Has been cancelled
2026-01-24 09:28:34 -05:00
32106203a3 Static builds with libs for Boost 1.90
Some checks failed
Build Wownero Core (Clean / Boost 1.90) / build-all (aarch64-apple-darwin11) (push) Failing after 41s
Build Wownero Core (Clean / Boost 1.90) / build-all (aarch64-linux-gnu) (push) Failing after 43s
Build Wownero Core (Clean / Boost 1.90) / build-all (riscv64-linux-gnu) (push) Failing after 45s
Build Wownero Core (Clean / Boost 1.90) / build-all (x86_64-apple-darwin11) (push) Failing after 47s
Build Wownero Core (Clean / Boost 1.90) / build-all (x86_64-linux-gnu) (push) Failing after 47s
Build Wownero Core (Clean / Boost 1.90) / build-all (x86_64-w64-mingw32) (push) Failing after 44s
Build Wownero Core (Clean / Boost 1.90) / release (push) Has been skipped
2026-01-24 09:05:23 -05:00
7136ae9788 Update to Boost 1.90 2026-01-24 09:02:19 -05:00
wowario
ec5d370e79 remove github actions 2026-01-17 02:55:37 +00:00
wowario
1a084a8736 update checkpoints 2026-01-17 02:55:37 +00:00
wowario
e39cc59597 v0.11 ASCII art 2026-01-17 02:55:37 +00:00
wowario
146c5c27a6 wownero skin pack 2026-01-17 02:55:37 +00:00
wowario
13dc93ba78 add checkpoints and fork heights 2026-01-17 02:55:37 +00:00
wowario
83f9af4335 change to debug level 2026-01-17 02:55:37 +00:00
wowario
c488dab8a0 add clear screen command 2026-01-17 02:55:37 +00:00
wowario
a996d67280 show full version 2026-01-17 02:55:37 +00:00
wowario
2f48099996 cleanup old bp 2026-01-17 02:55:36 +00:00
wowario
7e00405190 vote by block 2026-01-17 02:55:36 +00:00
wowario
9ab291ba8f miner block header signing 2026-01-17 02:55:36 +00:00
wowario
693c88e21c add nettype to diff algo 2026-01-17 02:55:36 +00:00
wowario
e938bd556b difficulty is fun 2026-01-17 02:55:36 +00:00
wowario
78029b6787 only allocate slow hash before RX 2026-01-17 02:55:36 +00:00
wowario
d0c47ec1a7 mod variant4_random_math 2026-01-17 02:55:36 +00:00
wowario
1b2e579160 set pow variants 2026-01-17 02:55:36 +00:00
wowario
d66b4c6091 bump RX block version 2026-01-17 02:55:36 +00:00
wowario
a3ca52f3f3 add RandomWOW 2026-01-17 02:55:36 +00:00
wowario
c67a16403d shorten timestamp check window 2026-01-17 02:55:36 +00:00
wowario
a348294daa limit future blk time to 10 min 2026-01-17 02:55:36 +00:00
wowario
f3032e08a2 bump unlock time to 288 blks 2026-01-17 02:55:36 +00:00
wowario
91699702d6 config wallet2 settings 2026-01-17 02:55:36 +00:00
wowario
1163cd2ef1 add wowario gpg key 2026-01-17 02:55:36 +00:00
wowario
d20fe8c67a update gitian 2026-01-17 02:55:36 +00:00
wowario
f7b8442840 fix unit tests 2026-01-17 02:55:36 +00:00
wowario
269abd8fc3 automatic submodule update 2026-01-17 02:55:36 +00:00
wowario
7c83b3d0fd fix mismatched daemon check bug 2026-01-17 02:55:36 +00:00
wowario
df98f370c7 update average block sizes table 2026-01-17 02:55:36 +00:00
wowario
7b1e62546b set decimal point 2026-01-17 02:55:36 +00:00
wowario
1e7e406407 add seeds 2026-01-17 02:55:36 +00:00
wowario
29e4e97d19 adjust approx_blockchain_height 2026-01-17 02:55:36 +00:00
wowario
9637a3a3a4 set last v1 block 2026-01-17 02:55:36 +00:00
wowario
9221a81d7a set quick height for syncing 2026-01-17 02:55:36 +00:00
wowario
63cea8989e set genesis block timestamp 2026-01-17 02:55:36 +00:00
wowario
f09d20956f correct length of addresses 2026-01-17 02:55:36 +00:00
wowario
5f07f775f3 bump ring size to 22 2026-01-17 02:55:36 +00:00
wowario
8c412d880a add release-minimal to Makefile 2026-01-17 02:55:36 +00:00
wowario
b16a5d035b add wow readme 2026-01-17 02:55:34 +00:00
wowario
7a1b710b81 initialize genesis block 2026-01-17 02:55:12 +00:00
wowario
2710361ef0 config cryptonote 2026-01-17 02:55:12 +00:00
wowario
f96f03507b del README.md 2026-01-17 02:55:01 +00:00
wowario
cb5d3212ee del seeds 2026-01-17 02:46:20 +00:00
wowario
1851693036 del testnet/stagenet blocks 2026-01-17 02:44:29 +00:00
wowario
5bef9f1236 del checkpoints and fork heights 2026-01-17 02:44:27 +00:00
wowario
14aae741dc del seed ips 2026-01-17 02:41:53 +00:00
wowario
03eacc42e0 del dns ips 2026-01-17 02:41:53 +00:00
wowario
4cce50c75e del moneropulse urls 2026-01-17 02:41:53 +00:00
wowario
056a57761f del monero tx bug fixes 2026-01-17 02:41:53 +00:00
tobtoht
316a98b11e Merge pull request #10262
ec34c5b build: prepare v0.18.4.5 (selsta)
2025-12-29 22:41:50 +00:00
tobtoht
6553d87c28 Merge pull request #10268
1075ace logging: Generalize terminal color detection (iamamyth)
2025-12-29 22:40:46 +00:00
iamamyth
1075acee90 logging: Generalize terminal color detection
Assume the terminal supports color codes if TERM ends with `-color` or
`-256color`, rather than special-casing a handful of such terminals.

Co-authored-by: laanwj <126646+laanwj@users.noreply.github.com>
2025-12-29 22:29:25 +00:00
tobtoht
1e5b761086 Merge pull request #10252
7baf2bd epee: add missing cstdint include (tobtoht)
2025-12-29 22:27:03 +00:00
tobtoht
9dff86103e Merge pull request #10257
d8d3cf9 p2p: fix race causing dropped connections during sync (j-berman)
2025-12-29 22:24:38 +00:00
tobtoht
4862ffd5dc Merge pull request #10255
c147e2d wallet2: fix edge case where tx's ki's remain marked unspent (j-berman)
2025-12-29 22:21:21 +00:00
selsta
ec34c5b93f build: prepare v0.18.4.5 2025-12-29 22:27:58 +01:00
j-berman
c147e2dfe2 wallet2: fix edge case where tx's ki's remain marked unspent
If a tx is marked as failed (because it never shows up in the
daemon's pool), its key images get reset back to unspent so they
can be used in future txs.

If the tx re-enters the daemon's pool (e.g. it's removed from the
pool and then relayed back), then the wallet incorrectly maintains
that the tx's key images are unspent.

This change ensures the wallet re-marks the tx's key images as
spent if the tx re-appears in the node's pool.
2025-12-12 09:14:55 -08:00
j-berman
d8d3cf9730 p2p: fix race causing dropped connections during sync
Without this commit:
1) read height from DB
2) add block to chain in separate thread
3) read chain for block id's and request them from peer
4) ERR in handle_response_chain_entry, peer's first block is the
one that was added to the chain, which has block idx=height from
step 1.

This commit reads the chain for height and highest block id's
in one go while holding the m_blockchain_lock to avoid the race.
2025-12-11 21:37:20 -08:00
tobtoht
7baf2bde6e epee: add missing cstdint include 2025-12-11 10:43:33 +01:00
tobtoht
ae08557f71 Merge pull request #10243
15fc1c8 ledger: add nano gen5 id (tobtoht)
2025-12-09 17:58:04 +00:00
tobtoht
15fc1c840c ledger: add nano gen5 id 2025-12-01 01:49:50 +01:00
tobtoht
e5d0b6078a Merge pull request #10238
ba163d3 simplewallet: edit desc. text for transfer (Cat)
2025-11-26 20:42:29 +00:00
tobtoht
853272408b Merge pull request #10234
c14a0ba depends: hidapi: update to 0.15.0 (tobtoht)
2025-11-26 19:35:43 +00:00
Cat
ba163d38cb simplewallet: edit desc. text for transfer 2025-11-26 19:21:18 +00:00
tobtoht
c14a0ba432 depends: hidapi: update to 0.15.0 2025-11-24 18:12:10 +01:00
tobtoht
516e5355a1 Merge pull request #10206
4e4e343 Daemon: relay empty fluffy block on found block (j-berman)
2025-11-12 09:22:38 +00:00
tobtoht
14f3d408ad Merge pull request #10204
90dad18 tx pool: only increment m_txpool_weight for newly added pool txs (j-berman)
2025-11-12 09:20:34 +00:00
j-berman
4e4e3439c9 Daemon: relay empty fluffy block on found block 2025-11-11 16:45:06 -08:00
j-berman
90dad18bfb tx pool: only increment m_txpool_weight for newly added pool txs
Otherwise we can end up double counting txs towards the weight,
which can over-state the pool weight. E.g. relay tx to node in
stem phase, add its weight to pool weight, then receive tx
from another node, then bump the pool weight again. That double
counts the tx towards the pool weight.

If the weight exceeds the max, the node will "prune" txs from the
pool. Thus, over-counting is probably a cause of, but perhaps
not the only cause of:
https://github.com/seraphis-migration/monero/issues/148
2025-11-11 16:31:37 -08:00
tobtoht
6f2574d9d2 Merge pull request #10195
26cf4f9 ledger: throw on secret view key export rejection (tobtoht)
2025-11-11 23:01:13 +00:00
tobtoht
68732126e9 Merge pull request #10202
dafecd0 cryptonote_protocol: accurate next_needed_height when there is an overlap (0xFFFC0000)
2025-11-11 22:42:07 +00:00
tobtoht
64f230d63a Merge pull request #10199
64f2d8e build: prepare v0.18.4.4 (selsta)
2025-11-11 21:52:46 +00:00
tobtoht
8167ae5ef0 Merge pull request #10194
a83a46d Fix logging deadlock (j-berman)
2025-11-11 21:51:35 +00:00
tobtoht
26cf4f9141 ledger: throw on secret view key export rejection 2025-11-11 20:57:56 +01:00
j-berman
a83a46d600 Fix logging deadlock 2025-11-11 10:44:26 -08:00
0xFFFC0000
dafecd0add cryptonote_protocol: accurate next_needed_height when there is an overlap 2025-11-11 00:28:50 +03:30
selsta
64f2d8e45d build: prepare v0.18.4.4 2025-11-10 18:56:57 +01:00
tobtoht
3cc9d65c93 Merge pull request #10153
9239d36 wallet: identify spends in pool when scanning (j-berman)
2025-10-27 18:51:14 +00:00
luigi1111
7c6e84466a Merge pull request #10106
09f5cbb build: prepare v0.18.4.3 (selsta)
2025-10-07 15:25:41 -04:00
luigi1111
fb76bc4d98 Merge pull request #10150
1829992 wallet2: warn instead of throw when RingDB doesn't include spend (j-berman)
2025-10-07 15:25:05 -04:00
luigi1111
020d980647 Merge pull request #10149
014f3cd cryptonote_basic: remove redundant call to get_transaction_hash() in overload (jeffro256)
2025-10-07 15:24:35 -04:00
luigi1111
de73139f42 Merge pull request #10148
7b53197 Cleaner validation (faster and saner) (j-berman)
2025-10-07 15:23:52 -04:00
luigi1111
f350ebdeeb Merge pull request #10125
cfc41b3 Daemon RPC: fix on_getblockhash error return on too high height (j-berman)
2025-10-07 15:19:25 -04:00
j-berman
9239d36691 wallet: identify spends in pool when scanning
- Make sure to mark identified spends in the pool as spends. The
wallet might not know these have been spent if it wasn't the wallet
that relayed the tx to the daemon, or the wallet was cleared via
rescan_bc.
- Make sure to add spends to m_unconfirmed_txs if not present.
- Make sure to process the entire pool again if refreshing for
the first time. The wallet fetches pool and blocks at the same
time. The wallet scans blocks first, then pool. If the wallet
identifies received outputs in the chain, then it may have spent
those received outputs in the pool. So we make sure to re-process
the entire pool again after scanning the chain for the first time.
- Multisig wallets that know about spent key images can now detect
spend txs in the pool. Update tests for that.
2025-10-07 11:02:17 -07:00
selsta
09f5cbbb98 build: prepare v0.18.4.3 2025-10-07 16:36:04 +02:00
j-berman
1829992970 wallet2: warn instead of throw when RingDB doesn't include spend
A reorg can end up causing an output's position in the chain to
move. Since the wallet doesn't update the RingDB on reorg, it
may refer to the output's stale position in the chain.

This seems a reasonable solution rather than introducing complex
logic to update the stale ring member's value on rerog, since
RingDB can be deprecated with FCMP++.
2025-10-06 13:25:19 -07:00
jeffro256
014f3cd0a1 cryptonote_basic: remove redundant call to get_transaction_hash() in overload
Issue noticed by DataHoarder.
2025-10-06 15:05:20 -05:00
j-berman
7b53197571 Cleaner validation (faster and saner) 2025-10-05 17:56:57 -07:00
j-berman
cfc41b3bdc Daemon RPC: fix on_getblockhash error return on too high height 2025-09-29 10:56:34 -07:00
tobtoht
a440e91790 Merge pull request #9901
9a45208 Daemon RPC: add max_block_count field to /getblocks.bin (j-berman)
2025-09-28 18:37:02 +00:00
tobtoht
6ee94b07df Merge pull request #10098
13e28ea simplewallet: batch address creation limit to match rpc (nahuhh)
2025-09-28 18:35:30 +00:00
tobtoht
6552aa6165 Merge pull request #10104
39c7a22 Send ZMQ miner notifications after txpool additions (WeebDataHoarder)
2025-09-28 18:34:03 +00:00
tobtoht
ca58206a57 Merge pull request #10112
dd82d28 removing lza_menace seed nodes (lza_menace)
2025-09-28 18:32:24 +00:00
tobtoht
be2cccf84b Merge pull request #10113
2879885 p2p: Improved peer selection with /24 subnet deduplication to disadvantage 'spy nodes' [v0.18] (rbrunner7)
2025-09-28 18:31:28 +00:00
tobtoht
c9859c6713 Merge pull request #10115
659114a net_node: add hinto seed nodes (hinto.janai)
2025-09-28 18:29:35 +00:00
hinto.janai
659114a7bf net_node: add hinto seed nodes 2025-09-26 19:26:55 +00:00
rbrunner7
2879885e3c p2p: Improved peer selection with /24 subnet deduplication to disadvantage 'spy nodes' [v0.18] 2025-09-26 15:40:46 +02:00
lza_menace
dd82d283b2 removing lza_menace seed nodes 2025-09-26 10:25:11 +01:00
tobtoht
bbc838557e Merge pull request #10105
f292444 remove 66.85.74.134 as seed node (Gingeropolous)
2025-09-24 20:53:32 +00:00
tobtoht
2d1972299a Merge pull request #10066
36b12ed Fix logging lock, future optimizations may needed (Lee *!* Clagett)
2025-09-24 20:51:55 +00:00
tobtoht
fc0ff59adf Merge pull request #10092
00e4faf cryptonote_core: `--dns-versions-check` is deprecated (nahuhh)
2025-09-24 20:49:35 +00:00
tobtoht
6382e1e3f7 Merge pull request #10096
751061c wallet_rpc_server: allow creating more than 64 addresses at once (moneromooo-monero)
2025-09-24 20:47:59 +00:00
Gingeropolous
f292444c54 remove 66.85.74.134 as seed node
remove 66.85.74.134 as seed node. bastards doubled the price of the server.
2025-09-24 17:09:57 +00:00
WeebDataHoarder
39c7a22856 Send ZMQ miner notifications after txpool additions
Bug was introduced in c069c04ede338929c50297558fee15192aa0f67c, before this txpool additions were not notified on block addition

When receiving blocks with previously unknown conditions, miner data was sent first, but txpool add events for already-added transactions in previous block were sent afterward. Miners would then include already-mined transactions in their new templates due to receiving the mistimed txpool add event.

The fix is to send miner notifications AFTER txpool events are sent, and before normal block notifications are sent (for mining switch speed purposes)

Fixes c069c04ede338929c50297558fee15192aa0f67c / #9135
Fixes dfee15eee1 / #7891
2025-09-24 09:22:28 +02:00
nahuhh
13e28ea6d6 simplewallet: batch address creation limit to match rpc 2025-09-22 13:56:25 +00:00
moneromooo-monero
751061c846 wallet_rpc_server: allow creating more than 64 addresses at once
it's too low a limit (at least one person mentioned having to
call create_address in a loop due to it)
2025-09-22 13:44:18 +00:00
nahuhh
00e4fafb6e cryptonote_core: --dns-versions-check is deprecated 2025-09-21 18:53:02 +00:00
Lee *!* Clagett
36b12ed50a Fix logging lock, future optimizations may needed 2025-09-02 14:48:12 -04:00
j-berman
9a45208149 Daemon RPC: add max_block_count field to /getblocks.bin 2025-04-10 14:25:54 -07:00
52 changed files with 544 additions and 1234 deletions

117
.gitea/workflows/build.yaml Normal file
View File

@@ -0,0 +1,117 @@
name: Build Wownero Core (Clean / Boost 1.90 / CMake 3.28)
on:
push:
branches: [ master, main ]
tags: [ 'v*' ]
workflow_dispatch:
env:
NODE_TLS_REJECT_UNAUTHORIZED: '0'
jobs:
build-all:
runs-on: ubuntu-latest
container:
image: wownero-builder-base:latest
strategy:
fail-fast: false
matrix:
target:
- x86_64-linux-gnu # Linux x64
- x86_64-w64-mingw32 # Windows x64
- aarch64-linux-gnu # Linux ARM64
- riscv64-linux-gnu # Linux RISC-V
- x86_64-apple-darwin11 # macOS Intel
- aarch64-apple-darwin11 # macOS ARM
steps:
- name: Fix DNS
run: echo "192.168.88.230 git.such.software" >> /etc/hosts
- name: Checkout
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
rm -rf *
git config --global --add safe.directory '*'
# --- CRITICAL FIX: FORCE LOCAL MIRRORS ---
# These lines tell Git: "If you try to go to Codeberg, GO HERE INSTEAD."
# We use the internal port 3000 and the token to ensure access.
# 1. Catch 'https://codeberg.org/wownero/RandomWOW' (no .git)
git config --global url."http://oauth2:${GITHUB_TOKEN}@git.such.software:3000/Builds/RandomWOW.git".insteadOf "https://codeberg.org/wownero/RandomWOW"
# 2. Catch 'https://codeberg.org/wownero/RandomWOW.git' (with .git)
git config --global url."http://oauth2:${GITHUB_TOKEN}@git.such.software:3000/Builds/RandomWOW.git".insteadOf "https://codeberg.org/wownero/RandomWOW.git"
# 3. Main Clone
git clone http://oauth2:$GITHUB_TOKEN@git.such.software:3000/${{ github.repository }}.git .
# 4. Now update submodules (It will use the re-written URLs above)
git submodule update --init --recursive
- name: Download macOS SDK
if: contains(matrix.target, 'apple')
run: |
mkdir -p contrib/depends/SDKs
curl -L -k -o contrib/depends/SDKs/MacOSX10.15.sdk.tar.gz \
"https://github.com/phracker/MacOSX-SDKs/releases/download/10.15/MacOSX10.15.sdk.tar.gz"
- name: Install Modern CMake
run: |
echo "Installing CMake 3.28.1..."
curl -L -o cmake.tar.gz https://github.com/Kitware/CMake/releases/download/v3.28.1/cmake-3.28.1-linux-x86_64.tar.gz
tar -xf cmake.tar.gz
# Add new cmake to PATH
echo "$(pwd)/cmake-3.28.1-linux-x86_64/bin" >> $GITHUB_PATH
- name: Build Dependencies
run: |
cd contrib/depends
# This builds Boost 1.90.0 using your updated boost.mk
make HOST=${{ matrix.target }} -j$(nproc)
- name: Build Wownero Core
run: |
PREFIX=$(pwd)/contrib/depends/${{ matrix.target }}
mkdir build && cd build
# Use the new 'cmake' (v3.28)
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=../contrib/depends/${{ matrix.target }}/share/toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_STATIC=ON
make -j$(nproc)
- name: Package Artifacts
run: |
LIB_DIR="contrib/depends/${{ matrix.target }}/lib"
INC_DIR="contrib/depends/${{ matrix.target }}/include"
mkdir -p output/lib output/include output/bin
find build/bin -type f -exec cp {} output/bin/ \;
cp $LIB_DIR/*.a output/lib/
find build -name "*.a" -exec cp {} output/lib/ \;
cp -r src output/include/wownero-src
cp -r $INC_DIR/* output/include/
tar -czf wownero-core-${{ matrix.target }}.tar.gz -C output .
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: wownero-core-${{ matrix.target }}
path: wownero-core-${{ matrix.target }}.tar.gz
release:
needs: build-all
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Download Artifacts
uses: actions/download-artifact@v3
- name: Publish Release
uses: softprops/action-gh-release@v1
with:
files: |
wownero-core-*/wownero-core-*.tar.gz

6
.gitmodules vendored
View File

@@ -7,12 +7,6 @@
[submodule "external/trezor-common"]
path = external/trezor-common
url = https://github.com/trezor/trezor-common.git
[submodule "external/utf8proc"]
path = external/utf8proc
url = https://github.com/JuliaStrings/utf8proc.git
[submodule "external/polyseed"]
path = external/polyseed
url = https://github.com/tevador/polyseed.git
[submodule "external/supercop"]
path = external/supercop
url = https://github.com/monero-project/supercop

View File

@@ -370,8 +370,6 @@ if(NOT MANUAL_SUBMODULES)
check_submodule(external/trezor-common)
check_submodule(external/randomwow)
check_submodule(external/supercop)
check_submodule(external/polyseed)
check_submodule(external/utf8proc)
endif()
endif()
@@ -461,7 +459,7 @@ endif()
# elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*")
# set(BSDI TRUE)
include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include external/polyseed/include external/utf8proc)
include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include)
if(APPLE)
cmake_policy(SET CMP0042 NEW)

View File

@@ -104,7 +104,7 @@ release-all:
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 STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release $(topdir) && $(MAKE)
release-minimal:
@echo "Starting minimal Wownero build... for full build, run: make release-all"
@@ -137,23 +137,6 @@ release-static-android-armv8:
cd $(builddir)/release/translations && cmake ../../../translations && $(MAKE)
cd $(builddir)/release && CC=aarch64-linux-android-clang CXX=aarch64-linux-android-clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D ANDROID=true -D BUILD_TAG="android-armv8" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI="arm64-v8a" ../.. && $(MAKE)
release-static-android-armv7-wallet_api:
mkdir -p $(builddir)/release
cd $(builddir)/release && CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android-armv7" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARM_MODE=ON -D CMAKE_ANDROID_ARCH_ABI="armeabi-v7a" -D NO_AES=true ../.. && $(MAKE) wallet_api
release-static-android-armv8-wallet_api:
mkdir -p $(builddir)/release
cd $(builddir)/release && CC=aarch64-linux-android-clang CXX=aarch64-linux-android-clang++ cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android-armv8" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI="arm64-v8a" ../.. && $(MAKE) wallet_api
release-static-android-x86_64-wallet_api:
mkdir -p $(builddir)/release
cd $(builddir)/release && CC=x86_64-linux-android-clang CXX=x86_64-linux-android-clang++ cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH="x86-64" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android-x86_64" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI="x86_64" ../.. && $(MAKE) wallet_api
release-static-android-x86-wallet_api:
mkdir -p $(builddir)/release
cd $(builddir)/release && CC=i686-linux-android-clang CXX=i686-linux-android-clang++ cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH="i686" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D BUILD_TAG="android-x86" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI="x86" ../.. && $(MAKE) wallet_api
release-static-linux-armv8:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="linux-armv8" $(topdir) && $(MAKE)

View File

@@ -1,36 +1,38 @@
package=boost
$(package)_version=1.69.0
package=boost
$(package)_version=1.90.0
$(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz
$(package)_sha256_hash=9a2c2819310839ea373f42d69e733c339b4e9a19deab6bfec448281554aa4dbb
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.bz2
$(package)_sha256_hash=49551aff3b22cbc5c5a9ed3dbc92f0e23ea50a0f7325b0d198b705e8ee3fc305
$(package)_dependencies=libiconv
$(package)_patches=fix_aroptions.patch fix_arm_arch.patch
define $(package)_set_vars
$(package)_config_opts_release=variant=release
$(package)_config_opts_debug=variant=debug
$(package)_config_opts+=--layout=system --user-config=user-config.jam
$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1
$(package)_config_opts_linux=threadapi=pthread runtime-link=shared
$(package)_config_opts_android=threadapi=pthread runtime-link=static target-os=android
$(package)_config_opts_darwin=--toolset=darwin runtime-link=shared
$(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static
$(package)_config_opts_x86_64_mingw32=address-model=64
$(package)_config_opts_i686_mingw32=address-model=32
$(package)_config_opts_i686_linux=address-model=32 architecture=x86
$(package)_toolset_$(host_os)=gcc
$(package)_archiver_$(host_os)=$($(package)_ar)
$(package)_toolset_darwin=darwin
$(package)_archiver_darwin=$($(package)_libtool)
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
$(package)_cxxflags=-std=c++11
$(package)_cxxflags_linux=-fPIC
$(package)_cxxflags_freebsd=-fPIC
$(package)_config_opts_release=variant=release
$(package)_config_opts_debug=variant=debug
# KEY FIX: Use 'system' layout to avoid weird naming (libboost_filesystem.a vs libboost_filesystem-mt-x64.a)
$(package)_config_opts+=--layout=system --user-config=user-config.jam
$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1
# CRITICAL: Force static runtime for Linux to fix "Wrong Format" linker errors
$(package)_config_opts_linux=threadapi=pthread runtime-link=static
$(package)_config_opts_darwin=target-os=darwin address-model=64 runtime-link=shared
$(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static
$(package)_config_opts_x86_64_mingw32=address-model=64
$(package)_config_opts_i686_mingw32=address-model=32
$(package)_config_opts_i686_linux=address-model=32 architecture=x86
$(package)_toolset_$(host_os)=gcc
$(package)_archiver_$(host_os)=$($(package)_ar)
$(package)_toolset_darwin=darwin
$(package)_archiver_darwin=$($(package)_libtool)
# CRITICAL: Added context, coroutine (for LWS) and C++17 (for Monero v18)
# Added 'atomic' and 'chrono' just to be safe for all platforms.
$(package)_config_libraries=atomic,chrono,date_time,filesystem,program_options,regex,serialization,system,thread,locale,context,coroutine
$(package)_cxxflags=-std=c++17 -fPIC
endef
define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/fix_aroptions.patch &&\
patch -p1 < $($(package)_patch_dir)/fix_arm_arch.patch &&\
echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : <cxxflags>\"$($(package)_cxxflags) $($(package)_cppflags)\" <linkflags>\"$($(package)_ldflags)\" <archiver>\"$(boost_archiver_$(host_os))\" <arflags>\"$($(package)_arflags)\" <striper>\"$(host_STRIP)\" <ranlib>\"$(host_RANLIB)\" <rc>\"$(host_WINDRES)\" : ;" > user-config.jam
endef
@@ -44,4 +46,4 @@ endef
define $(package)_stage_cmds
./b2 -d0 -j4 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) install
endef
endef

View File

@@ -1,10 +1,9 @@
package=hidapi
$(package)_version=0.13.1
$(package)_version=0.15.0
$(package)_download_path=https://github.com/libusb/hidapi/archive/refs/tags
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=476a2c9a4dc7d1fc97dd223b84338dbea3809a84caea2dcd887d9778725490e3
$(package)_sha256_hash=5d84dec684c27b97b921d2f3b73218cb773cf4ea915caee317ac8fc73cef8136
$(package)_linux_dependencies=libusb eudev
$(package)_patches=missing_win_include.patch
define $(package)_set_vars
$(package)_config_opts=--enable-static --disable-shared
@@ -17,7 +16,7 @@ $(package)_config_opts_linux+=--with-pic
endef
define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/missing_win_include.patch && ./bootstrap
./bootstrap
endef
define $(package)_config_cmds

View File

@@ -1,21 +0,0 @@
From a77b066311da42ed7654e39c0356a3b951b2e296 Mon Sep 17 00:00:00 2001
From: selsta <selsta@sent.at>
Date: Wed, 10 Nov 2021 02:28:54 +0100
Subject: [PATCH] windows: add missing include for mingw32
---
windows/hid.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/windows/hid.c b/windows/hid.c
index 24756a4..6d8394c 100644
--- a/windows/hid.c
+++ b/windows/hid.c
@@ -33,6 +33,7 @@ typedef LONG NTSTATUS;
#endif
#ifdef __MINGW32__
+#include <devpropdef.h>
#include <ntdef.h>
#include <winbase.h>
#endif

View File

@@ -30,6 +30,7 @@
#ifdef __cplusplus
#include <sstream>
#include <string>
#include "easylogging++.h"
@@ -40,9 +41,15 @@
#define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes
#define MAX_LOG_FILES 50
#define LOG_TO_STRING(x) \
std::stringstream ss; \
ss << x; \
const std::string str = ss.str();
#define MCLOG_TYPE(level, cat, color, type, x) do { \
if (el::Loggers::allowed(level, cat)) { \
el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \
LOG_TO_STRING(x); \
el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << str; \
} \
} while (0)
@@ -91,7 +98,8 @@
do { \
if (el::Loggers::allowed(level, cat)) { \
init; \
el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \
LOG_TO_STRING(x); \
el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << str; \
} \
} while(0)
#define MIDEBUG(init, x) IFLOG(el::Level::Debug, MONERO_DEFAULT_LOG_CATEGORY, el::Color::Default, el::base::DispatchAction::NormalLog, init, x)

View File

@@ -34,6 +34,7 @@
#include <string>
#include <utility>
#include <list>
#include <cstdint>
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"

View File

@@ -34,7 +34,6 @@
#include <string>
#include "memwipe.h"
#include "fnv1.h"
#include "serialization/keyvalue_serialization.h"
namespace epee
{
@@ -76,12 +75,6 @@ namespace epee
bool operator!=(const wipeable_string &other) const noexcept { return buffer != other.buffer; }
wipeable_string &operator=(wipeable_string &&other);
wipeable_string &operator=(const wipeable_string &other);
char& operator[](size_t idx);
const char& operator[](size_t idx) const;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(buffer)
END_KV_SERIALIZE_MAP()
private:
void grow(size_t sz, size_t reserved = 0);

View File

@@ -261,14 +261,4 @@ wipeable_string &wipeable_string::operator=(const wipeable_string &other)
return *this;
}
char& wipeable_string::operator[](size_t idx) {
CHECK_AND_ASSERT_THROW_MES(idx < buffer.size(), "Index out of bounds");
return buffer[idx];
}
const char& wipeable_string::operator[](size_t idx) const {
CHECK_AND_ASSERT_THROW_MES(idx < buffer.size(), "Index out of bounds");
return buffer[idx];
}
}

View File

@@ -57,7 +57,7 @@ The dockrun.sh script will do everything to build the binaries. Just specify the
version to build as its only argument, e.g.
```bash
VERSION=v0.18.4.2
VERSION=v0.18.4.5
./dockrun.sh $VERSION
```

View File

@@ -133,7 +133,7 @@ Common setup part:
su - gitianuser
GH_USER=YOUR_GITHUB_USER_NAME
VERSION=v0.18.4.2
VERSION=v0.18.4.5
```
Where `GH_USER` is your GitHub user name and `VERSION` is the version tag you want to build.

View File

@@ -71,5 +71,3 @@ add_subdirectory(db_drivers)
add_subdirectory(easylogging++)
add_subdirectory(qrcodegen)
add_subdirectory(randomwow EXCLUDE_FROM_ALL)
add_subdirectory(polyseed EXCLUDE_FROM_ALL)
add_subdirectory(utf8proc EXCLUDE_FROM_ALL)

View File

@@ -1244,11 +1244,19 @@ std::string OS::currentHost(void) {
#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID
}
static bool endswith(const std::string &s, const std::string &ending)
{
return s.size() >= ending.size() && s.substr(s.size() - ending.size()) == ending;
}
bool OS::termSupportsColor(std::string& term) {
return term == "xterm" || term == "screen" || term == "linux" || term == "cygwin"
|| endswith(term, "-color") || endswith(term, "-256color");
}
bool OS::termSupportsColor(void) {
std::string term = getEnvironmentVariable("TERM", "");
return term == "xterm" || term == "xterm-color" || term == "xterm-256color"
|| term == "screen" || term == "linux" || term == "cygwin"
|| term == "screen-256color" || term == "screen.xterm-256color";
return termSupportsColor(term);
}
// DateTime
@@ -3057,8 +3065,9 @@ void Writer::triggerDispatch(void) {
}
if (m_proceed && m_level == Level::Fatal
&& !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) {
const std::string str = "Aborting application. Reason: Fatal log at [" + std::string(m_file) + ":" + std::to_string(m_line) + "]";
base::Writer(Level::Warning, Color::Default, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
<< "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]";
<< str;
std::stringstream reasonStream;
reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
<< " If you wish to disable 'abort on fatal log' please use "

View File

@@ -1210,7 +1210,9 @@ class OS : base::StaticClass {
///
/// @detail For android systems this is device name with its manufacturer and model seperated by hyphen
static std::string currentHost(void);
/// @brief Whether or not terminal supports colors
/// @brief Whether or not the named terminal supports colors
static bool termSupportsColor(std::string& term);
/// @brief Whether or not the process's current terminal supports colors
static bool termSupportsColor(void);
};
/// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str
@@ -3272,9 +3274,7 @@ class Writer : base::NoCopy {
processDispatch();
}
template <typename T>
inline typename std::enable_if<std::is_integral<T>::value, Writer&>::type
operator<<(T log) {
Writer& operator<<(const std::string &log) {
#if ELPP_LOGGING_ENABLED
if (m_proceed) {
m_messageBuilder << log;
@@ -3283,26 +3283,6 @@ class Writer : base::NoCopy {
return *this;
}
template <typename T>
inline typename std::enable_if<!std::is_integral<T>::value, Writer&>::type
operator<<(const T& log) {
#if ELPP_LOGGING_ENABLED
if (m_proceed) {
m_messageBuilder << log;
}
#endif // ELPP_LOGGING_ENABLED
return *this;
}
inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) {
#if ELPP_LOGGING_ENABLED
if (m_proceed) {
m_messageBuilder << log;
}
#endif // ELPP_LOGGING_ENABLED
return *this;
}
inline operator bool() {
return true;
}
@@ -3619,8 +3599,9 @@ class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback {
ss << ELPP_LITERAL("]");
}
}
const std::string str = ss.str();
el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1,
m_data->loggerId().c_str()) << ss.str();
m_data->loggerId().c_str()) << str;
}
private:
const PerformanceTrackingData* m_data;

1
external/polyseed vendored

Submodule external/polyseed deleted from dfb05d8edb

1
external/utf8proc vendored

Submodule external/utf8proc deleted from 1cb28a66ca

View File

@@ -95,7 +95,6 @@ add_subdirectory(net)
add_subdirectory(hardforks)
add_subdirectory(blockchain_db)
add_subdirectory(mnemonics)
add_subdirectory(polyseed)
add_subdirectory(rpc)
if(NOT IOS)
add_subdirectory(serialization)

View File

@@ -71,7 +71,6 @@ target_link_libraries(cryptonote_basic
checkpoints
cryptonote_format_utils_basic
device
polyseed_wrapper
${Boost_DATE_TIME_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}

View File

@@ -87,16 +87,12 @@ DISABLE_VS_WARNINGS(4244 4345)
void account_keys::xor_with_key_stream(const crypto::chacha_key &key)
{
// encrypt a large enough byte stream with chacha20
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (3 + m_multisig_keys.size()) + m_passphrase.size());
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size()));
const char *ptr = key_stream.data();
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
m_spend_secret_key.data[i] ^= *ptr++;
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
m_view_secret_key.data[i] ^= *ptr++;
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
m_polyseed.data[i] ^= *ptr++;
for (size_t i = 0; i < m_passphrase.size(); ++i)
m_passphrase.data()[i] ^= *ptr++;
for (crypto::secret_key &k: m_multisig_keys)
{
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
@@ -154,8 +150,6 @@ DISABLE_VS_WARNINGS(4244 4345)
{
m_keys.m_spend_secret_key = crypto::secret_key();
m_keys.m_multisig_keys.clear();
m_keys.m_polyseed = crypto::secret_key();
m_keys.m_passphrase.wipe();
}
//-----------------------------------------------------------------
void account_base::set_spend_key(const crypto::secret_key& spend_secret_key)
@@ -261,21 +255,6 @@ DISABLE_VS_WARNINGS(4244 4345)
create_from_keys(address, fake, viewkey);
}
//-----------------------------------------------------------------
void account_base::create_from_polyseed(const polyseed::data& seed, const epee::wipeable_string &passphrase)
{
crypto::secret_key secret_key;
seed.keygen(&secret_key, sizeof(secret_key));
if (!passphrase.empty()) {
secret_key = cryptonote::decrypt_key(secret_key, passphrase);
}
generate(secret_key, true, false);
seed.save(m_keys.m_polyseed.data);
m_keys.m_passphrase = passphrase;
}
//-----------------------------------------------------------------
bool account_base::make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys)
{
m_keys.m_account_address.m_spend_public_key = spend_public_key;

View File

@@ -33,7 +33,6 @@
#include "cryptonote_basic.h"
#include "crypto/crypto.h"
#include "serialization/keyvalue_serialization.h"
#include "polyseed/polyseed.hpp"
namespace cryptonote
{
@@ -46,8 +45,6 @@ namespace cryptonote
std::vector<crypto::secret_key> m_multisig_keys;
hw::device *m_device = &hw::get_device("default");
crypto::chacha_iv m_encryption_iv;
crypto::secret_key m_polyseed;
epee::wipeable_string m_passphrase; // Only used with polyseed
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_account_address)
@@ -56,8 +53,6 @@ namespace cryptonote
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys)
const crypto::chacha_iv default_iv{{0, 0, 0, 0, 0, 0, 0, 0}};
KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_polyseed)
KV_SERIALIZE(m_passphrase)
END_KV_SERIALIZE_MAP()
void encrypt(const crypto::chacha_key &key);
@@ -84,7 +79,6 @@ namespace cryptonote
void create_from_device(hw::device &hwdev);
void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey);
void create_from_polyseed(const polyseed::data &polyseed, const epee::wipeable_string &passphrase);
bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys);
const account_keys& get_keys() const;
std::string get_public_address_str(network_type nettype) const;

View File

@@ -223,8 +223,6 @@
#define DNS_BLOCKLIST_LIFETIME (86400 * 8)
#define POLYSEED_COIN POLYSEED_MONERO
//The limit is enough for the mandatory transaction content with 16 outputs (547 bytes),
//a custom tag (1 byte) and up to 32 bytes of custom data for each recipient.
// (1+32) + (1+1+16*32) + (1+16*32) = 1060

View File

@@ -728,13 +728,13 @@ crypto::hash Blockchain::get_tail_id() const
* powers of 2 less recent from there, so 13, 17, 25, etc...
*
*/
bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids, uint64_t& current_height) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
uint64_t i = 0;
uint64_t current_multiplier = 1;
uint64_t sz = m_db->height();
uint64_t sz = current_height = m_db->height();
if(!sz)
return true;

View File

@@ -445,10 +445,11 @@ namespace cryptonote
* powers of 2 less recent from there, so 13, 17, 25, etc...
*
* @param ids return-by-reference list to put the resulting hashes in
* @param current_height the current blockchain height, return-by-reference
*
* @return true
*/
bool get_short_chain_history(std::list<crypto::hash>& ids) const;
bool get_short_chain_history(std::list<crypto::hash>& ids, uint64_t& current_height) const;
/**
* @brief get recent block hashes for a foreign chain

View File

@@ -1302,20 +1302,23 @@ namespace cryptonote
NOTIFY_NEW_FLUFFY_BLOCK::request arg{};
arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height();
std::vector<crypto::hash> missed_txs;
std::vector<cryptonote::blobdata> txs;
m_blockchain_storage.get_transactions_blobs(b.tx_hashes, txs, missed_txs);
for (const auto &tx_hash : b.tx_hashes)
{
if (m_blockchain_storage.have_tx(tx_hash))
continue;
missed_txs.push_back(tx_hash);
}
if(missed_txs.size() && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b))
{
LOG_PRINT_L1("Block found but, seems that reorganize just happened after that, do not relay this block");
return true;
}
CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size() && !missed_txs.size(), false, "can't find some transactions in found block:" << get_block_hash(b) << " txs.size()=" << txs.size()
<< ", b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()" << missed_txs.size());
CHECK_AND_ASSERT_MES(!missed_txs.size(), false, "can't find some transactions in found block:" << get_block_hash(b)
<< " b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()" << missed_txs.size());
block_to_blob(b, arg.b.block);
//pack transactions
for(auto& tx: txs)
arg.b.txs.push_back({tx, crypto::null_hash});
// Relay an empty fluffy block
arg.b.txs.clear();
m_pprotocol->relay_block(arg, exclude_context);
}
@@ -1533,9 +1536,9 @@ namespace cryptonote
return m_mempool.get_pool_for_rpc(tx_infos, key_image_infos);
}
//-----------------------------------------------------------------------------------------------
bool core::get_short_chain_history(std::list<crypto::hash>& ids) const
bool core::get_short_chain_history(std::list<crypto::hash>& ids, uint64_t& current_height) const
{
return m_blockchain_storage.get_short_chain_history(ids);
return m_blockchain_storage.get_short_chain_history(ids, current_height);
}
//-----------------------------------------------------------------------------------------------
bool core::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote_connection_context& context)

View File

@@ -580,7 +580,7 @@ namespace cryptonote
*
* @note see Blockchain::get_short_chain_history
*/
bool get_short_chain_history(std::list<crypto::hash>& ids) const;
bool get_short_chain_history(std::list<crypto::hash>& ids, uint64_t& current_height) const;
/**
* @copydoc Blockchain::find_blockchain_supplement(const std::list<crypto::hash>&, NOTIFY_RESPONSE_CHAIN_ENTRY::request&) const

View File

@@ -344,7 +344,8 @@ namespace cryptonote
}
tvc.m_verifivation_failed = false;
m_txpool_weight += tx_weight;
if (tvc.m_added_to_pool)
m_txpool_weight += tx_weight;
++m_cookie;

View File

@@ -153,18 +153,26 @@ uint64_t block_queue::get_next_needed_height(uint64_t blockchain_height) const
boost::unique_lock<boost::recursive_mutex> lock(mutex);
if (blocks.empty())
return blockchain_height;
uint64_t last_needed_height = blockchain_height;
bool first = true;
uint64_t covered_until = blockchain_height;
for (const auto &span: blocks)
{
if (span.start_block_height + span.nblocks - 1 < blockchain_height)
// Ignore spans entirely below current chain height
const uint64_t span_end = span.start_block_height + span.nblocks - 1;
if (span_end < blockchain_height)
continue;
if (span.start_block_height != last_needed_height || (first && span.blocks.empty()))
return last_needed_height;
last_needed_height = span.start_block_height + span.nblocks;
first = false;
// If this span starts after what we already have/scheduled, we found the first gap
if (span.start_block_height > covered_until)
return covered_until;
// This span overlaps or is adjacent; extend coverage regardless of filled/scheduled
if (span.start_block_height <= covered_until)
covered_until = std::max(covered_until, span.start_block_height + span.nblocks);
}
return last_needed_height;
return covered_until;
}
void block_queue::print() const

View File

@@ -44,6 +44,7 @@
#include "net/network_throttle-detail.hpp"
#include "common/pruning.h"
#include "common/util.h"
#include "misc_log_ex.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
@@ -55,8 +56,10 @@
const char *cat = "net.p2p.msg"; \
if (ELPP->vRegistry()->allowed(level, cat)) { \
init; \
if (test) \
el::base::Writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << x; \
if (test) { \
LOG_TO_STRING(x); \
el::base::Writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << str; \
} \
} \
} while(0)
@@ -271,8 +274,7 @@ namespace cryptonote
{
NOTIFY_REQUEST_CHAIN::request r = {};
context.m_needed_objects.clear();
context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks;
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
@@ -727,8 +729,7 @@ namespace cryptonote
context.m_needed_objects.clear();
context.m_state = cryptonote_connection_context::state_synchronizing;
NOTIFY_REQUEST_CHAIN::request r = {};
context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks;
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
@@ -2351,8 +2352,7 @@ skip:
{//we have to fetch more objects ids, request blockchain entry
NOTIFY_REQUEST_CHAIN::request r = {};
context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
// we'll want to start off from where we are on that peer, which may not be added yet
@@ -2488,7 +2488,7 @@ skip:
int t_cryptonote_protocol_handler<t_core>::handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context)
{
MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height << ", expect height=" << context.m_expect_height);
MLOG_PEER_STATE("received chain");
if (context.m_expect_response != NOTIFY_RESPONSE_CHAIN_ENTRY::ID)

View File

@@ -409,7 +409,7 @@ namespace hw {
this->length_send = set_command_header_noopt(ins, p1);
if (ins == INS_GET_KEY && p1 == IO_SECRET_KEY) {
// export view key user input
this->exchange_wait_on_input();
CHECK_AND_ASSERT_THROW_MES(this->exchange_wait_on_input() == 0, "Key export rejected on device.");
} else {
this->exchange();
}
@@ -528,6 +528,7 @@ namespace hw {
{0x2c97, 0x0005, 0, 0xffa0},
{0x2c97, 0x0006, 0, 0xffa0},
{0x2c97, 0x0007, 0, 0xffa0},
{0x2c97, 0x0008, 0, 0xffa0},
};
bool device_ledger::connect(void) {
@@ -618,15 +619,14 @@ namespace hw {
send_simple(INS_GET_KEY, 0x02);
//View key is retrievied, if allowed, to speed up blockchain parsing
memmove(this->viewkey.data, this->buffer_recv+0, 32);
if (is_fake_view_key(this->viewkey)) {
MDEBUG("Have Not view key");
this->has_view_key = false;
} else {
MDEBUG("Have view key");
this->has_view_key = true;
}
crypto::secret_key view_secret_key;
memmove(view_secret_key.data, this->buffer_recv+0, 32);
CHECK_AND_ASSERT_THROW_MES(!is_fake_view_key(view_secret_key), "Key export rejected on device.");
this->viewkey = view_secret_key;
this->has_view_key = true;
#ifdef DEBUG_HWDEVICE
send_simple(INS_GET_KEY, 0x04);
memmove(dbg_viewkey.data, this->buffer_recv+0, 32);

View File

@@ -177,8 +177,8 @@ namespace hw {
HMACmap hmac_map;
// To speed up blockchain parsing the view key maybe handle here.
crypto::secret_key viewkey;
bool has_view_key;
crypto::secret_key viewkey = crypto::null_skey;
bool has_view_key = false;
device *controle_device;

View File

@@ -1,25 +0,0 @@
set(polyseed_sources
pbkdf2.c
polyseed.cpp
)
monero_find_all_headers(polyseed_private_headers "${CMAKE_CURRENT_SOURCE_DIR}")
monero_private_headers(polyseed_wrapper
${polyseed_private_headers}
)
monero_add_library(polyseed_wrapper
${polyseed_sources}
${polyseed_headers}
${polyseed_private_headers}
)
target_link_libraries(polyseed_wrapper
PUBLIC
polyseed
utf8proc
${SODIUM_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES}
)

View File

@@ -1,85 +0,0 @@
// Copyright (c) 2023, The Monero Project
// Copyright (c) 2021, tevador <tevador@gmail.com>
// Copyright (c) 2005,2007,2009 Colin Percival
//
// 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.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <string.h>
#include <sodium/crypto_auth_hmacsha256.h>
#include <sodium/utils.h>
static inline void
store32_be(uint8_t dst[4], uint32_t w)
{
dst[3] = (uint8_t) w; w >>= 8;
dst[2] = (uint8_t) w; w >>= 8;
dst[1] = (uint8_t) w; w >>= 8;
dst[0] = (uint8_t) w;
}
void
crypto_pbkdf2_sha256(const uint8_t* passwd, size_t passwdlen,
const uint8_t* salt, size_t saltlen, uint64_t c,
uint8_t* buf, size_t dkLen)
{
crypto_auth_hmacsha256_state Phctx, PShctx, hctx;
size_t i;
uint8_t ivec[4];
uint8_t U[32];
uint8_t T[32];
uint64_t j;
int k;
size_t clen;
crypto_auth_hmacsha256_init(&Phctx, passwd, passwdlen);
PShctx = Phctx;
crypto_auth_hmacsha256_update(&PShctx, salt, saltlen);
for (i = 0; i * 32 < dkLen; i++) {
store32_be(ivec, (uint32_t)(i + 1));
hctx = PShctx;
crypto_auth_hmacsha256_update(&hctx, ivec, 4);
crypto_auth_hmacsha256_final(&hctx, U);
memcpy(T, U, 32);
for (j = 2; j <= c; j++) {
hctx = Phctx;
crypto_auth_hmacsha256_update(&hctx, U, 32);
crypto_auth_hmacsha256_final(&hctx, U);
for (k = 0; k < 32; k++) {
T[k] ^= U[k];
}
}
clen = dkLen - i * 32;
if (clen > 32) {
clen = 32;
}
memcpy(&buf[i * 32], T, clen);
}
sodium_memzero((void*)&Phctx, sizeof Phctx);
sodium_memzero((void*)&PShctx, sizeof PShctx);
}

View File

@@ -1,46 +0,0 @@
// Copyright (c) 2023, The Monero Project
// Copyright (c) 2021, tevador <tevador@gmail.com>
//
// 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.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
#ifndef PBKDF2_H
#define PBKDF2_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void
crypto_pbkdf2_sha256(const uint8_t* passwd, size_t passwdlen,
const uint8_t* salt, size_t saltlen, uint64_t c,
uint8_t* buf, size_t dkLen);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,182 +0,0 @@
// Copyright (c) 2023, The Monero Project
// Copyright (c) 2021, tevador <tevador@gmail.com>
//
// 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.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 "polyseed.hpp"
#include "pbkdf2.h"
#include <sodium/core.h>
#include <sodium/utils.h>
#include <sodium/randombytes.h>
#include <utf8proc.h>
#include <cstring>
#include <algorithm>
#include <array>
namespace polyseed {
inline size_t utf8_norm(const char* str, polyseed_str norm, utf8proc_option_t options) {
utf8proc_int32_t buffer[POLYSEED_STR_SIZE];
utf8proc_ssize_t result;
result = utf8proc_decompose(reinterpret_cast<const uint8_t*>(str), 0, buffer, POLYSEED_STR_SIZE, options);
if (result < 0) {
return POLYSEED_STR_SIZE;
}
if (result > POLYSEED_STR_SIZE - 1) {
return result;
}
result = utf8proc_reencode(buffer, result, options);
strcpy(norm, reinterpret_cast<const char*>(buffer));
sodium_memzero(buffer, POLYSEED_STR_SIZE);
return result;
}
static size_t utf8_nfc(const char* str, polyseed_str norm) {
// Note: UTF8PROC_LUMP is used here to replace the ideographic space with a regular space for Japanese phrases
// to allow wallets to split on ' '.
return utf8_norm(str, norm, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE | UTF8PROC_STRIPNA | UTF8PROC_LUMP));
}
static size_t utf8_nfkd(const char* str, polyseed_str norm) {
return utf8_norm(str, norm, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT | UTF8PROC_STRIPNA));
}
struct dependency {
dependency();
std::vector<language> languages;
};
static dependency deps;
dependency::dependency() {
if (sodium_init() == -1) {
throw std::runtime_error("sodium_init failed");
}
polyseed_dependency pd;
pd.randbytes = &randombytes_buf;
pd.pbkdf2_sha256 = &crypto_pbkdf2_sha256;
pd.memzero = &sodium_memzero;
pd.u8_nfc = &utf8_nfc;
pd.u8_nfkd = &utf8_nfkd;
pd.time = nullptr;
pd.alloc = nullptr;
pd.free = nullptr;
polyseed_inject(&pd);
for (int i = 0; i < polyseed_get_num_langs(); ++i) {
languages.push_back(language(polyseed_get_lang(i)));
}
}
static language invalid_lang;
const std::vector<language>& get_langs() {
return deps.languages;
}
const language& get_lang_by_name(const std::string& name) {
for (auto& lang : deps.languages) {
if (name == lang.name_en()) {
return lang;
}
if (name == lang.name()) {
return lang;
}
}
return invalid_lang;
}
inline void data::check_init() const {
if (valid()) {
throw std::runtime_error("already initialized");
}
}
static std::array<const char*, 8> error_desc = {
"Success",
"Wrong number of words in the phrase",
"Unknown language or unsupported words",
"Checksum mismatch",
"Unsupported seed features",
"Invalid seed format",
"Memory allocation failure",
"Unicode normalization failed"
};
static error get_error(polyseed_status status) {
if (status > 0 && status < sizeof(error_desc) / sizeof(const char*)) {
return error(error_desc[(int)status], status);
}
return error("Unknown error", status);
}
void data::create(feature_type features) {
check_init();
auto status = polyseed_create(features, &m_data);
if (status != POLYSEED_OK) {
throw get_error(status);
}
}
void data::split(const language& lang, polyseed_phrase& words) {
check_init();
if (!lang.valid()) {
throw std::runtime_error("invalid language");
}
}
void data::load(polyseed_storage storage) {
check_init();
auto status = polyseed_load(storage, &m_data);
if (status != POLYSEED_OK) {
throw get_error(status);
}
}
void data::load(const crypto::secret_key &key) {
polyseed_storage d;
memcpy(&d, &key.data, 32);
auto status = polyseed_load(d, &m_data);
if (status != POLYSEED_OK) {
throw get_error(status);
}
}
language data::decode(const char* phrase) {
check_init();
const polyseed_lang* lang;
auto status = polyseed_decode(phrase, m_coin, &lang, &m_data);
if (status != POLYSEED_OK) {
throw get_error(status);
}
return language(lang);
}
}

View File

@@ -1,167 +0,0 @@
// Copyright (c) 2023, The Monero Project
// Copyright (c) 2021, tevador <tevador@gmail.com>
//
// 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.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
#ifndef POLYSEED_HPP
#define POLYSEED_HPP
#include <polyseed/include/polyseed.h>
#include <polyseed/src/lang.h>
#include <vector>
#include <stdexcept>
#include <string>
#include "crypto/crypto.h"
namespace polyseed {
class data;
class language {
public:
language() : m_lang(nullptr) {}
language(const language&) = default;
language(const polyseed_lang* lang) : m_lang(lang) {}
const char* name() const {
return polyseed_get_lang_name(m_lang);
}
const char* name_en() const {
return polyseed_get_lang_name_en(m_lang);
}
const char* separator() const {
return m_lang->separator;
}
bool valid() const {
return m_lang != nullptr;
}
const polyseed_lang* m_lang;
private:
friend class data;
};
const std::vector<language>& get_langs();
const language& get_lang_by_name(const std::string& name);
class error : public std::runtime_error {
public:
error(const char* msg, polyseed_status status)
: std::runtime_error(msg), m_status(status)
{
}
polyseed_status status() const {
return m_status;
}
private:
polyseed_status m_status;
};
using feature_type = unsigned int;
inline int enable_features(feature_type features) {
return polyseed_enable_features(features);
}
class data {
public:
data(const data&) = delete;
data(polyseed_coin coin) : m_data(nullptr), m_coin(coin) {}
~data() {
polyseed_free(m_data);
}
void create(feature_type features);
void load(polyseed_storage storage);
void load(const crypto::secret_key &key);
language decode(const char* phrase);
template<class str_type>
void encode(const language& lang, str_type& str) const {
check_valid();
if (!lang.valid()) {
throw std::runtime_error("invalid language");
}
str.resize(POLYSEED_STR_SIZE);
auto size = polyseed_encode(m_data, lang.m_lang, m_coin, &str[0]);
str.resize(size);
}
void split(const language& lang, polyseed_phrase& words);
void save(polyseed_storage storage) const {
check_valid();
polyseed_store(m_data, storage);
}
void save(void *storage) const {
check_valid();
polyseed_store(m_data, (uint8_t*)storage);
}
void crypt(const char* password) {
check_valid();
polyseed_crypt(m_data, password);
}
void keygen(void* ptr, size_t key_size) const {
check_valid();
polyseed_keygen(m_data, m_coin, key_size, (uint8_t*)ptr);
}
bool valid() const {
return m_data != nullptr;
}
bool encrypted() const {
check_valid();
return polyseed_is_encrypted(m_data);
}
uint64_t birthday() const {
check_valid();
return polyseed_get_birthday(m_data);
}
bool has_feature(feature_type feature) const {
check_valid();
return polyseed_get_feature(m_data, feature) != 0;
}
private:
void check_valid() const {
if (m_data == nullptr) {
throw std::runtime_error("invalid object");
}
}
void check_init() const;
polyseed_data* m_data;
polyseed_coin m_coin;
};
}
#endif //POLYSEED_HPP

View File

@@ -3428,7 +3428,7 @@ simple_wallet::simple_wallet()
tr("Show the blockchain height."));
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::on_command, this, &simple_wallet::transfer, _1),
tr(USAGE_TRANSFER),
tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included). The \"subtractfeefrom=\" list allows you to choose which destinations to fund the tx fee from instead of the change output. The fee will be split across the chosen destinations proportionally equally. For example, to make 3 transfers where the fee is taken from the first and third destinations, one could do: \"transfer <addr1> 3 <addr2> 0.5 <addr3> 1 subtractfeefrom=0,2\". Let's say the tx fee is 0.1. The balance would drop by exactly 4.5 XMR including fees, and addr1 & addr3 would receive 2.925 & 0.975 XMR, respectively. Use \"subtractfeefrom=all\" to spread the fee across all destinations."));
tr("Transfer <address> <amount>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included). The \"subtractfeefrom=\" list allows you to choose which destinations to fund the tx fee from instead of the change output. The fee will be split across the chosen destinations proportionally equally. For example, to make 3 transfers where the fee is taken from the first and third destinations, one could do: \"transfer <addr1> 3 <addr2> 0.5 <addr3> 1 subtractfeefrom=0,2\". Let's say the tx fee is 0.1. The balance would drop by exactly 4.5 XMR including fees, and addr1 & addr3 would receive 2.925 & 0.975 XMR, respectively. Use \"subtractfeefrom=all\" to spread the fee across all destinations."));
m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_unmixable, _1),
tr("Send all unmixable outputs to yourself with ring_size 1"));
@@ -5833,7 +5833,7 @@ bool simple_wallet::save_bc(const std::vector<std::string>& args)
return true;
}
//----------------------------------------------------------------------------------------------------
void simple_wallet::on_new_block(uint64_t height, bool last, const cryptonote::block& block)
void simple_wallet::on_new_block(uint64_t height, const cryptonote::block& block)
{
if (m_locked)
return;
@@ -6971,7 +6971,7 @@ bool simple_wallet::transfer_main(const std::vector<std::string> &args_, bool ca
{
// figure out what tx will be necessary
auto ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, priority, extra,
m_current_subaddress_account, subaddr_indices, {}, subtract_fee_from_outputs);
m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
if (ptx_vector.empty())
{

View File

@@ -345,7 +345,7 @@ namespace cryptonote
bool check_daemon_rpc_prices(const std::string &daemon_url, uint32_t &actual_cph, uint32_t &claimed_cph);
//----------------- i_wallet2_callback ---------------------
virtual void on_new_block(uint64_t height, bool last, const cryptonote::block& block);
virtual void on_new_block(uint64_t height, const cryptonote::block& block);
virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time);
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index);
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index);

View File

@@ -47,7 +47,6 @@
#include <boost/locale.hpp>
#include <boost/filesystem.hpp>
#include <vector>
using namespace std;
using namespace cryptonote;
@@ -176,7 +175,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
return m_listener;
}
virtual void on_new_block(uint64_t height, bool last, const cryptonote::block& block)
virtual void on_new_block(uint64_t height, const cryptonote::block& block)
{
// Don't flood the GUI with signals. On fast refresh - send signal every 1000th block
// get_refresh_from_block_height() returns the blockheight from when the wallet was
@@ -184,7 +183,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
if(height >= m_wallet->m_wallet->get_refresh_from_block_height() || height % 1000 == 0) {
// LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height);
if (m_listener) {
m_listener->newBlock(height, last);
m_listener->newBlock(height);
}
}
}
@@ -245,10 +244,10 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
// Light wallet callbacks
virtual void on_lw_new_block(uint64_t height, bool last)
virtual void on_lw_new_block(uint64_t height)
{
if (m_listener) {
m_listener->newBlock(height, last);
m_listener->newBlock(height);
}
}
@@ -725,28 +724,6 @@ bool WalletImpl::recoverFromDevice(const std::string &path, const std::string &p
return true;
}
bool WalletImpl::createFromPolyseed(const std::string &path, const std::string &password, const std::string &seed,
const std::string &passphrase, bool newWallet, uint64_t restoreHeight)
{
clearStatus();
m_recoveringFromSeed = !newWallet;
m_recoveringFromDevice = false;
polyseed::data polyseed(POLYSEED_COIN);
try {
auto lang = polyseed.decode(seed.data());
m_wallet->set_seed_language(lang.name());
m_wallet->generate(path, password, polyseed, passphrase, !newWallet);
}
catch (const std::exception &e) {
setStatusError(e.what());
return false;
}
return true;
}
Wallet::Device WalletImpl::getDeviceType() const
{
return static_cast<Wallet::Device>(m_wallet->get_device_type());
@@ -857,55 +834,6 @@ std::string WalletImpl::seed(const std::string& seed_offset) const
return std::string(seed.data(), seed.size()); // TODO
}
bool WalletImpl::getPolyseed(std::string &seed_words, std::string &passphrase) const
{
epee::wipeable_string seed_words_epee(seed_words.c_str(), seed_words.size());
epee::wipeable_string passphrase_epee(passphrase.c_str(), passphrase.size());
clearStatus();
if (!m_wallet) {
return false;
}
bool result = m_wallet->get_polyseed(seed_words_epee, passphrase_epee);
seed_words.assign(seed_words_epee.data(), seed_words_epee.size());
passphrase.assign(passphrase_epee.data(), passphrase_epee.size());
return result;
}
std::vector<std::pair<std::string, std::string>> Wallet::getPolyseedLanguages()
{
std::vector<std::pair<std::string, std::string>> languages;
auto langs = polyseed::get_langs();
for (const auto &lang : langs) {
languages.emplace_back(std::pair<std::string, std::string>(lang.name_en(), lang.name()));
}
return languages;
}
bool Wallet::createPolyseed(std::string &seed_words, std::string &err, const std::string &language)
{
epee::wipeable_string seed_words_epee(seed_words.c_str(), seed_words.size());
try {
polyseed::data polyseed(POLYSEED_COIN);
polyseed.create(0);
polyseed.encode(polyseed::get_lang_by_name(language), seed_words_epee);
seed_words.assign(seed_words_epee.data(), seed_words_epee.size());
}
catch (const std::exception &e) {
err = e.what();
return false;
}
return true;
}
std::string WalletImpl::getSeedLanguage() const
{
return m_wallet->get_seed_language();
@@ -1730,7 +1658,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat
// - unconfirmed_transfer_details;
// - confirmed_transfer_details)
PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<string> &dst_addr, const string &payment_id, optional<std::vector<uint64_t>> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::set<std::string> &preferred_inputs)
PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<string> &dst_addr, const string &payment_id, optional<std::vector<uint64_t>> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
clearStatus();
@@ -1799,19 +1727,6 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
}
}
}
std::vector<crypto::key_image> preferred_input_list;
if (!preferred_inputs.empty()) {
for (const auto &public_key : preferred_inputs) {
crypto::key_image keyImage;
bool r = epee::string_tools::hex_to_pod(public_key, keyImage);
if (!r) {
error = true;
setStatusError(tr("failed to parse key image"));
break;
}
preferred_input_list.push_back(keyImage);
}
}
if (error) {
break;
}
@@ -1826,11 +1741,11 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
if (amount) {
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count,
adjusted_priority,
extra, subaddr_account, subaddr_indices, preferred_input_list);
extra, subaddr_account, subaddr_indices);
} else {
transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count,
adjusted_priority,
extra, subaddr_account, subaddr_indices, preferred_input_list);
extra, subaddr_account, subaddr_indices);
}
pendingTxPostProcess(transaction);
@@ -1911,10 +1826,10 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
}
PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::set<std::string> &preferred_inputs)
PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices, preferred_inputs);
return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices);
}
PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
@@ -2040,56 +1955,6 @@ AddressBook *WalletImpl::addressBook()
return m_addressBook.get();
}
std::vector<Enote> WalletImpl::enotes()
{
LOG_PRINT_L2("Refreshing coins");
boost::shared_lock<boost::shared_mutex> transfers_lock(m_wallet->m_transfers_mutex);
std::vector<Enote> enotes;
for (size_t i = 0; i < m_wallet->get_num_transfer_details(); ++i)
{
const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(i);
Enote enote;
enote.idx = i;
enote.blockHeight = td.m_block_height;
enote.hash = epee::string_tools::pod_to_hex(td.m_txid);
enote.internalOutputIndex = td.m_internal_output_index;
enote.globalOutputIndex = td.m_global_output_index;
enote.spent = td.m_spent;
enote.frozen = td.m_frozen;
enote.spentHeight = td.m_spent_height;
enote.amount = td.m_amount;
enote.rct = td.m_rct;
enote.keyImageKnown = td.m_key_image_known;
enote.pkIndex = td.m_pk_index;
enote.subaddrIndex = td.m_subaddr_index.minor;
enote.subaddrAccount = td.m_subaddr_index.major;
enote.address = m_wallet->get_subaddress_as_str(td.m_subaddr_index); // todo: this is expensive, cache maybe?
enote.addressLabel = m_wallet->get_subaddress_label(td.m_subaddr_index);
enote.keyImage = epee::string_tools::pod_to_hex(td.m_key_image);
enote.unlockTime = td.m_tx.unlock_time;
enote.unlocked = m_wallet->is_transfer_unlocked(td);
enote.pubKey = epee::string_tools::pod_to_hex(td.get_public_key());
enote.coinbase = td.m_tx.vin.size() == 1 && td.m_tx.vin[0].type() == typeid(cryptonote::txin_gen);
enote.description = m_wallet->get_tx_note(td.m_txid);
enotes.push_back(enote);
}
return enotes;
}
void WalletImpl::freeze(size_t idx) {
m_wallet->freeze(idx);
}
void WalletImpl::thaw(size_t idx) {
m_wallet->thaw(idx);
}
Subaddress *WalletImpl::subaddress()
{
return m_subaddress.get();

View File

@@ -79,19 +79,9 @@ public:
bool recoverFromDevice(const std::string &path,
const std::string &password,
const std::string &device_name);
bool createFromPolyseed(const std::string &path,
const std::string &password,
const std::string &seed,
const std::string &passphrase = "",
bool newWallet = true,
uint64_t restoreHeight = 0);
Device getDeviceType() const override;
bool close(bool store = true);
std::string seed(const std::string& seed_offset = "") const override;
bool getPolyseed(std::string &seed_words, std::string &passphrase) const override;
std::string getSeedLanguage() const override;
void setSeedLanguage(const std::string &arg) override;
// void setListener(Listener *) {}
@@ -166,14 +156,12 @@ public:
optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {},
const std::set<std::string> &preferred_inputs = {}) override;
std::set<uint32_t> subaddr_indices = {}) override;
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {},
const std::set<std::string> &preferred_inputs = {}) override;
std::set<uint32_t> subaddr_indices = {}) override;
virtual PendingTransaction * createSweepUnmixableTransaction() override;
bool submitTransaction(const std::string &fileName) override;
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override;
@@ -195,9 +183,6 @@ public:
PendingTransaction::Priority priority) const override;
virtual TransactionHistory * history() override;
virtual AddressBook * addressBook() override;
virtual std::vector<Enote> enotes() override;
virtual void freeze(size_t idx) override;
virtual void thaw(size_t idx) override;
virtual Subaddress * subaddress() override;
virtual SubaddressAccount * subaddressAccount() override;
virtual void setListener(WalletListener * l) override;

View File

@@ -32,7 +32,6 @@
#include <string>
#include <utility>
#include <vector>
#include <list>
#include <set>
@@ -262,35 +261,6 @@ struct AddressBook
virtual int lookupPaymentID(const std::string &payment_id) const = 0;
};
/**
* @brief Enote - enote (utxo) information
*/
struct Enote
{
size_t idx;
uint64_t blockHeight;
std::string hash;
size_t internalOutputIndex;
uint64_t globalOutputIndex;
bool spent;
bool frozen;
uint64_t spentHeight;
uint64_t amount;
bool rct;
bool keyImageKnown;
size_t pkIndex;
uint32_t subaddrIndex;
uint32_t subaddrAccount;
std::string address;
std::string addressLabel;
std::string keyImage;
uint64_t unlockTime;
bool unlocked;
std::string pubKey;
bool coinbase;
std::string description;
};
struct SubaddressRow {
public:
SubaddressRow(std::size_t _rowId, const std::string &_address, const std::string &_label):
@@ -401,9 +371,8 @@ struct WalletListener
/**
* @brief newBlock - called when new block received
* @param height - block height
* @param last - true if the block is the last block in the batch
*/
virtual void newBlock(uint64_t height, bool last) = 0;
virtual void newBlock(uint64_t height) = 0;
/**
* @brief updated - generic callback, called when any event (sent/received/block reveived/etc) happened with the wallet;
@@ -737,10 +706,6 @@ struct Wallet
static void warning(const std::string &category, const std::string &str);
static void error(const std::string &category, const std::string &str);
virtual bool getPolyseed(std::string &seed, std::string &passphrase) const = 0;
static bool createPolyseed(std::string &seed_words, std::string &err, const std::string &language = "English");
static std::vector<std::pair<std::string, std::string>> getPolyseedLanguages();
/**
* @brief StartRefresh - Start/resume refresh thread (refresh every 10 seconds)
*/
@@ -884,8 +849,7 @@ struct Wallet
optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
PendingTransaction::Priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {},
const std::set<std::string> &preferred_inputs = {}) = 0;
std::set<uint32_t> subaddr_indices = {}) = 0;
/*!
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
@@ -904,8 +868,7 @@ struct Wallet
optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {},
const std::set<std::string> &preferred_inputs = {}) = 0;
std::set<uint32_t> subaddr_indices = {}) = 0;
/*!
* \brief createSweepUnmixableTransaction creates transaction with unmixable outputs.
@@ -1017,9 +980,6 @@ struct Wallet
virtual TransactionHistory * history() = 0;
virtual AddressBook * addressBook() = 0;
virtual std::vector<Enote> enotes() = 0;
virtual void freeze(size_t idx) = 0;
virtual void thaw(size_t idx) = 0;
virtual Subaddress * subaddress() = 0;
virtual SubaddressAccount * subaddressAccount() = 0;
virtual void setListener(WalletListener *) = 0;
@@ -1338,27 +1298,6 @@ struct WalletManager
uint64_t kdf_rounds = 1,
WalletListener * listener = nullptr) = 0;
/*!
* \brief creates a wallet from a polyseed mnemonic phrase
* \param path Name of the wallet file to be created
* \param password Password of wallet file
* \param nettype Network type
* \param mnemonic Polyseed mnemonic
* \param passphrase Optional seed offset passphrase
* \param newWallet Whether it is a new wallet
* \param restoreHeight Override the embedded restore height
* \param kdf_rounds Number of rounds for key derivation function
* @return
*/
virtual Wallet * createWalletFromPolyseed(const std::string &path,
const std::string &password,
NetworkType nettype,
const std::string &mnemonic,
const std::string &passphrase = "",
bool newWallet = true,
uint64_t restore_height = 0,
uint64_t kdf_rounds = 1) = 0;
/*!
* \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted
* \param wallet previously opened / created wallet instance
@@ -1425,9 +1364,6 @@ struct WalletManager
//! returns current blockchain target height
virtual uint64_t blockchainTargetHeight() = 0;
//! returns current blockchain and target height
virtual std::pair<uint64_t, uint64_t> blockchainAndTargetHeight() = 0;
//! returns current network difficulty
virtual uint64_t networkDifficulty() = 0;

View File

@@ -156,15 +156,6 @@ Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
return wallet;
}
Wallet *WalletManagerImpl::createWalletFromPolyseed(const std::string &path, const std::string &password, NetworkType nettype,
const std::string &mnemonic, const std::string &passphrase,
bool newWallet, uint64_t restoreHeight, uint64_t kdf_rounds)
{
WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds);
wallet->createFromPolyseed(path, password, mnemonic, passphrase, newWallet, restoreHeight);
return wallet;
}
bool WalletManagerImpl::closeWallet(Wallet *wallet, bool store)
{
WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
@@ -280,18 +271,6 @@ uint64_t WalletManagerImpl::blockchainTargetHeight()
return ires.target_height >= ires.height ? ires.target_height : ires.height;
}
std::pair<uint64_t, uint64_t> WalletManagerImpl::blockchainAndTargetHeight()
{
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
cryptonote::COMMAND_RPC_GET_INFO::response ires;
if (!epee::net_utils::invoke_http_json("/getinfo", ireq, ires, m_http_client))
return std::make_pair(0, 0);
uint64_t height = ires.height;
uint64_t target_height = ires.target_height >= ires.height ? ires.target_height : ires.height;
return std::make_pair(height, target_height);
}
uint64_t WalletManagerImpl::networkDifficulty()
{
cryptonote::COMMAND_RPC_GET_INFO::request ireq;

View File

@@ -75,16 +75,6 @@ public:
const std::string &subaddressLookahead = "",
uint64_t kdf_rounds = 1,
WalletListener * listener = nullptr) override;
virtual Wallet * createWalletFromPolyseed(const std::string &path,
const std::string &password,
NetworkType nettype,
const std::string &mnemonic,
const std::string &passphrase,
bool newWallet = true,
uint64_t restore_height = 0,
uint64_t kdf_rounds = 1) override;
virtual bool closeWallet(Wallet *wallet, bool store = true) override;
bool walletExists(const std::string &path) override;
bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const override;
@@ -95,7 +85,6 @@ public:
bool connected(uint32_t *version = NULL) override;
uint64_t blockchainHeight() override;
uint64_t blockchainTargetHeight() override;
std::pair<uint64_t, uint64_t> blockchainAndTargetHeight() override;
uint64_t networkDifficulty() override;
double miningHashRate() override;
uint64_t blockTarget() override;

View File

@@ -92,7 +92,6 @@ using namespace epee;
#include "device/device_cold.hpp"
#include "device_trezor/device_trezor.hpp"
#include "net/socks_connect.h"
#include "polyseed/include/polyseed.h"
extern "C"
{
@@ -928,6 +927,11 @@ bool get_short_payment_id(crypto::hash8 &payment_id8, const tools::wallet2::pend
return false;
}
uint64_t get_outgoing_amount(const cryptonote::transaction &tx, const uint64_t amount_spent)
{
return tx.version == 1 ? get_outs_money_amount(tx) : (amount_spent - tx.rct_signatures.txnFee);
}
tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev)
{
tools::wallet2::tx_construction_data construction_data = ptx.construction_data;
@@ -954,16 +958,6 @@ uint32_t get_subaddress_clamped_sum(uint32_t idx, uint32_t extra)
return idx + extra;
}
bool is_preferred_input(const std::vector<crypto::key_image>& preferred_input_list, const crypto::key_image& input) {
if (!preferred_input_list.empty()) {
auto it = std::find(preferred_input_list.begin(), preferred_input_list.end(), input);
if (it == preferred_input_list.end()) {
return false;
}
}
return true;
}
static void setup_shim(hw::wallet_shim * shim, tools::wallet2 * wallet)
{
shim->get_tx_pub_key_from_received_outs = std::bind(&tools::wallet2::get_tx_pub_key_from_received_outs, wallet, std::placeholders::_1);
@@ -1281,8 +1275,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std
m_enable_multisig(false),
m_pool_info_query_time(0),
m_has_ever_refreshed_from_node(false),
m_allow_mismatched_daemon_version(false),
m_polyseed(false)
m_allow_mismatched_daemon_version(false)
{
set_rpc_client_secret_key(rct::rct2sk(rct::skGen()));
}
@@ -1469,25 +1462,10 @@ bool wallet2::get_seed(epee::wipeable_string& electrum_words, const epee::wipeab
key = cryptonote::encrypt_key(key, passphrase);
if (!crypto::ElectrumWords::bytes_to_words(key, electrum_words, seed_language))
{
std::cout << "Failed to create seed from key for language: " << seed_language << ", falling back to English." << std::endl;
crypto::ElectrumWords::bytes_to_words(key, electrum_words, "English");
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_polyseed(epee::wipeable_string& polyseed, epee::wipeable_string& passphrase) const
{
if (!m_polyseed) {
std::cout << "Failed to create seed from key for language: " << seed_language << std::endl;
return false;
}
polyseed::data data(POLYSEED_COIN);
data.load(get_account().get_keys().m_polyseed);
data.encode(polyseed::get_lang_by_name(seed_language), polyseed);
passphrase = get_account().get_keys().m_passphrase;
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -2125,21 +2103,12 @@ bool wallet2::frozen(const multisig_tx_set& txs) const
return false;
}
void wallet2::freeze(const crypto::public_key &pk)
{
freeze(get_transfer_details(pk));
}
//----------------------------------------------------------------------------------------------------
void wallet2::freeze(const crypto::key_image &ki)
{
freeze(get_transfer_details(ki));
}
//----------------------------------------------------------------------------------------------------
void wallet2::thaw(const crypto::public_key &pk)
{
thaw(get_transfer_details(pk));
}
//----------------------------------------------------------------------------------------------------
void wallet2::thaw(const crypto::key_image &ki)
{
thaw(get_transfer_details(ki));
@@ -2150,18 +2119,6 @@ bool wallet2::frozen(const crypto::key_image &ki) const
return frozen(get_transfer_details(ki));
}
//----------------------------------------------------------------------------------------------------
size_t wallet2::get_transfer_details(const crypto::public_key &pk) const
{
for (size_t idx = 0; idx < m_transfers.size(); ++idx)
{
const transfer_details &td = m_transfers[idx];
if (td.get_public_key() == pk) {
return idx;
}
}
CHECK_AND_ASSERT_THROW_MES(false, "Public key not found");
}
//----------------------------------------------------------------------------------------------------
size_t wallet2::get_transfer_details(const crypto::key_image &ki) const
{
for (size_t idx = 0; idx < m_transfers.size(); ++idx)
@@ -2576,7 +2533,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount;
if (!pool)
{
boost::unique_lock<boost::shared_mutex> lock(m_transfers_mutex);
m_transfers.push_back(transfer_details{});
transfer_details& td = m_transfers.back();
td.m_block_height = height;
@@ -2680,7 +2636,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
uint64_t extra_amount = amount - burnt;
if (!pool)
{
boost::unique_lock<boost::shared_mutex> lock(m_transfers_mutex);
transfer_details &td = m_transfers[kit->second];
td.m_block_height = height;
td.m_internal_output_index = o;
@@ -2770,10 +2725,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
LOG_ERROR("spent funds are from different subaddress accounts; count of incoming/outgoing payments will be incorrect");
subaddr_account = td.m_subaddr_index.major;
subaddr_indices.insert(td.m_subaddr_index.minor);
LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << txid);
set_spent(it->second, height);
if (!pool)
{
LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << txid);
set_spent(it->second, height);
if (!ignore_callbacks && 0 != m_callback)
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
@@ -2862,21 +2817,33 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
if (tx_money_spent_in_ins > 0 && !pool)
if (tx_money_spent_in_ins > 0)
{
uint64_t self_received = std::accumulate<decltype(tx_money_got_in_outs.begin()), uint64_t>(tx_money_got_in_outs.begin(), tx_money_got_in_outs.end(), 0,
[&subaddr_account] (uint64_t acc, const std::pair<cryptonote::subaddress_index, uint64_t>& p)
{
return acc + (p.first.major == *subaddr_account ? p.second : 0);
});
process_outgoing(txid, tx, height, ts, tx_money_spent_in_ins, self_received, *subaddr_account, subaddr_indices);
// if sending to yourself at the same subaddress account, set the outgoing payment amount to 0 so that it's less confusing
if (tx_money_spent_in_ins == self_received + fee)
if (!pool)
{
auto i = m_confirmed_txs.find(txid);
THROW_WALLET_EXCEPTION_IF(i == m_confirmed_txs.end(), error::wallet_internal_error,
"confirmed tx wasn't found: " + string_tools::pod_to_hex(txid));
i->second.m_change = self_received;
process_outgoing(txid, tx, height, ts, tx_money_spent_in_ins, self_received, *subaddr_account, subaddr_indices);
// if sending to yourself at the same subaddress account, set the outgoing payment amount to 0 so that it's less confusing
if (tx_money_spent_in_ins == self_received + fee)
{
auto i = m_confirmed_txs.find(txid);
THROW_WALLET_EXCEPTION_IF(i == m_confirmed_txs.end(), error::wallet_internal_error,
"confirmed tx wasn't found: " + string_tools::pod_to_hex(txid));
i->second.m_change = self_received;
}
}
else if (!m_unconfirmed_txs.count(txid))
{
// Add to unconfirmed txs if not already there (e.g. restoring wallet, or running the wallet in parallel to the sending wallet w/same seed)
add_unconfirmed_tx(txid, tx, tx_money_spent_in_ins, {}/*don't know dests*/, crypto::null_hash/*don't know payment_id*/, self_received, *subaddr_account, subaddr_indices);
auto i = m_unconfirmed_txs.find(txid);
THROW_WALLET_EXCEPTION_IF(i == m_unconfirmed_txs.end(), error::wallet_internal_error,
"unconfirmed tx wasn't found: " + string_tools::pod_to_hex(txid));
i->second.m_amount_out = get_outgoing_amount(tx, tx_money_spent_in_ins);
}
}
@@ -3025,10 +2992,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
// wallet (eg, we're a cold wallet and the hot wallet sent it). For RCT transactions,
// we only see 0 input amounts, so have to deduce amount out from other parameters.
entry.first->second.m_amount_in = spent;
if (tx.version == 1)
entry.first->second.m_amount_out = get_outs_money_amount(tx);
else
entry.first->second.m_amount_out = spent - tx.rct_signatures.txnFee;
entry.first->second.m_amount_out = get_outgoing_amount(tx, spent);
entry.first->second.m_change = received;
std::vector<tx_extra_field> tx_extra_fields;
@@ -3064,7 +3028,7 @@ bool wallet2::should_skip_block(const cryptonote::block &b, uint64_t height) con
return !(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height && height >= m_skip_to_height);
}
//----------------------------------------------------------------------------------------------------
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, bool last, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
"block transactions=" + std::to_string(bche.txs.size()) +
@@ -3099,7 +3063,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
m_blockchain.push_back(bl_id);
if (0 != m_callback)
m_callback->on_new_block(height, last, b);
m_callback->on_new_block(height, b);
}
//----------------------------------------------------------------------------------------------------
void wallet2::get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity) const
@@ -3460,11 +3424,9 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
const crypto::hash &bl_id = parsed_blocks[i].hash;
const cryptonote::block &bl = parsed_blocks[i].block;
bool last = i == blocks.size() - 1;
if(current_index >= m_blockchain.size())
{
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, last, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
++blocks_added;
}
else if(bl_id != m_blockchain[current_index])
@@ -3481,7 +3443,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
std::to_string(reorg_depth));
handle_reorg(current_index, output_tracker_cache);
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, last, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
}
else
{
@@ -3714,6 +3676,35 @@ bool wallet2::accept_pool_tx_for_processing(const crypto::hash &txid)
// Process an unconfirmed transfer after we know whether it's in the pool or not
void wallet2::process_unconfirmed_transfer(bool incremental, const crypto::hash &txid, wallet2::unconfirmed_transfer_details &tx_details, bool seen_in_pool, std::chrono::system_clock::time_point now, bool refreshed)
{
const auto set_tx_key_images_spent = [&](const bool spent)
{
for (size_t vini = 0; vini < tx_details.m_tx.vin.size(); ++vini)
{
if (tx_details.m_tx.vin[vini].type() != typeid(txin_to_key))
continue;
const crypto::key_image &key_image = boost::get<txin_to_key>(tx_details.m_tx.vin[vini]).k_image;
const auto it_ki = m_key_images.find(key_image);
if (it_ki == m_key_images.end())
continue;
const std::size_t i = it_ki->second;
if (i >= m_transfers.size())
continue;
const transfer_details &td = m_transfers.at(i);
if (td.m_key_image != key_image)
continue;
if (td.m_spent == spent)
continue;
LOG_PRINT_L1("Resetting spent status for output " << vini << ": " << key_image << " (spent=" << spent << ")");
if (spent)
set_spent(i, 0);
else
set_unspent(i);
}
};
// TODO: set tx_propagation_timeout to CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2 after v15 hardfork
constexpr const std::chrono::seconds tx_propagation_timeout{500};
if (seen_in_pool)
@@ -3723,6 +3714,10 @@ void wallet2::process_unconfirmed_transfer(bool incremental, const crypto::hash
tx_details.m_state = wallet2::unconfirmed_transfer_details::pending_in_pool;
MINFO("Pending txid " << txid << " seen in pool, marking as pending in pool");
}
// The inputs are spent, they're in the pool! It's possible the tx was previously marked as failed, so we
// make sure to re-mark the outputs as spent.
set_tx_key_images_spent(true/*spent*/);
}
else
{
@@ -3748,23 +3743,7 @@ void wallet2::process_unconfirmed_transfer(bool incremental, const crypto::hash
tx_details.m_state = wallet2::unconfirmed_transfer_details::failed;
// the inputs aren't spent anymore, since the tx failed
for (size_t vini = 0; vini < tx_details.m_tx.vin.size(); ++vini)
{
if (tx_details.m_tx.vin[vini].type() == typeid(txin_to_key))
{
txin_to_key &tx_in_to_key = boost::get<txin_to_key>(tx_details.m_tx.vin[vini]);
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details &td = m_transfers[i];
if (td.m_key_image == tx_in_to_key.k_image)
{
LOG_PRINT_L1("Resetting spent status for output " << vini << ": " << td.m_key_image);
set_unspent(i);
break;
}
}
}
}
set_tx_key_images_spent(false/*spent*/);
}
}
}
@@ -4039,7 +4018,7 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height,
if (0 != m_callback)
{ // FIXME: this isn't right, but simplewallet just logs that we got a block.
cryptonote::block dummy;
m_callback->on_new_block(current_index, false, dummy);
m_callback->on_new_block(current_index, dummy);
}
}
else if(bl_id != m_blockchain[current_index])
@@ -4134,8 +4113,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
if(m_light_wallet_blockchain_height != prev_height)
{
MDEBUG("new block since last time!");
// this fork does not support light wallets, so `last` param is just set to false
m_callback->on_lw_new_block(m_light_wallet_blockchain_height - 1, false);
m_callback->on_lw_new_block(m_light_wallet_blockchain_height - 1);
}
m_light_wallet_connected = true;
MDEBUG("lw scanned block height: " << m_light_wallet_scanned_block_height);
@@ -4150,6 +4128,18 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
// Lighwallet refresh done
return;
}
if (!m_first_refresh_done)
{
// We want to process the whole pool again, in case we identify received outputs in the chain we might have spent in the pool
m_pool_info_query_time = 0;
m_scanned_pool_txs[0].clear();
m_scanned_pool_txs[1].clear();
// Clear unconfirmed (received) payments because the data is 100% recovered when scanning
m_unconfirmed_payments.clear();
// Don't clear unconfirmed (sent) txs because some data is not recover-able when scanning (dests)
}
received_money = false;
blocks_fetched = 0;
uint64_t added_blocks = 0;
@@ -4881,9 +4871,6 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const crypt
value2.SetInt(m_enable_multisig ? 1 : 0);
json.AddMember("enable_multisig", value2, json.GetAllocator());
value2.SetInt(m_polyseed ? 1 : 0);
json.AddMember("polyseed", value2, json.GetAllocator());
if (m_background_sync_type == BackgroundSyncCustomPassword && !background_keys_file && m_custom_background_key)
{
value.SetString(reinterpret_cast<const char*>(m_custom_background_key.get().data()), m_custom_background_key.get().size());
@@ -5122,7 +5109,6 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
m_credits_target = 0;
m_enable_multisig = false;
m_allow_mismatched_daemon_version = false;
m_polyseed = false;
m_custom_background_key = boost::none;
}
else if(json.IsObject())
@@ -5364,9 +5350,6 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, background_sync_type, BackgroundSyncType, Int, false, BackgroundSyncOff);
m_background_sync_type = field_background_sync_type;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, polyseed, int, Int, false, false);
m_polyseed = field_polyseed;
// Load encryption key used to encrypt background cache
crypto::chacha_key custom_background_key;
m_custom_background_key = boost::none;
@@ -5686,48 +5669,6 @@ void wallet2::init_type(hw::device::device_type device_type)
m_key_device_type = device_type;
}
/*!
* \brief Generates a polyseed wallet or restores one.
* \param wallet_ Name of wallet file
* \param password Password of wallet file
* \param passphrase Seed offset passphrase
* \param recover Whether it is a restore
* \param seed_words If it is a restore, the polyseed
* \param create_address_file Whether to create an address file
* \return The secret key of the generated wallet
*/
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
const polyseed::data &seed, const epee::wipeable_string& passphrase, bool recover, uint64_t restoreHeight, bool create_address_file)
{
clear();
prepare_file_names(wallet_);
if (!wallet_.empty()) {
boost::system::error_code ignored_ec;
THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
}
m_account.create_from_polyseed(seed, passphrase);
init_type(hw::device::device_type::SOFTWARE);
m_polyseed = true;
setup_keys(password);
if (recover) {
m_refresh_from_block_height = estimate_blockchain_height(restoreHeight > 0 ? restoreHeight : seed.birthday());
} else {
m_refresh_from_block_height = estimate_blockchain_height();
}
create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
setup_new_blockchain();
if (!wallet_.empty())
store();
}
/*!
* \brief Generates a wallet or restores one. Assumes the multisig setup
* has already completed for the provided multisig info.
@@ -5855,7 +5796,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
return retval;
}
uint64_t wallet2::estimate_blockchain_height(uint64_t time)
uint64_t wallet2::estimate_blockchain_height()
{
// -1 month for fluctuations in block time and machine date/time setup.
// avg seconds per block
@@ -5879,7 +5820,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
// the daemon is currently syncing.
// If we use the approximate height we subtract one month as
// a safety margin.
height = get_approximate_blockchain_height(time);
height = get_approximate_blockchain_height();
uint64_t target_height = get_daemon_blockchain_target_height(err);
if (err.empty()) {
if (target_height < height)
@@ -7593,9 +7534,9 @@ uint64_t wallet2::select_transfers(uint64_t needed_money, std::vector<size_t> un
return found_money;
}
//----------------------------------------------------------------------------------------------------
void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices)
void wallet2::add_unconfirmed_tx(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices)
{
unconfirmed_transfer_details& utd = m_unconfirmed_txs[cryptonote::get_transaction_hash(tx)];
unconfirmed_transfer_details& utd = m_unconfirmed_txs[txid];
utd.m_amount_in = amount_in;
utd.m_amount_out = 0;
for (const auto &d: dests)
@@ -7708,7 +7649,7 @@ void wallet2::commit_tx(pending_tx& ptx)
for(size_t idx: ptx.selected_transfers)
amount_in += m_transfers[idx].amount();
}
add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
add_unconfirmed_tx(txid, ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
if (store_tx_info() && ptx.tx_key != crypto::null_skey)
{
m_tx_keys[txid] = ptx.tx_key;
@@ -10491,7 +10432,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
LOG_PRINT_L2("transfer_selected_rct done");
}
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list)
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices)
{
std::vector<size_t> picks;
float current_output_relatdness = 1.0f;
@@ -10502,9 +10443,6 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (!is_spent(td, false) && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below)
@@ -10525,9 +10463,6 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below)
@@ -10539,9 +10474,6 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t j = i + 1; j < m_transfers.size(); ++j)
{
const transfer_details& td2 = m_transfers[j];
if (!is_preferred_input(preferred_input_list, td2.m_key_image)) {
continue;
}
if (td2.amount() > m_ignore_outputs_above || td2.amount() < m_ignore_outputs_below)
{
MDEBUG("Ignoring output " << j << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
@@ -11114,7 +11046,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image,
// This system allows for sending (almost) the entire balance, since it does
// not generate spurious change in all txes, thus decreasing the instantaneous
// usable balance.
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list, const unique_index_container& subtract_fee_from_outputs)
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs)
{
//ensure device is let in NONE mode in any case
hw::device &hwdev = m_account.get_device();
@@ -11323,9 +11255,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
{
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below fractional threshold " << print_money(fractional_threshold));
@@ -11411,7 +11340,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// will get us a known fee.
uint64_t estimated_fee = estimate_fee(use_per_byte_fee, use_rct, 2, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags, base_fee, fee_quantization_mask);
total_needed_money = needed_money + (subtract_fee_from_outputs.size() ? 0 : estimated_fee);
preferred_inputs = pick_preferred_rct_inputs(total_needed_money, subaddr_account, subaddr_indices, preferred_input_list);
preferred_inputs = pick_preferred_rct_inputs(total_needed_money, subaddr_account, subaddr_indices);
if (!preferred_inputs.empty())
{
string s;
@@ -11890,7 +11819,7 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, c
return true;
}
std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list)
std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices;
@@ -11920,9 +11849,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
{
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
@@ -13705,7 +13631,7 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
return target_height;
}
uint64_t wallet2::get_approximate_blockchain_height(uint64_t t) const
uint64_t wallet2::get_approximate_blockchain_height() const
{
uint64_t approx_blockchain_height = m_nettype == TESTNET ? 0 : (time(NULL) - 1522624244)/307;
LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
@@ -15815,21 +15741,6 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day)
{
std::tm date = { 0, 0, 0, 0, 0, 0, 0, 0 };
date.tm_year = year - 1900;
date.tm_mon = month - 1;
date.tm_mday = day;
if (date.tm_mon < 0 || 11 < date.tm_mon || date.tm_mday < 1 || 31 < date.tm_mday)
{
throw std::runtime_error("month or day out of range");
}
uint64_t timestamp_target = std::mktime(&date);
return get_blockchain_height_by_timestamp(timestamp_target);
}
uint64_t wallet2::get_blockchain_height_by_timestamp(uint64_t timestamp_target) {
uint32_t version;
if (!check_connection(&version))
{
@@ -15839,7 +15750,15 @@ uint64_t wallet2::get_blockchain_height_by_timestamp(uint64_t timestamp_target)
{
throw std::runtime_error("this function requires RPC version 1.6 or higher");
}
std::tm date = { 0, 0, 0, 0, 0, 0, 0, 0 };
date.tm_year = year - 1900;
date.tm_mon = month - 1;
date.tm_mday = day;
if (date.tm_mon < 0 || 11 < date.tm_mon || date.tm_mday < 1 || 31 < date.tm_mday)
{
throw std::runtime_error("month or day out of range");
}
uint64_t timestamp_target = std::mktime(&date);
std::string err;
uint64_t height_min = 0;
uint64_t height_max = get_daemon_blockchain_height(err) - 1;

View File

@@ -72,7 +72,6 @@
#include "message_store.h"
#include "wallet_light_rpc.h"
#include "wallet_rpc_helpers.h"
#include "polyseed/polyseed.hpp"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.wallet2"
@@ -139,7 +138,7 @@ private:
{
public:
// Full wallet callbacks
virtual void on_new_block(uint64_t height, bool last, const cryptonote::block& block) {}
virtual void on_new_block(uint64_t height, const cryptonote::block& block) {}
virtual void on_reorg(uint64_t height, uint64_t blocks_detached, size_t transfers_detached) {}
virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) {}
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {}
@@ -147,7 +146,7 @@ private:
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx) {}
virtual boost::optional<epee::wipeable_string> on_get_password(const char *reason) { return boost::none; }
// Light wallet callbacks
virtual void on_lw_new_block(uint64_t height, bool last) {}
virtual void on_lw_new_block(uint64_t height) {}
virtual void on_lw_money_received(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
virtual void on_lw_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
virtual void on_lw_money_spent(uint64_t height, const crypto::hash &txid, uint64_t amount) {}
@@ -922,20 +921,6 @@ private:
void generate(const std::string& wallet_, const epee::wipeable_string& password,
const epee::wipeable_string& multisig_data, bool create_address_file = false);
/*!
* \brief Generates a wallet from a polyseed.
* @param wallet_ Name of wallet file
* @param password Password of wallet file
* @param seed Polyseed data
* @param passphrase Optional seed offset passphrase
* @param recover Whether it is a restore
* @param restoreHeight Override the embedded restore height
* @param create_address_file Whether to create an address file
*/
void generate(const std::string& wallet_, const epee::wipeable_string& password,
const polyseed::data &seed, const epee::wipeable_string& passphrase = "",
bool recover = false, uint64_t restoreHeight = 0, bool create_address_file = false);
/*!
* \brief Generates a wallet or restores one.
* \param wallet_ Name of wallet file
@@ -1108,15 +1093,6 @@ private:
bool is_deterministic() const;
bool get_seed(epee::wipeable_string& electrum_words, const epee::wipeable_string &passphrase = epee::wipeable_string()) const;
/*!
* \brief get_polyseed Gets the polyseed (if available) and passphrase (if set) needed to recover the wallet.
* @param seed Polyseed mnemonic phrase
* @param passphrase Seed offset passphrase that was used to restore the wallet
* @return Returns true if the wallet has a polyseed.
* Note: both the mnemonic phrase and the passphrase are needed to recover the wallet
*/
bool get_polyseed(epee::wipeable_string& seed, epee::wipeable_string &passphrase) const;
/*!
* \brief Checks if light wallet. A light wallet sends view key to a server where the blockchain is scanned.
*/
@@ -1220,8 +1196,8 @@ private:
bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const;
bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func);
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list = {}, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose
std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list = {});
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose
std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices);
std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra);
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra);
bool sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, const std::vector<cryptonote::tx_destination_entry>& dsts, const unique_index_container& subtract_fee_from_outputs = {}) const;
@@ -1573,7 +1549,6 @@ private:
uint64_t get_num_rct_outputs();
size_t get_num_transfer_details() const { return m_transfers.size(); }
const transfer_details &get_transfer_details(size_t idx) const;
size_t get_transfer_details(const crypto::public_key &pk) const;
uint8_t get_current_hard_fork();
void get_hard_fork_info(uint8_t version, uint64_t &earliest_height);
@@ -1591,8 +1566,8 @@ private:
/*!
* \brief Calculates the approximate blockchain height from current date/time.
*/
uint64_t get_approximate_blockchain_height(uint64_t time = 0) const;
uint64_t estimate_blockchain_height(uint64_t time = 0);
uint64_t get_approximate_blockchain_height() const;
uint64_t estimate_blockchain_height();
std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct);
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f);
std::vector<size_t> select_available_unmixable_outputs();
@@ -1684,7 +1659,6 @@ private:
bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error);
uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31
uint64_t get_blockchain_height_by_timestamp(uint64_t timestamp);
bool is_synced();
@@ -1803,9 +1777,7 @@ private:
void freeze(size_t idx);
void thaw(size_t idx);
bool frozen(size_t idx) const;
void freeze(const crypto::public_key &pk);
void freeze(const crypto::key_image &ki);
void thaw(const crypto::public_key &pk);
void thaw(const crypto::key_image &ki);
bool frozen(const crypto::key_image &ki) const;
bool frozen(const transfer_details &td) const;
@@ -1846,8 +1818,6 @@ private:
static std::string get_default_daemon_address() { CRITICAL_REGION_LOCAL(default_daemon_address_lock); return default_daemon_address; }
boost::shared_mutex m_transfers_mutex;
private:
/*!
* \brief Stores wallet information to wallet file.
@@ -1876,7 +1846,7 @@ private:
void load_wallet_cache(const bool use_fs, const std::string& cache_buf = "");
void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL, bool ignore_callbacks = false);
bool should_skip_block(const cryptonote::block &b, uint64_t height) const;
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, bool last, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
detached_blockchain_data detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void handle_reorg(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const;
@@ -1905,7 +1875,7 @@ private:
bool prepare_file_names(const std::string& file_path);
void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height);
void process_outgoing(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height, uint64_t ts, uint64_t spent, uint64_t received, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices);
void add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices);
void add_unconfirmed_tx(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount_in, const std::vector<cryptonote::tx_destination_entry> &dests, const crypto::hash &payment_id, uint64_t change_amount, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices);
void generate_genesis(cryptonote::block& b) const;
void check_genesis(const crypto::hash& genesis_hash) const; //throws
bool generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const;
@@ -1919,7 +1889,7 @@ private:
std::vector<uint64_t> get_unspent_amounts_vector(bool strict);
uint64_t get_dynamic_base_fee_estimate();
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list);
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices);
void set_spent(size_t idx, uint64_t height);
void set_unspent(size_t idx);
bool is_spent(const transfer_details &td, bool strict = true) const;
@@ -2034,7 +2004,6 @@ private:
std::string seed_language; /*!< Language of the mnemonics (seed). */
bool is_old_file_format; /*!< Whether the wallet file is of an old file format */
bool m_watch_only; /*!< no spend key */
bool m_polyseed;
bool m_multisig; /*!< if > 1 spend secret key will not match spend public key */
uint32_t m_multisig_threshold;
std::vector<crypto::public_key> m_multisig_signers;

View File

@@ -1261,7 +1261,7 @@ namespace tools
{
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, priority, extra, req.account_index, req.subaddr_indices, {}, req.subtract_fee_from_outputs);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, priority, extra, req.account_index, req.subaddr_indices, req.subtract_fee_from_outputs);
if (ptx_vector.empty())
{

View File

@@ -29,6 +29,7 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
import json
import random
"""Test multisig transfers
@@ -408,10 +409,37 @@ class MultisigTest():
assert len(res.tx_hash_list) == 1
txid = res.tx_hash_list[0]
# Retrieve spent key images from daemon
res = daemon.get_transactions([txid], decode_as_json = True)
assert len(res.txs) == 1
tx = res.txs[0]
assert tx.tx_hash == txid
assert len(tx.as_json) > 0
try:
j = json.loads(tx.as_json)
except:
j = None
assert j
assert len(j['vin']) >= 1
spent_key_images = [vin['key']['k_image'] for vin in j['vin']]
assert len(spent_key_images) == len(j['vin'])
for i in range(len(self.wallet)):
# Check if the wallet knows about any spent key images (all signers *should*, non-signers *might*)
is_a_signer = len([x for x in signers if x == i]) > 0
knows_key_image = False
for ki in spent_key_images:
try:
res = self.wallet[i].frozen(ki)
knows_key_image = True
except AssertionError:
if is_a_signer:
raise ValueError('Signer should know about spent key image')
pass
self.wallet[i].refresh()
res = self.wallet[i].get_transfers()
assert len([x for x in (res['pending'] if 'pending' in res else []) if x.txid == txid]) == (1 if i == signers[-1] else 0)
# Any wallet that knows about any spent key images should be able to detect the spend in the pool
assert len([x for x in (res['pending'] if 'pending' in res else []) if x.txid == txid]) == (1 if knows_key_image else 0)
assert len([x for x in (res['out'] if 'out' in res else []) if x.txid == txid]) == 0
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
@@ -507,9 +535,13 @@ class MultisigTest():
txid = res.tx_hash_list[0]
for i in range(len(self.wallet)):
# Make sure wallet knows about the key image
frozen = self.wallet[i].frozen(ki).frozen
assert not frozen
self.wallet[i].refresh()
res = self.wallet[i].get_transfers()
assert len([x for x in (res['pending'] if 'pending' in res else []) if x.txid == txid]) == (1 if i == signers[-1] else 0)
# Since all wallets should have key image, all wallets should be able to detect the spend in the pool
assert len([x for x in (res['pending'] if 'pending' in res else []) if x.txid == txid]) == 1
assert len([x for x in (res['out'] if 'out' in res else []) if x.txid == txid]) == 0
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)

View File

@@ -58,6 +58,17 @@ def diff_incoming_transfers(actual_transfers, expected_transfers):
# wallet2 m_transfers container is ordered and order should be the same across rescans
diff_transfers(actual_transfers, expected_transfers, ignore_order = False)
def restore_wallet(wallet, seed, restore_height = 0, filename = '', password = ''):
try: wallet.close_wallet()
except: pass
if filename != '':
util_resources.remove_wallet_files(filename)
wallet.auto_refresh(enable = False)
wallet.restore_deterministic_wallet(seed = seed, restore_height = restore_height, filename = filename, password = password)
res = wallet.get_transfers()
assert not 'in' in res or len(res['in']) == 0
assert not 'out' in res or len(res.out) == 0
class TransferTest():
def run_test(self):
self.reset()
@@ -78,6 +89,7 @@ class TransferTest():
self.check_background_sync()
self.check_background_sync_reorg_recovery()
self.check_subaddress_lookahead()
self.check_pool_scanner()
def reset(self):
print('Resetting blockchain')
@@ -265,6 +277,7 @@ class TransferTest():
assert len(res.multisig_txset) == 0
assert len(res.unsigned_txset) == 0
tx_blob = res.tx_blob
running_balances[0] -= 1000000000000 + fee
res = daemon.send_raw_transaction(tx_blob)
assert res.not_relayed == False
@@ -306,7 +319,6 @@ class TransferTest():
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
res = daemon.getlastblockheader()
running_balances[0] -= 1000000000000 + fee
running_balances[0] += res.block_header.reward
self.wallet[1].refresh()
running_balances[1] += 1000000000000
@@ -1154,14 +1166,6 @@ class TransferTest():
except: invalid_password = True
assert invalid_password
def restore_wallet(wallet, seed, filename = '', password = ''):
wallet.close_wallet()
if filename != '':
util_resources.remove_wallet_files(filename)
wallet.restore_deterministic_wallet(seed = seed, filename = filename, password = password)
wallet.auto_refresh(enable = False)
assert wallet.get_transfers() == {}
def assert_correct_transfers(wallet, expected_transfers, expected_inc_transfers, expected_balance):
diff_transfers(wallet.get_transfers(), expected_transfers)
diff_incoming_transfers(wallet.incoming_transfers(transfer_type = 'all'), expected_inc_transfers)
@@ -1171,10 +1175,7 @@ class TransferTest():
# We're testing a sweep because it makes sure background sync can
# properly pick up txs which do not have a change output back to sender.
sender_wallet = self.wallet[0]
try: sender_wallet.close_wallet()
except: pass
sender_wallet.restore_deterministic_wallet(seed = seeds[0])
sender_wallet.auto_refresh(enable = False)
restore_wallet(sender_wallet, seeds[0])
sender_wallet.refresh()
res = sender_wallet.incoming_transfers(transfer_type = 'available')
unlocked = [x for x in res.transfers if x.unlocked and x.amount > 0]
@@ -1193,10 +1194,7 @@ class TransferTest():
# set up receiver_wallet
receiver_wallet = self.wallet[1]
try: receiver_wallet.close_wallet()
except: pass
receiver_wallet.restore_deterministic_wallet(seed = seeds[1])
receiver_wallet.auto_refresh(enable = False)
restore_wallet(receiver_wallet, seeds[1])
receiver_wallet.refresh()
res = receiver_wallet.get_transfers()
in_len = 0 if 'in' not in res else len(res['in'])
@@ -1267,7 +1265,7 @@ class TransferTest():
# Check stopping a wallet with wallet files saved to disk
for background_sync_type in [reuse_password, custom_password]:
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
sender_wallet.start_background_sync()
@@ -1279,7 +1277,7 @@ class TransferTest():
# Close wallet while background syncing, then reopen
for background_sync_type in [reuse_password, custom_password]:
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
sender_wallet.start_background_sync()
@@ -1293,7 +1291,7 @@ class TransferTest():
# Close wallet while syncing normally, then reopen
for background_sync_type in [reuse_password, custom_password]:
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
sender_wallet.refresh()
@@ -1305,7 +1303,7 @@ class TransferTest():
# Create background cache using custom password, then use it to sync, then reopen main wallet
for background_cache_password in ['background_password', '']:
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
assert not util_resources.file_exists('test1.background')
assert not util_resources.file_exists('test1.background.keys')
sender_wallet.setup_background_sync(background_sync_type = custom_password, wallet_password = 'test_password', background_cache_password = background_cache_password)
@@ -1321,7 +1319,7 @@ class TransferTest():
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
# Check that main wallet keeps background cache encrypted with custom password in sync
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = 'background_password')
sender_wallet.refresh()
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
@@ -1330,7 +1328,7 @@ class TransferTest():
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
# Try using wallet password as custom background password
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
assert not util_resources.file_exists('test1.background')
assert not util_resources.file_exists('test1.background.keys')
same_password = False
@@ -1342,7 +1340,7 @@ class TransferTest():
# Turn off background sync
for background_sync_type in [reuse_password, custom_password]:
restore_wallet(sender_wallet, seeds[0], 'test1', 'test_password')
restore_wallet(sender_wallet, seeds[0], filename = 'test1', password = 'test_password')
background_cache_password = None if background_sync_type == reuse_password else 'background_password'
sender_wallet.setup_background_sync(background_sync_type = background_sync_type, wallet_password = 'test_password', background_cache_password = background_cache_password)
if background_sync_type == custom_password:
@@ -1367,8 +1365,7 @@ class TransferTest():
sender_wallet.open_wallet('test1', password = 'test_password')
# Sanity check against outgoing wallet restored at height 0
sender_wallet.close_wallet()
sender_wallet.restore_deterministic_wallet(seed = seeds[0], restore_height = 0)
restore_wallet(sender_wallet, seeds[0], restore_height = 0)
sender_wallet.refresh()
assert_correct_transfers(sender_wallet, transfers, incoming_transfers, expected_sender_balance)
@@ -1417,7 +1414,7 @@ class TransferTest():
assert receiver_wallet.get_balance().balance == expected_receiver_balance
# Check a fresh incoming wallet with wallet files saved to disk and encrypted with password
restore_wallet(receiver_wallet, seeds[1], 'test2', 'test_password')
restore_wallet(receiver_wallet, seeds[1], filename = 'test2', password = 'test_password')
receiver_wallet.setup_background_sync(background_sync_type = reuse_password, wallet_password = 'test_password')
receiver_wallet.start_background_sync()
receiver_wallet.refresh()
@@ -1427,7 +1424,7 @@ class TransferTest():
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
# Close receiver's wallet while background sync is enabled then reopen
restore_wallet(receiver_wallet, seeds[1], 'test2', 'test_password')
restore_wallet(receiver_wallet, seeds[1], filename = 'test2', password = 'test_password')
receiver_wallet.setup_background_sync(background_sync_type = reuse_password, wallet_password = 'test_password')
receiver_wallet.start_background_sync()
receiver_wallet.refresh()
@@ -1440,8 +1437,7 @@ class TransferTest():
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
# Sanity check against incoming wallet restored at height 0
receiver_wallet.close_wallet()
receiver_wallet.restore_deterministic_wallet(seed = seeds[1], restore_height = 0)
restore_wallet(receiver_wallet, seeds[1], restore_height = 0)
receiver_wallet.refresh()
assert_correct_transfers(receiver_wallet, transfers, incoming_transfers, expected_receiver_balance)
@@ -1558,5 +1554,62 @@ class TransferTest():
assert balance_info_0_999['blocks_to_unlock'] == 9
assert balance_info_0_999['time_to_unlock'] == 0
def check_pool_scanner(self):
daemon = Daemon()
print('Checking pool scanner')
# Sync first wallet
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
self.wallet[0].refresh()
# Open second wallet with same seed as first
restore_wallet(self.wallet[1], seeds[0])
assert self.wallet[0].get_address().address == self.wallet[1].get_address().address
# Send to another wallet, spending from first wallet
dst = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1000000000000}
res = self.wallet[0].transfer([dst])
assert len(res.tx_hash) == 32*2
txid = res.tx_hash
assert res.fee > 0
fee = res.fee
# Sync both wallets
self.wallet[0].refresh()
self.wallet[1].refresh()
# Both wallets should be able to detect the spend tx in the pool
res_wallet0 = self.wallet[0].get_transfers()
res_wallet1 = self.wallet[1].get_transfers()
# After restoring, should still be able to detect the spend in the pool
restore_wallet(self.wallet[1], seed = seeds[0])
self.wallet[1].refresh()
res_wallet1_after_restore = self.wallet[1].get_transfers()
for res in [res_wallet0, res_wallet1, res_wallet1_after_restore]:
assert len(res.pending) == 1
assert not 'pool' in res or len(res.pool) == 0
assert not 'failed' in res or len(res.failed) == 0
e = res.pending[0]
assert e.txid == txid
assert e.payment_id in ['', '0000000000000000']
assert e.type == 'pending'
assert e.unlock_time == 0
assert e.subaddr_index.major == 0
assert e.subaddr_indices == [{'major': 0, 'minor': 0}]
assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
assert e.double_spend_seen == False
assert not 'confirmations' in e or e.confirmations == 0
assert e.amount == dst['amount']
assert e.fee == fee
# Mine a block to mine the tx and reset 2nd wallet
daemon.generateblocks('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 1)
restore_wallet(self.wallet[1], seeds[1])
self.wallet[1].refresh()
self.wallet[0].refresh()
if __name__ == '__main__':
TransferTest().run_test()

View File

@@ -847,7 +847,7 @@ struct MyWalletListener : public Monero::WalletListener
// cv_receive.notify_one();
}
virtual void newBlock(uint64_t height, bool last)
virtual void newBlock(uint64_t height)
{
// std::cout << "wallet: " << wallet->mainAddress()
// <<", new block received, blockHeight: " << height << std::endl;

View File

@@ -28,6 +28,10 @@
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <condition_variable>
#include <mutex>
#include <thread>
#include <boost/filesystem.hpp>
#include "gtest/gtest.h"
#include "file_io_utils.h"
@@ -215,3 +219,55 @@ TEST(logging, empty_configurations_throws)
const el::Configurations cfg;
EXPECT_ANY_THROW(log1.configure(cfg));
}
TEST(logging, deadlock)
{
std::mutex inner_mutex;
// 1. Thread 1 starts logger
// 2. Thread 2 grabs inner mutex shared across threads
// 3. Thread 2 logs
// 4. Thread 1 grabs inner mutex shared across threads
// 5. Thread 1 finishes logging
std::condition_variable cv1, cv2;
std::mutex mutex1, mutex2;
std::unique_lock<std::mutex> lock_until_t1_starts_logger(mutex1);
std::unique_lock<std::mutex> lock_until_t2_finishes_logging(mutex2);
bool t1_started_logger = false;
bool t2_finished_logging = false;
const auto thread1_func = [&]
{
const auto thread1_inner_func = [&]() -> std::string
{
t1_started_logger = true;
lock_until_t1_starts_logger.unlock();
cv1.notify_one();
cv2.wait(lock_until_t2_finishes_logging, [&]{return t2_finished_logging;});
std::lock_guard<std::mutex> guard(inner_mutex);
return "world!";
};
MGINFO("Hello, " << thread1_inner_func() << " - Sincerely, thread 1");
};
const auto thread2_func = [&]
{
cv1.wait(lock_until_t1_starts_logger, [&]{return t1_started_logger;});
{
std::lock_guard<std::mutex> guard(inner_mutex);
MGINFO("Hello, world! - Sincerely, thread 2");
}
t2_finished_logging = true;
lock_until_t2_finishes_logging.unlock();
cv2.notify_one();
};
std::thread t1(thread1_func);
std::thread t2(thread2_func);
t1.join();
t2.join();
}

View File

@@ -56,7 +56,7 @@ public:
void set_target_blockchain_height(uint64_t) {}
bool init(const boost::program_options::variables_map& vm) {return true ;}
bool deinit(){return true;}
bool get_short_chain_history(std::list<crypto::hash>& ids) const { return true; }
bool get_short_chain_history(std::list<crypto::hash>& ids, uint64_t& current_height) const { return true; }
bool have_block(const crypto::hash& id, int *where = NULL) const {return false;}
bool have_block_unlocked(const crypto::hash& id, int *where = NULL) const {return false;}
void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;}