Compare commits

...

37 Commits

Author SHA1 Message Date
Vijay
e45a60ad01
Merge 8a58b5e244 into 7530f3d245 2024-12-17 04:31:49 +00:00
pasta
7530f3d245
Merge #6490: ci: container improvements
Some checks failed
CI / Build Image (push) Failing after 2m9s
CI / Build Dependencies (arm-linux, arm-linux-gnueabihf) (push) Has been skipped
CI / Build Dependencies (linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (arm-linux, arm-linux, arm-linux-gnueabihf) (push) Has been skipped
CI / Build (linux64, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_cxx20, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_fuzz, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_nowallet, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_sqlite, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_tsan, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_ubsan, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
Label Merge Conflicts / main (push) Failing after 2m49s
Check Merge Fast-Forward Only / check_merge (push) Successful in 1m51s
Guix Build / build-image (push) Failing after 6m6s
Guix Build / build (aarch64-linux-gnu) (push) Has been skipped
Guix Build / build (arm-linux-gnueabihf) (push) Has been skipped
Guix Build / build (arm64-apple-darwin) (push) Has been skipped
Guix Build / build (x86_64-apple-darwin) (push) Has been skipped
Guix Build / build (powerpc64-linux-gnu) (push) Has been skipped
Guix Build / build (x86_64-linux-gnu) (push) Has been skipped
Guix Build / build (riscv64-linux-gnu) (push) Has been skipped
Guix Build / build (x86_64-w64-mingw32) (push) Has been skipped
04ce1fea52 ci: deduplicate macOS SDK setup logic (Kittywhiskers Van Gogh)
8dd0db7de9 ci: fix "LC_ALL: cannot change locale (en_US.UTF-8)" in Guix container (Kittywhiskers Van Gogh)
187fe17650 ci: don't stage packages in `/tmp`, reduce layers for `cppcheck` build (Kittywhiskers Van Gogh)
eef863554a ci: install `i386` packages only if host is `amd64`, merge layers (Kittywhiskers Van Gogh)
e7702292d1 ci: purge package manager cache after each interaction (Kittywhiskers Van Gogh)
b7099eed47 ci: remove redundant `version` attribute, avoid `lldb` personality error (Kittywhiskers Van Gogh)
64cdc42130 ci: add LLVM library path to `LD_LIBRARY_PATH` and GDB allowlist (Kittywhiskers Van Gogh)
440fd3fe21 ci: drop distro LLVM packages, move Clang install up, set defaults (Kittywhiskers Van Gogh)

Pull request description:

  ## Additional Information

  * This pull request pulls container-specific changes from [dash#6387](https://github.com/dashpay/dash/pull/6387), [dash#6400](https://github.com/dashpay/dash/pull/6400) and [dash#6421](https://github.com/dashpay/dash/pull/6421)

  * The `HOST` check before running `setup_sdk.sh` isn't a part of the script itself as the script is written to be independent of external variables set. The caller is expected to know the conditions needed to run `setup_sdk.sh` as the script is _relatively_ agnostic to its environment.

  * The `version` attribute in the [`develop`](a8e2316d6f/contrib/containers/develop/docker-compose.yml) and [`guix`](a8e2316d6f/contrib/containers/guix/docker-compose.yml) container's `docker-compose.yml` has been dropped as the attribute has been deprecated in the compose spec ([source](65ef9f4a5d/spec.md (version-top-level-element-obsolete))).

  * Using `LD_LIBRARY_PATH` to point to LLVM's libraries are acceptable and will not interfere with executing binaries built using the distro's packaged compiler as it will eventually search default paths and find the libraries shipped with the distro ([source](https://man7.org/linux/man-pages/man8/ld.so.8.html)).

  * Currently, running LLDB will result in a "personality set failed: Operation not permitted" error ([source](https://discourse.llvm.org/t/running-lldb-in-a-container/76801)). This is caused by its attempt at disabling ASLR for debugging.

    To work around this error, the container will now operate under relaxed restrictions (`seccomp=unconfined`). As disabling ASLR is valuable when debugging and the container is meant for developers (i.e. it isn't used for CI), we have opted to relax restrictions instead of skipping ASLR disablement.

  * As of `develop` (a8e2316d6f), packages built by the container are stored in `/tmp`, which is inadvisable as it is the same directory used to store functional test runs and it's not too difficult to delete `/tmp`'s contents to save space in a long running [`develop`](a8e2316d6f/contrib/containers/develop/docker-compose.yml) container and then realize that both `shellcheck` and `cppcheck` are stored there and now you have to ditch the container you're working in and restart it.
    * To remedy this, packages are now built and stored in `/opt` in accordance with the FHS ([source](https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s13.html)). `/usr/local` was a contender but it's pre-populated, meanwhile `ls /opt` would give you a very quick picture of what's built for the container.

    * `/tmp` will not be entirely empty because [pypa/pip#10753](https://github.com/pypa/pip/issues/10753) results in residual `.pem` files leaking into `/tmp` and `pyenv` stores its build log there and keeping it around has some debug value.

  ## Breaking Changes

  None expected.

  ## Checklist:

  - [x] I have performed a self-review of my own code
  - [x] I have commented my code, particularly in hard-to-understand areas
  - [x] I have added or updated relevant unit/integration/functional/e2e tests **(note: N/A)**
  - [x] I have made corresponding changes to the documentation **(note: N/A)**
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  UdjinM6:
    ACK 04ce1fea52
  PastaPastaPasta:
    utACK 04ce1fea52

Tree-SHA512: 5442ae06cb73b9bc4eec908803548195ae8fd9150422789e5f98578ad01a303b5361f9ba42fe8faee27ac91e38328b7771e4ba42b296dfa70ecbbfc7d10436b6
2024-12-16 22:29:09 -06:00
pasta
5bf0409eba
Merge #6300: backport: Merge bitcoin#23642, 22794, 23316, 24365, gui#517, 24219, 23253, 24449, 22543
3931608858 Merge bitcoin/bitcoin#22543: test: Use MiniWallet in mempool_limit.py (merge-script)
f147373a32 Merge bitcoin/bitcoin#24449: fuzz: FuzzedFileProvider::write should not return negative value (MarcoFalke)
2a2a2693d0 Merge bitcoin/bitcoin#23253: bitcoin-tx: Reject non-integral and out of range int strings (W. J. van der Laan)
11eeae2ab9 Merge bitcoin/bitcoin#24219: Fix implicit-integer-sign-change in bloom (MarcoFalke)
f16265dd50 Merge bitcoin-core/gui#517: refactor, qt: Use std::chrono for parameters of QTimer methods (Hennadii Stepanov)
b212ca0515 Merge bitcoin/bitcoin#24365: wallet: Don't generate keys for wallets with private keys disabled during upgradewallet (laanwj)
66e77f7879 Merge bitcoin/bitcoin#23316: test: make the node param explicit in init_wallet() (MarcoFalke)
995cae46af Merge bitcoin/bitcoin#22794: test: Verify if wallet is compiled in rpc_invalid_address_message.py test (MarcoFalke)
61a0140362 Merge bitcoin/bitcoin#23642: refactor: Call type-solver earlier in decodescript (MarcoFalke)

Pull request description:

  Bitcoin Backports

ACKs for top commit:
  UdjinM6:
    utACK 3931608858
  PastaPastaPasta:
    utACK 3931608858

Tree-SHA512: 38f384776002e8014b2510aeaf1f4655fea0531011eb326eb2ab546d9e7193ad9e5c4b570d9831f88bb696e06ded04259a21ddb750d7ffedfedebdbb9a951379
2024-12-16 21:01:12 -06:00
pasta
a9cfd39390
Merge #6491: ci: merge bitcoin#27314, #28954, fix multiprocess builds
27d9763b1b fix: add `linux64_multiprocess` `BUILD_TARGET` to matrix, mend C(XX) (Kittywhiskers Van Gogh)
26cc5a1c90 ci: use underscore to separate variant name from target triple (Kittywhiskers Van Gogh)
d0131a5259 trivial: sort `BUILD_TARGET` on GitHub and in `matrix.sh` alphabetically (Kittywhiskers Van Gogh)
4f1b5c165b merge bitcoin#28954: Reduce use of bash -c (Kittywhiskers Van Gogh)
a49162ffae merge bitcoin#27314: Fix handling of `CXX=clang++` when building `qt` package (Kittywhiskers Van Gogh)

Pull request description:

  ## Additional Information

  * [bitcoin#27314](https://github.com/bitcoin/bitcoin/pull/27314) has been backported in this PR as [bitcoin#25838](https://github.com/bitcoin/bitcoin/pull/25838) (backported in [dash#6384](https://github.com/dashpay/dash/pull/6384)) broke Clang depends builds.

  * [bitcoin#28954](https://github.com/bitcoin/bitcoin/pull/28954) has been backported to fix a problem associated with multiprocess runs ([build](https://gitlab.com/dashpay/dash/-/jobs/8396677312#L2921)).

  * Support for multiprocess builds were enabled _proper_ in [dash#6143](https://github.com/dashpay/dash/pull/6143) but unfortunately, the configuration params for multiprocess builds were not processed by CI as the build variant was not added to `matrix.sh` ([source](6a51ab271d/ci/dash/matrix.sh)). This is evident by comparing two variants with Boost::Process enablement (`--with-boost-process`), `linux64_fuzz` ([source](6a51ab271d/ci/test/00_setup_env_native_fuzz.sh (L19))) and `linux64_multiprocess` ([source](6a51ab271d/ci/test/00_setup_env_native_multiprocess.sh (L13))).

    Looking at a `develop` (6a51ab271d) build, the fuzz build has it enabled ([source](https://gitlab.com/dashpay/dash/-/jobs/8394892905#L737)) while the multiprocess build doesn't ([source](https://gitlab.com/dashpay/dash/-/jobs/8394892909#L1524)) despite both scripts having the enablement argument.

  ## Breaking Changes

  None expected.

  ## Checklist:

  - [x] I have performed a self-review of my own code
  - [x] I have commented my code, particularly in hard-to-understand areas **(note: N/A)**
  - [x] I have added or updated relevant unit/integration/functional/e2e tests **(note: N/A)**
  - [x] I have made corresponding changes to the documentation **(note: N/A)**
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  PastaPastaPasta:
    utACK 27d9763b1b
  UdjinM6:
    utACK 27d9763b1b

Tree-SHA512: 3e2fb72d4211875a162d3aecb994c5bd43b2f6d9fea0804d7e00a38a034672730f9351ceb9256ace38e32f7ef81527c8a034a870e5099a277dfd06f9fa54b480
2024-12-16 20:42:35 -06:00
pasta
0968a0023b
Merge #6492: test: add functional tests for coinjoinsalt RPC
16c2e13fb4 test: add functional tests for `coinjoinsalt` RPC (Kittywhiskers Van Gogh)
a1b256b06f test: extend CoinJoin RPC tests to include more cases, add logging (Kittywhiskers Van Gogh)
c6dd3dd567 test: rename test functions to reflect RPC used, simplify them (Kittywhiskers Van Gogh)
ff29c62103 test: run CoinJoin RPC tests using blank wallet (Kittywhiskers Van Gogh)

Pull request description:

  ## Additional Information

  * Current suite of tests do not check if restoring salt results in restoring CoinJoin balance. This is because functional tests currently do not test CoinJoin mixing (and thus, routines for the same are not currently present).

  ## Breaking Changes

  None expected.

  ## Checklist:

  - [x] I have performed a self-review of my own code
  - [x] I have commented my code, particularly in hard-to-understand areas
  - [x] I have added or updated relevant unit/integration/functional/e2e tests
  - [x] I have made corresponding changes to the documentation **(note: N/A)**
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  knst:
    utACK 16c2e13fb4
  UdjinM6:
    utACK 16c2e13fb4

Tree-SHA512: 0ce4e67f2caf0619cae42e8158cd39fba24c0a86050e061511ea23c4c0bf34a0eede72917516b6039d7ac15f85730ab36ba9ec1c42d0eb271f6cb4341389bcec
2024-12-16 20:38:11 -06:00
Kittywhiskers Van Gogh
04ce1fea52
ci: deduplicate macOS SDK setup logic
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
2024-12-16 12:13:27 +00:00
Kittywhiskers Van Gogh
16c2e13fb4
test: add functional tests for coinjoinsalt RPC 2024-12-16 08:33:23 +00:00
Kittywhiskers Van Gogh
a1b256b06f
test: extend CoinJoin RPC tests to include more cases, add logging 2024-12-16 08:33:22 +00:00
Kittywhiskers Van Gogh
c6dd3dd567
test: rename test functions to reflect RPC used, simplify them 2024-12-16 08:31:27 +00:00
Kittywhiskers Van Gogh
ff29c62103
test: run CoinJoin RPC tests using blank wallet 2024-12-16 08:31:27 +00:00
Kittywhiskers Van Gogh
27d9763b1b
fix: add linux64_multiprocess BUILD_TARGET to matrix, mend C(XX) 2024-12-15 13:12:30 +00:00
Kittywhiskers Van Gogh
26cc5a1c90
ci: use underscore to separate variant name from target triple 2024-12-15 13:12:25 +00:00
Kittywhiskers Van Gogh
d0131a5259
trivial: sort BUILD_TARGET on GitHub and in matrix.sh alphabetically 2024-12-15 13:12:04 +00:00
Kittywhiskers Van Gogh
4f1b5c165b
merge bitcoin#28954: Reduce use of bash -c 2024-12-15 13:08:32 +00:00
Kittywhiskers Van Gogh
a49162ffae
merge bitcoin#27314: Fix handling of CXX=clang++ when building qt package 2024-12-15 13:08:29 +00:00
Kittywhiskers Van Gogh
8dd0db7de9
ci: fix "LC_ALL: cannot change locale (en_US.UTF-8)" in Guix container 2024-12-15 11:02:55 +00:00
Kittywhiskers Van Gogh
187fe17650
ci: don't stage packages in /tmp, reduce layers for cppcheck build 2024-12-15 11:02:55 +00:00
Kittywhiskers Van Gogh
eef863554a
ci: install i386 packages only if host is amd64, merge layers 2024-12-15 11:02:55 +00:00
Kittywhiskers Van Gogh
e7702292d1
ci: purge package manager cache after each interaction 2024-12-15 11:02:55 +00:00
Kittywhiskers Van Gogh
b7099eed47
ci: remove redundant version attribute, avoid lldb personality error 2024-12-15 11:02:54 +00:00
Kittywhiskers Van Gogh
64cdc42130
ci: add LLVM library path to LD_LIBRARY_PATH and GDB allowlist 2024-12-15 10:59:47 +00:00
Kittywhiskers Van Gogh
440fd3fe21
ci: drop distro LLVM packages, move Clang install up, set defaults
Also simplify the download and execution of `llvm.sh`
2024-12-15 10:59:46 +00:00
merge-script
3931608858
Merge bitcoin/bitcoin#22543: test: Use MiniWallet in mempool_limit.py
08634e82c68ea1be79e1395f4f551082f497023f fix typos in logging messages (ShubhamPalriwala)
d447ded6babebe7c7948e585c9e78bf34dbef226 replace: self.nodes[0] with node (ShubhamPalriwala)
dddca3899c4738e512313a85aeb006310e34e31f test: use MiniWallet in mempool_limit.py (ShubhamPalriwala)

Pull request description:

  This is a PR proposed in #20078

  This PR enables running another non-wallet functional test even when the wallet is disabled thanks to the MiniWallet, i.e. it can be run even when bitcoin-core is compiled with --disable-wallet.

  It also includes changes in wallet.py in the form of a new method, `create_large_transactions()` for the MiniWallet to create large transactions.

  Efforts for this feature started in #20874 but were not continued and that PR was closed hence I picked this up.

  To test this PR locally, compile and build bitcoin-core without the wallet and run:
  ```
  $ test/functional/mempool_limit.py
  ```

ACKs for top commit:
  amitiuttarwar:
    ACK 08634e8, only git changes since last push (and one new line).
  Zero-1729:
    ACK 08634e82c68ea1be79e1395f4f551082f497023f 🧉

Tree-SHA512: 0f744ad26bf7a5a784aac1ed5077b59c95a36d1ff3ad0087ffd10ac8d5979f7362c63c20c2ce2bfa650fda02dfbcd60b1fceee049a2465c8d221cce51c20369f
2024-12-06 17:48:07 +05:30
MarcoFalke
f147373a32
Merge bitcoin/bitcoin#24449: fuzz: FuzzedFileProvider::write should not return negative value
fc471814dc34abb4d5479803ebb1033b572eda43 fuzz: FuzzedFileProvider::write should not return negative value (eugene)

Pull request description:

  Doing so can lead to a glibc crash (from 2005 but I think it's relevant https://sourceware.org/bugzilla/show_bug.cgi?id=2074). Also the manpage for fopencookie warns against this: https://man7.org/linux/man-pages/man3/fopencookie.3.html. This would invalidate the autofile seeds (and maybe others?) in qa-assets.

  On another note, I noticed that FuzzedFileProvider::seek has some confusing behavior with SEEK_END. It seems to me that if these handlers are supposed to mimic the real functions, that SEEK_END would use the offset from the end of the stream, rather than changing the offset with a random value between 0 and 4096. I could also open a PR to fix SEEK_END, but it would invalidate the seeds.

ACKs for top commit:
  MarcoFalke:
    cr ACK fc471814dc34abb4d5479803ebb1033b572eda43

Tree-SHA512: 9db41637f0df7f2b2407b82531cbc34f4ba9393063b63ec6786372e808fe991f7f24df45936c203fe0f9fc49686180c65ad57c2ce7d49e0c5402240616bcfede
2024-12-06 17:48:07 +05:30
W. J. van der Laan
2a2a2693d0
Merge bitcoin/bitcoin#23253: bitcoin-tx: Reject non-integral and out of range int strings
fa6f29de516c7af5206b91b59ada466032329250 bitcoin-tx: Reject non-integral and out of range multisig numbers (MarcoFalke)
fafab8ea5e6ed6b87fac57a5cd16a8135236cdd6 bitcoin-tx: Reject non-integral and out of range sequence ids (MarcoFalke)
fa53d3d8266ad0257315d07b71b4f8a711134622 test: Check that bitcoin-tx accepts whitespace around sequence id and multisig numbers (MarcoFalke)

Pull request description:

  Seems odd to silently accept arbitrary strings that don't even represent integral values.

  Fix that.

ACKs for top commit:
  practicalswift:
    cr ACK fa6f29de516c7af5206b91b59ada466032329250
  laanwj:
    Code review ACK fa6f29de516c7af5206b91b59ada466032329250
  Empact:
    Code review ACK fa6f29de51
  promag:
    Code review ACK fa6f29de516c7af5206b91b59ada466032329250.

Tree-SHA512: e31f7f21fe55ac069e755557bdbcae8d5d29e20ff82e441ebdfc65153e3a31a4edd46ad3e6dea5190ecbd1b8ea5a8f94daa5d59a3b7558e46e794e30db0e6c79
2024-12-06 17:48:07 +05:30
MarcoFalke
11eeae2ab9
Merge bitcoin/bitcoin#24219: Fix implicit-integer-sign-change in bloom
fad84a25956ec081f22aebbda309d168a3dc0004 refactor: Fixup uint64_t-cast style in touched line (MarcoFalke)
fa041878de786f5be74ec74a06ec407c99ca8656 Fix implicit-integer-sign-change in bloom (MarcoFalke)

Pull request description:

  Signed values don't really make sense when using `std::vector::operator[]`.

  Fix that and remove the suppression.

ACKs for top commit:
  PastaPastaPasta:
    utACK fad84a25956ec081f22aebbda309d168a3dc0004
  theStack:
    Code-review ACK fad84a25956ec081f22aebbda309d168a3dc0004

Tree-SHA512: 7139dd9aa098c41e4af1b6e63dd80e71a92b0a98062d1676b01fe550ffa8e21a5f84a578afa7a536d70dad1b8a5017625e3a9e2dda6f864b452ec77b130ddf2a
2024-12-05 08:43:28 +05:30
Hennadii Stepanov
f16265dd50
Merge bitcoin-core/gui#517: refactor, qt: Use std::chrono for parameters of QTimer methods
51250b0906e56b39488304208ad119c951b4ae7d refactor, qt: Use std::chrono for input_filter_delay constant (Hennadii Stepanov)
f3bdc143b67e8a5e763071a0774f6d994ca35c57 refactor, qt: Add SHUTDOWN_POLLING_DELAY constant (Hennadii Stepanov)
0e193deb523a4fa04e0ee69bd66f917895802ac9 refactor, qt: Use std::chrono for non-zero arguments in QTimer methods (Hennadii Stepanov)
6f0da958116ecc0e06332fad2f490e37b6884166 refactor, qt: Use std::chrono in ConfirmMessage parameter (Hennadii Stepanov)
33d520ac538fcd6285fd958578f1bd26295592e4 refactor, qt: Use std::chrono for MODEL_UPDATE_DELAY constant (Hennadii Stepanov)

Pull request description:

  Since Qt 5.8 `QTimer` methods have overloads that accept `std::chrono::milliseconds` arguments:
  - [`QTimer::singleShot`](https://doc.qt.io/archives/qt-5.9/qtimer.html#singleShot-8)
  - [`QTimer::start`](https://doc.qt.io/archives/qt-5.9/qtimer.html#start-2)

ACKs for top commit:
  promag:
    Code review ACK 51250b0906e56b39488304208ad119c951b4ae7d.
  shaavan:
    reACK 51250b0906e56b39488304208ad119c951b4ae7d

Tree-SHA512: aa843bb2322a84c0c2bb113d3b48d7bf02d7f09a770779dcde312c32887f973ef9445cdef42f39edaa599ff0f3d0457454f6153aa130efadd989e413d39c6062
2024-12-05 08:43:28 +05:30
laanwj
b212ca0515
Merge bitcoin/bitcoin#24365: wallet: Don't generate keys for wallets with private keys disabled during upgradewallet
c7376cc8d728f3a7c40f79bd57e7cef685def723 tests: Test upgrading wallet with privkeys disabled (Andrew Chow)
3d985d4f43b5344f998bcf6db22d02782e647a2a wallet: Don't generate keys when privkeys disabled when upgrading (Andrew Chow)

Pull request description:

  When we're upgrading a wallet, we shouldn't be trying to generate new keys for wallets where private keys are disabled.

  Fixes #23610

ACKs for top commit:
  laanwj:
    Code review ACK c7376cc8d728f3a7c40f79bd57e7cef685def723
  benthecarman:
    tACK c7376cc8d728f3a7c40f79bd57e7cef685def723 this fixed the issue for me

Tree-SHA512: fa07cf37df9196ff98671bb1ce5c9aa0bab46495066b4dab796d7e8e5d5c7adb414ff56adae4fd3e15658a610995bd19a9e1edb00c46144b0df635c5b343f3a6
2024-12-05 08:43:28 +05:30
MarcoFalke
66e77f7879
Merge bitcoin/bitcoin#23316: test: make the node param explicit in init_wallet()
7b3c9e4ee8feb552dc0fc4347db2d06e60894a9f Make explicit the node param in init_wallet() (lsilva01)

Pull request description:

  This PR changes the definition of `def init_wallet(self, i)` to `def init_wallet(self, *, node)` to make the node parameter explicit, as suggested in https://github.com/bitcoin/bitcoin/pull/22794#discussion_r713287448 .

ACKs for top commit:
  stratospher:
    tested ACK 7b3c9e4.

Tree-SHA512: 2ef036f4c2110b2f7dc893dc6eea8faa0a18edd7f8f59b25460a6c544df7238175ddd6a0d766e2bb206326b1c9afc84238c75613a0f01eeda89a8ccb7d86a4f1
2024-12-05 08:43:28 +05:30
MarcoFalke
995cae46af
Merge bitcoin/bitcoin#22794: test: Verify if wallet is compiled in rpc_invalid_address_message.py test
c2fbdca54915e85ffafe1a88858d3c70c2b1afe8 Add BECH32_INVALID_VERSION test (lsilva01)
b142f79ddb91a44f29fcb2afb7f2edf3ca17e168 skip test_getaddressinfo() if wallet is disabled (lsilva01)

Pull request description:

  Most of  `test/functional/rpc_invalid_address_message.py` does not requires wallet.
  But if the project is compiled in disable-wallet mode, the entire test will be skipped.

  This PR changes the test to run the RPC tests first and then checks if the wallet is compiled.

ACKs for top commit:
  stratospher:
    tested ACK c2fbdca

Tree-SHA512: 11fa2fedf4a15aa45e3f12490df8e22290a867d5de594247211499533c32289c68c0b60bd42dbf8305e43dbcc042789e7139317ef5c9f8cf386f2d84c91b9ac2
2024-12-05 08:43:28 +05:30
MarcoFalke
61a0140362
Merge bitcoin/bitcoin#23642: refactor: Call type-solver earlier in decodescript
33330702081f67cb05fd86e00b252f6355249513 refactor: Call type-solver earlier in decodescript (MarcoFalke)
fab0d998f4bf0f3f09afa51845d91408dd484408 style: Remove whitespace (MarcoFalke)

Pull request description:

  The current logic is a bit confusing. First creating the `UniValue` return dict, then parsing it again to get the type as `std::string`.

  Clean this up by using a strong type `TxoutType`. Also, remove whitespace.

ACKs for top commit:
  shaavan:
    ACK 33330702081f67cb05fd86e00b252f6355249513
  theStack:
    Code-review ACK 33330702081f67cb05fd86e00b252f6355249513

Tree-SHA512: 49db7bc614d2491cd3ec0177d21ad1e9924dbece1eb5635290cd7fd18cb30adf4711b891daf522e7c4f6baab3033b66393bbfcd1d4726f24f90a433124f925d6
2024-12-05 08:43:28 +05:30
Samuel Dobson
8a58b5e244
Merge bitcoin/bitcoin#22100: refactor: Clean up new wallet spend, receive files added #21207
b11a195ef450bd138aa03204a5e74fdd3ddced26 refactor: Detach wallet transaction methods (followup for move-only) (Russell Yanofsky)

Pull request description:

  This makes `CWallet` and `CWalletTx` methods in `spend.cpp` and `receive.cpp` files into standalone functions.

  It's a followup to [#21207 MOVEONLY: CWallet transaction code out of wallet.cpp/.h](https://github.com/bitcoin/bitcoin/pull/21207), which moved code from `wallet.cpp` to new `spend.cpp` and `receive.cpp` files.

  There are no changes in behavior. This is just making methods into functions and removing circular dependencies created by #21207. There are no comment or documentation changes, either. Removed comments from `transaction.h` are just migrated to `spend.h`, `receive.h`, and `wallet.h`.

  ---

  This commit was split off from #21206 so there are a few earlier review comments there

ACKs for top commit:
  achow101:
    ACK b11a195ef450bd138aa03204a5e74fdd3ddced26
  Sjors:
    utACK b11a195ef450bd138aa03204a5e74fdd3ddced26
  meshcollider:
    light ACK b11a195ef450bd138aa03204a5e74fdd3ddced26

Tree-SHA512: 75ce818d3f03b728b14b12e2d21bd20b7be73978601989cb37ff98254393300d1bb7823281449cd3d9e40756d67d42bd9a46bbdafd2e8baa95aaf2cb1c84549f
2024-11-27 12:38:23 +05:30
Andrew Chow
18ddb83fbc
Merge #22008: wallet: Cleanup and refactor CreateTransactionInternal
-BEGIN VERIFY SCRIPT-
sed -i 's/SelectCoinsMinConf/AttemptSelection/g' $(git grep -l SelectCoinsMinConf ./src)
-END VERIFY SCRIPT-
2024-11-27 12:38:22 +05:30
MarcoFalke
9e7f0e0d6e
Merge bitcoin/bitcoin#23640: MOVEONLY: Move helper functions from rpcwallet to wallet/rpc/util
ff945e553affbb7e25da1257a0dd47e413ec5164 MOVEONLY: Move utility functions from rpcwallet to wallet/rpc/util (Samuel Dobson)
7b04a064f6e8ee9d93e5a5ad54dab20b769083f2 Introduce wallet/rpc/util (Samuel Dobson)

Pull request description:

  This is part one of multiple to split up rpcwallet.cpp into smaller, more logical units.

  See #23622 for context and overall plan. I'll open PRs in stages to hopefully minimise conflicts.

  Can be reviewed with `--color-moved=dimmed-zebra`

  The end goal can be seen here: https://github.com/meshcollider/bitcoin/tree/202111_split_walletrpc

ACKs for top commit:
  MarcoFalke:
    nice, ACK ff945e553affbb7e25da1257a0dd47e413ec5164 🐰
  shaavan:
    ACK ff945e553affbb7e25da1257a0dd47e413ec5164

Tree-SHA512: 6e3d1de6db770fe2fca540c8c4f30183ab8258c26e3a1fb46937714d28818a52933eafbfcafe2995f6a6e2551a3f3dd3ec93363b81de7912c0d81f5749d1c86d
2024-11-27 12:32:06 +05:30
MarcoFalke
7bfcbb2f89
Merge bitcoin/bitcoin#23120: test: Remove unused and confusing main parameter from script_util
fa54efda9bc8f8f742dacbc3673516d88d9d601d test: pep-8 touched test (MarcoFalke)
fa4676805910bfea5549f5b51460c8456bc8945c test: Remove unused and confusing main parameter from script_util (MarcoFalke)

Pull request description:

ACKs for top commit:
  fanquake:
    ACK fa54efda9bc8f8f742dacbc3673516d88d9d601d

Tree-SHA512: 124e888e16c92bb24ab4d6f68a768d295500a48f8c6c0b4f069493effcd761f80be78dd93b31edbb529ebe4c8aaca764aaff48d1e3b23659dde722981dc787a5
2024-11-27 12:32:06 +05:30
MarcoFalke
6801e0d1ed
Merge bitcoin/bitcoin#23346: util, refactor: Improve headers for bitcoin-wallet tool
3431839c33fa3892c982322e4add39e28ddba719 util, refactor: Improve headers for bitcoin-wallet tool (Hennadii Stepanov)

Pull request description:

  This PR:
  - removes unneeded `#include <wallet/wallet.h>` from `<wallet/wallettool.h>`
  - introduces class forward declaration in `<wallet/wallettool.h>`
  - added `#include <config/bitcoin-config.h>` to `wallet/wallettool.cpp` where the `USE_BDB` macro is used

Top commit has no ACKs.

Tree-SHA512: a0de560d821f8b570ae806a1165b9b382c9e0b339687d932052fa4c38ab2ba493e7e050f19adc02ad7db40c42cf88ac1d37209f9071494a0ab268ed33ff22b9f
2024-11-27 12:32:05 +05:30
MarcoFalke
0469c6a9ae
Merge bitcoin/bitcoin#23712: test: interface_bitcoin_cli.py: check specified wallet type availability
b57bf25cfee3d3d0e08e5565b23e5e12ea88aee5 test: interface_bitcoin_cli.py: check specified wallet type availability (Sebastian Falbesoner)

Pull request description:

  Currently the test `interface_bitcoin_cli.py` performs the wallet-relevant parts if _any_ wallet type support is compiled in, independently of
  whether the test is run with legacy or descriptor wallet specified. This leads to a failure if the test is started with the `--legacy-wallet` parameter, but bitcoind is compiled without BDB support, see e.g
   https://github.com/bitcoin/bitcoin/pull/23686#issuecomment-987705540

  Fix this by checking if the specified wallet type (BDB for legacy wallet, SQLite for descriptor wallet) is available.

  Should further pave the way for #23682.

ACKs for top commit:
  achow101:
    ACK b57bf25cfee3d3d0e08e5565b23e5e12ea88aee5

Tree-SHA512: ddb5a94ba61133eff8de79d4946b3b9d476232b26e83bf768894cac4691e72602f88b6c02c72b992e12c2feb9bff1f0a2e0a265948a00954311104add1347184
2024-11-27 12:32:00 +05:30
62 changed files with 899 additions and 649 deletions

View File

@ -114,22 +114,22 @@ jobs:
- build_target: linux64
host: x86_64-pc-linux-gnu
depends_on: linux64
- build_target: linux64_tsan
host: x86_64-pc-linux-gnu
depends_on: linux64
- build_target: linux64_ubsan
- build_target: linux64_cxx20
host: x86_64-pc-linux-gnu
depends_on: linux64
- build_target: linux64_fuzz
host: x86_64-pc-linux-gnu
depends_on: linux64
- build_target: linux64_cxx20
- build_target: linux64_nowallet
host: x86_64-pc-linux-gnu
depends_on: linux64
- build_target: linux64_sqlite
host: x86_64-pc-linux-gnu
depends_on: linux64
- build_target: linux64_nowallet
- build_target: linux64_tsan
host: x86_64-pc-linux-gnu
depends_on: linux64
- build_target: linux64_ubsan
host: x86_64-pc-linux-gnu
depends_on: linux64
container:

View File

@ -40,26 +40,11 @@ builder-image:
needs:
- builder-image
image: $CI_REGISTRY_IMAGE:builder-$CI_COMMIT_REF_SLUG
variables:
SDK_URL: https://bitcoincore.org/depends-sources/sdks
XCODE_VERSION: "15.0"
XCODE_BUILD_ID: 15A240d
before_script:
- echo HOST=$HOST
- |
if [ "$HOST" = "x86_64-apple-darwin" ]; then
mkdir -p depends/SDKs
mkdir -p depends/sdk-sources
OSX_SDK_BASENAME="Xcode-${XCODE_VERSION}-${XCODE_BUILD_ID}-extracted-SDK-with-libcxx-headers.tar.gz"
OSX_SDK_PATH="depends/sdk-sources/${OSX_SDK_BASENAME}"
if [ ! -f "$OSX_SDK_PATH" ]; then
echo "Downloading MacOS SDK"
curl --location --fail "${SDK_URL}/${OSX_SDK_BASENAME}" -o "$OSX_SDK_PATH"
fi
if [ -f "$OSX_SDK_PATH" ]; then
echo "Extracting MacOS SDK"
tar -C depends/SDKs -xf "$OSX_SDK_PATH"
fi
echo HOST=${HOST}
if [[ "${HOST}" == "x86_64-apple-darwin" ]]; then
./contrib/containers/guix/scripts/setup-sdk
fi
script:
- make -j$(nproc) -C depends HOST=$HOST $DEP_OPTS
@ -193,13 +178,13 @@ x86_64-w64-mingw32:
variables:
HOST: x86_64-w64-mingw32
x86_64-pc-linux-gnu-debug:
x86_64-pc-linux-gnu_debug:
extends: .build-depends-template
variables:
HOST: x86_64-pc-linux-gnu
DEP_OPTS: "DEBUG=1"
x86_64-pc-linux-gnu-nowallet:
x86_64-pc-linux-gnu_nowallet:
extends:
- .build-depends-template
- .skip-in-fast-mode-template
@ -207,13 +192,13 @@ x86_64-pc-linux-gnu-nowallet:
HOST: x86_64-pc-linux-gnu
DEP_OPTS: "NO_WALLET=1"
x86_64-pc-linux-gnu-multiprocess:
x86_64-pc-linux-gnu_multiprocess:
extends:
- .build-depends-template
- .skip-in-fast-mode-template
variables:
HOST: x86_64-pc-linux-gnu
DEP_OPTS: "MULTIPROCESS=1"
DEP_OPTS: "DEBUG=1 MULTIPROCESS=1"
x86_64-apple-darwin:
extends:
@ -243,7 +228,7 @@ win64-build:
linux64-build:
extends: .build-template
needs:
- x86_64-pc-linux-gnu-debug
- x86_64-pc-linux-gnu_debug
variables:
BUILD_TARGET: linux64
@ -252,7 +237,7 @@ linux64_cxx20-build:
- .build-template
- .skip-in-fast-mode-template
needs:
- x86_64-pc-linux-gnu-debug
- x86_64-pc-linux-gnu_debug
variables:
BUILD_TARGET: linux64_cxx20
@ -261,7 +246,7 @@ linux64_sqlite-build:
- .build-template
- .skip-in-fast-mode-template
needs:
- x86_64-pc-linux-gnu-debug
- x86_64-pc-linux-gnu_debug
variables:
BUILD_TARGET: linux64_sqlite
@ -270,7 +255,7 @@ linux64_fuzz-build:
- .build-template
- .skip-in-fast-mode-template
needs:
- x86_64-pc-linux-gnu-debug
- x86_64-pc-linux-gnu_debug
variables:
BUILD_TARGET: linux64_fuzz
@ -279,7 +264,7 @@ linux64_fuzz-build:
# - .build-template
# - .skip-in-fast-mode-template
# needs:
# - x86_64-pc-linux-gnu-debug
# - x86_64-pc-linux-gnu_debug
# variables:
# BUILD_TARGET: linux64_asan
@ -288,7 +273,7 @@ linux64_tsan-build:
- .build-template
- .skip-in-fast-mode-template
needs:
- x86_64-pc-linux-gnu-debug
- x86_64-pc-linux-gnu_debug
variables:
BUILD_TARGET: linux64_tsan
@ -297,7 +282,7 @@ linux64_ubsan-build:
- .build-template
- .skip-in-fast-mode-template
needs:
- x86_64-pc-linux-gnu-debug
- x86_64-pc-linux-gnu_debug
variables:
BUILD_TARGET: linux64_ubsan
@ -306,7 +291,7 @@ linux64_nowallet-build:
- .build-template
- .skip-in-fast-mode-template
needs:
- x86_64-pc-linux-gnu-nowallet
- x86_64-pc-linux-gnu_nowallet
variables:
BUILD_TARGET: linux64_nowallet
@ -315,7 +300,7 @@ linux64_multiprocess-build:
- .build-template
- .skip-in-fast-mode-template
needs:
- x86_64-pc-linux-gnu-multiprocess
- x86_64-pc-linux-gnu_multiprocess
variables:
BUILD_TARGET: linux64_multiprocess
@ -324,7 +309,7 @@ linux64_multiprocess-build:
# - .build-template
# - .skip-in-fast-mode-template
# needs:
# - x86_64-pc-linux-gnu-debug
# - x86_64-pc-linux-gnu_debug
# variables:
# BUILD_TARGET: linux64_valgrind

View File

@ -20,17 +20,8 @@ mkdir -p $CACHE_DIR/sdk-sources
ln -s $CACHE_DIR/depends ${DEPENDS_DIR}/built
ln -s $CACHE_DIR/sdk-sources ${DEPENDS_DIR}/sdk-sources
mkdir -p ${DEPENDS_DIR}/SDKs
if [ -n "$XCODE_VERSION" ]; then
OSX_SDK_BASENAME="Xcode-${XCODE_VERSION}-${XCODE_BUILD_ID}-extracted-SDK-with-libcxx-headers.tar.gz"
OSX_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${OSX_SDK_BASENAME}"
if [ ! -f "$OSX_SDK_PATH" ]; then
curl --location --fail "${SDK_URL}/${OSX_SDK_BASENAME}" -o "$OSX_SDK_PATH"
fi
if [ -f "$OSX_SDK_PATH" ]; then
tar -C ${DEPENDS_DIR}/SDKs -xf "$OSX_SDK_PATH"
fi
if [[ "${HOST}" == "x86_64-apple-darwin" ]]; then
./contrib/containers/guix/scripts/setup-sdk
fi
make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS

View File

@ -18,28 +18,30 @@ export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/
if [ "$BUILD_TARGET" = "arm-linux" ]; then
source ./ci/test/00_setup_env_arm.sh
elif [ "$BUILD_TARGET" = "win64" ]; then
source ./ci/test/00_setup_env_win64.sh
elif [ "$BUILD_TARGET" = "linux64" ]; then
source ./ci/test/00_setup_env_native_qt5.sh
elif [ "$BUILD_TARGET" = "linux64_asan" ]; then
source ./ci/test/00_setup_env_native_asan.sh
elif [ "$BUILD_TARGET" = "linux64_cxx20" ]; then
source ./ci/test/00_setup_env_native_cxx20.sh
elif [ "$BUILD_TARGET" = "linux64_fuzz" ]; then
source ./ci/test/00_setup_env_native_fuzz.sh
elif [ "$BUILD_TARGET" = "linux64_multiprocess" ]; then
source ./ci/test/00_setup_env_native_multiprocess.sh
elif [ "$BUILD_TARGET" = "linux64_nowallet" ]; then
source ./ci/test/00_setup_env_native_nowallet.sh
elif [ "$BUILD_TARGET" = "linux64_sqlite" ]; then
source ./ci/test/00_setup_env_native_sqlite.sh
elif [ "$BUILD_TARGET" = "linux64_tsan" ]; then
source ./ci/test/00_setup_env_native_tsan.sh
elif [ "$BUILD_TARGET" = "linux64_ubsan" ]; then
source ./ci/test/00_setup_env_native_ubsan.sh
elif [ "$BUILD_TARGET" = "linux64_fuzz" ]; then
source ./ci/test/00_setup_env_native_fuzz.sh
elif [ "$BUILD_TARGET" = "linux64_cxx20" ]; then
source ./ci/test/00_setup_env_native_cxx20.sh
elif [ "$BUILD_TARGET" = "linux64_sqlite" ]; then
source ./ci/test/00_setup_env_native_sqlite.sh
elif [ "$BUILD_TARGET" = "linux64_nowallet" ]; then
source ./ci/test/00_setup_env_native_nowallet.sh
elif [ "$BUILD_TARGET" = "linux64_valgrind" ]; then
source ./ci/test/00_setup_env_native_valgrind.sh
elif [ "$BUILD_TARGET" = "mac" ]; then
source ./ci/test/00_setup_env_mac.sh
elif [ "$BUILD_TARGET" = "s390x" ]; then
source ./ci/test/00_setup_env_s390x.sh
elif [ "$BUILD_TARGET" = "win64" ]; then
source ./ci/test/00_setup_env_win64.sh
fi

View File

@ -42,7 +42,7 @@ echo "Using socketevents mode: $SOCKETEVENTS"
EXTRA_ARGS="--dashd-arg=-socketevents=$SOCKETEVENTS"
set +e
LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib ${TEST_RUNNER_ENV} ./test/functional/test_runner.py --ci --attempts=3 --ansi --combinedlogslen=4000 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA} --failfast --nocleanup --tmpdir=$(pwd)/testdatadirs $PASS_ARGS $EXTRA_ARGS
LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib ./test/functional/test_runner.py --ci --attempts=3 --ansi --combinedlogslen=4000 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA} --failfast --nocleanup --tmpdir=$(pwd)/testdatadirs $PASS_ARGS $EXTRA_ARGS
RESULT=$?
set -e

View File

@ -29,8 +29,8 @@ if [ "$DIRECT_WINE_EXEC_TESTS" = "true" ]; then
wine ./src/test/test_dash.exe
else
if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
${TEST_RUNNER_ENV} ./src/test/test_dash --catch_system_errors=no -l test_suite
./src/test/test_dash --catch_system_errors=no -l test_suite
else
${TEST_RUNNER_ENV} make $MAKEJOBS check VERBOSE=1
make $MAKEJOBS check VERBOSE=1
fi
fi

View File

@ -43,7 +43,6 @@ export RUN_SECURITY_TESTS=${RUN_SECURITY_TESTS:-false}
# This is needed because some ci machines have slow CPU or disk, so sanitizers
# might be slow or a reindex might be waiting on disk IO.
export TEST_RUNNER_TIMEOUT_FACTOR=${TEST_RUNNER_TIMEOUT_FACTOR:-4}
export TEST_RUNNER_ENV=${TEST_RUNNER_ENV:-}
export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false}
export EXPECTED_TESTS_DURATION_IN_SECONDS=${EXPECTED_TESTS_DURATION_IN_SECONDS:-1000}

View File

@ -11,5 +11,5 @@ export PACKAGES="cmake python3 llvm clang"
export DEP_OPTS="DEBUG=1 MULTIPROCESS=1"
export GOAL="install"
export TEST_RUNNER_EXTRA="--v2transport"
export BITCOIN_CONFIG="--with-boost-process --enable-debug CC=clang CXX=clang++" # Use clang to avoid OOM
export TEST_RUNNER_ENV="BITCOIND=dash-node"
export BITCOIN_CONFIG="--with-boost-process --enable-debug CC=clang-16 CXX=clang++-16" # Use clang to avoid OOM
export BITCOIND=dash-node # Used in functional tests

View File

@ -19,7 +19,6 @@ fi
# Use debian to avoid 404 apt errors
export CONTAINER_NAME=ci_s390x
export RUN_UNIT_TESTS=true
export TEST_RUNNER_ENV="LC_ALL=C"
export RUN_FUNCTIONAL_TESTS=true
export GOAL="install"
export BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests --with-boost-process" # GUI tests disabled for now, see https://github.com/bitcoin/bitcoin/issues/23730

View File

@ -7,14 +7,17 @@ ENV DEBIAN_FRONTEND="noninteractive" TZ="Europe/London"
# (zlib1g-dev is needed for the Qt host binary builds, but should not be used by target binaries)
ENV APT_ARGS="-y --no-install-recommends --no-upgrade"
# Install packages for i386; disabled on aarch64 and arm64 hosts
RUN (dpkg --print-architecture | grep -Eq 'aarch64|arm64' || dpkg --add-architecture i386)
RUN (dpkg --print-architecture | grep -Eq 'aarch64|arm64' || (apt-get update && apt-get install $APT_ARGS \
g++-multilib \
wine32) && rm -rf /var/lib/apt/lists/*)
RUN apt-get update && apt-get install $APT_ARGS \
# Install packages for i386 on amd64 hosts, then install common packages
RUN set -ex; \
apt-get update && \
if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
dpkg --add-architecture i386 && \
apt-get update && \
apt-get install $APT_ARGS \
g++-multilib \
wine32; \
fi; \
apt-get install $APT_ARGS \
autotools-dev \
automake \
autoconf \
@ -23,13 +26,11 @@ RUN apt-get update && apt-get install $APT_ARGS \
bsdmainutils \
curl \
ccache \
clang \
cmake \
g++ \
gettext \
git \
libc++-dev \
libc++abi-dev \
gnupg \
libtool \
libxcb-icccm4 \
libxcb-image0 \
@ -42,11 +43,38 @@ RUN apt-get update && apt-get install $APT_ARGS \
libxcb-xinerama0 \
libxcb-xkb1 \
libxkbcommon-x11-0 \
wget \
lsb-release \
software-properties-common \
unzip \
wget \
m4 \
pkg-config \
zlib1g-dev
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Clang+LLVM and set it as default
# We don't need all packages but the default set doesn't include some
# packages we want so we will need to install some of them manually.
ARG LLVM_VERSION=16
RUN set -ex; \
echo "Installing LLVM and Clang ${LLVM_VERSION}..."; \
curl -sL https://apt.llvm.org/llvm.sh | bash -s "${LLVM_VERSION}"; \
echo "Installing additional packages..."; \
apt-get update && apt-get install $APT_ARGS \
"clang-format-${LLVM_VERSION}" \
"clang-tidy-${LLVM_VERSION}" \
"libc++-${LLVM_VERSION}-dev" \
"libc++abi-${LLVM_VERSION}-dev" \
"libclang-rt-${LLVM_VERSION}-dev"; \
rm -rf /var/lib/apt/lists/*; \
echo "Setting defaults..."; \
lldbUpdAltArgs="update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-${LLVM_VERSION} 100"; \
for binName in clang clang++ clang-format clang-tidy clangd ld.lld lldb lldb-server; do \
lldbUpdAltArgs="${lldbUpdAltArgs} --slave /usr/bin/${binName} ${binName} /usr/bin/${binName}-${LLVM_VERSION}"; \
done; \
sh -c "${lldbUpdAltArgs}";
# LD_LIBRARY_PATH is empty by default, this is the first entry
ENV LD_LIBRARY_PATH="/usr/lib/llvm-${LLVM_VERSION}/lib"
# Python setup
# PYTHON_VERSION should match the value in .python-version
@ -61,10 +89,11 @@ RUN apt-get update && apt-get install $APT_ARGS \
libreadline-dev \
libsqlite3-dev \
libssl-dev \
llvm \
make \
tk-dev \
xz-utils
xz-utils \
&& rm -rf /var/lib/apt/lists/*
ENV PYENV_ROOT="/usr/local/pyenv"
ENV PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${PATH}"
RUN curl https://pyenv.run | bash \
@ -82,19 +111,38 @@ RUN pip3 install \
pyzmq==22.3.0 \
vulture==2.3
# dash_hash
ARG DASH_HASH_VERSION=1.4.0
RUN git clone --depth 1 --no-tags --branch=${DASH_HASH_VERSION} https://github.com/dashpay/dash_hash
RUN cd dash_hash && pip3 install -r requirements.txt .
RUN set -ex; \
cd /tmp; \
git clone --depth 1 --no-tags --branch=${DASH_HASH_VERSION} https://github.com/dashpay/dash_hash; \
cd dash_hash && pip3 install -r requirements.txt .; \
cd .. && rm -rf dash_hash
ARG CPPCHECK_VERSION=2.13.0
RUN set -ex; \
curl -fL "https://github.com/danmar/cppcheck/archive/${CPPCHECK_VERSION}.tar.gz" -o /tmp/cppcheck.tar.gz; \
mkdir -p /opt/cppcheck && tar -xzf /tmp/cppcheck.tar.gz -C /opt/cppcheck --strip-components=1 && rm /tmp/cppcheck.tar.gz; \
cd /opt/cppcheck; \
mkdir build && cd build && cmake .. && cmake --build . -j "$(( $(nproc) - 1 ))"; \
mkdir /usr/local/share/Cppcheck && ln -s /opt/cppcheck/cfg/ /usr/local/share/Cppcheck/cfg; \
rm -rf /tmp/cppcheck.tar.gz
ENV PATH="/opt/cppcheck/build/bin:${PATH}"
ARG SHELLCHECK_VERSION=v0.7.1
RUN set -ex; \
curl -fL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" -o /tmp/shellcheck.tar.xz; \
mkdir -p /opt/shellcheck && tar -xf /tmp/shellcheck.tar.xz -C /opt/shellcheck --strip-components=1 && rm /tmp/shellcheck.tar.xz
ENV PATH="/opt/shellcheck:${PATH}"
# Add user with specified (or default) user/group ids and setup configuration files
ARG USER_ID=1000
ARG GROUP_ID=1000
# add user with specified (or default) user/group ids
ENV USER_ID="${USER_ID}"
ENV GROUP_ID="${GROUP_ID}"
RUN groupadd -g ${GROUP_ID} dash
RUN useradd -u ${USER_ID} -g dash -s /bin/bash -m -d /home/dash dash
RUN set -ex; \
groupadd -g ${GROUP_ID} dash; \
useradd -u ${USER_ID} -g dash -s /bin/bash -m -d /home/dash dash; \
mkdir -p /home/dash/.config/gdb; \
echo "add-auto-load-safe-path /usr/lib/llvm-${LLVM_VERSION}/lib" | tee /home/dash/.config/gdb/gdbinit; \
chown ${USER_ID}:${GROUP_ID} -R /home/dash
# Packages needed for all target builds
RUN apt-get update && apt-get install $APT_ARGS \
@ -111,17 +159,8 @@ RUN apt-get update && apt-get install $APT_ARGS \
valgrind \
wine-stable \
wine64 \
xorriso
ARG CPPCHECK_VERSION=2.13.0
RUN curl -sL "https://github.com/danmar/cppcheck/archive/${CPPCHECK_VERSION}.tar.gz" | tar -xvzf - --directory /tmp/
RUN cd /tmp/cppcheck-${CPPCHECK_VERSION} && mkdir build && cd build && cmake .. && cmake --build . -j 8
ENV PATH="/tmp/cppcheck-${CPPCHECK_VERSION}/build/bin:${PATH}"
RUN mkdir /usr/local/share/Cppcheck && ln -s /tmp/cppcheck-${CPPCHECK_VERSION}/cfg/ /usr/local/share/Cppcheck/cfg
ARG SHELLCHECK_VERSION=v0.7.1
RUN curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/
ENV PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}"
xorriso \
&& rm -rf /var/lib/apt/lists/*
# This is a hack. It is needed because gcc-multilib and g++-multilib are conflicting with g++-arm-linux-gnueabihf. This is
# due to gcc-multilib installing the following symbolic link, which is needed for -m32 support. However, this causes
@ -135,20 +174,6 @@ RUN \
update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix; \
exit 0
ARG LLVM_VERSION=16
# Setup Clang+LLVM support
RUN apt-get update && apt-get install $APT_ARGS \
lsb-release \
software-properties-common \
gnupg \
&& rm -rf /var/lib/apt/lists/*
RUN cd /tmp && \
wget https://apt.llvm.org/llvm.sh && \
chmod +x llvm.sh && \
/tmp/llvm.sh ${LLVM_VERSION} && \
rm -rf /tmp/llvm.sh
RUN \
mkdir -p /src/dash && \
mkdir -p /cache/ccache && \

View File

@ -1,17 +1,18 @@
version: "3.9"
services:
container:
entrypoint: /bin/bash
build:
context: '..'
dockerfile: './develop/Dockerfile'
tty: true # Equivalent to -t
stdin_open: true # Equivalent to -i
ports:
- "9998:9998" # Mainnet Ports
- "9999:9999"
- "19998:19998" # Testnet Ports
- "19999:19999"
security_opt:
- seccomp:unconfined
stdin_open: true # Equivalent to -i
tty: true # Equivalent to -t
# A note about volumes:
#

View File

@ -18,7 +18,11 @@ RUN apt-get update && \
sudo \
wget \
xz-utils && \
rm -rf /var/lib/apt/lists/*
rm -rf /var/lib/apt/lists/*; \
targetLocale="en_US.UTF-8"; \
locale-gen ${targetLocale} && \
update-locale LC_ALL=${targetLocale} && \
update-locale LANG=${targetLocale};
ARG guix_download_path=ftp://ftp.gnu.org/gnu/guix
ARG guix_version=1.4.0
@ -30,8 +34,7 @@ ENV PATH="/usr/local/bin:/usr/local/guix/current/bin:$PATH"
# Application Setup
# https://guix.gnu.org/manual/en/html_node/Application-Setup.html
ENV GUIX_LOCPATH="/usr/local/guix/profile" \
LC_ALL="en_US.UTF-8"
ENV GUIX_LOCPATH="/usr/local/guix/profile"
RUN guix_file_name=guix-binary-${guix_version}.$(uname -m)-linux.tar.xz && \
eval "guix_checksum=\${guix_checksum_$(uname -m)}" && \
@ -74,18 +77,19 @@ RUN usermod -aG sudo ${USERNAME} && \
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
# Copy required files to container
COPY --from=docker_root ./motd.txt /etc/motd
COPY --from=docker_root ./scripts/entrypoint /usr/local/bin/entrypoint
COPY --from=docker_root ./scripts/guix-check /usr/local/bin/guix-check
COPY --from=docker_root ./scripts/guix-start /usr/local/bin/guix-start
COPY --from=docker_root ./motd.txt /etc/motd
COPY --from=docker_root ./scripts/entrypoint /usr/local/bin/entrypoint
COPY --from=docker_root ./scripts/guix-check /usr/local/bin/guix-check
COPY --from=docker_root ./scripts/guix-start /usr/local/bin/guix-start
COPY --from=docker_root ./scripts/setup-sdk /usr/local/bin/setup-sdk
# Create directories for mounting to save/restore cache and grant necessary permissions
RUN mkdir -p \
/home/${USERNAME}/.cache \
/src/dash/depends/{built,sources,work} && \
/src/dash/depends/{built,sources,work}; \
chown -R ${USER_ID}:${GROUP_ID} \
/home/${USERNAME}/.cache \
/src
/src;
WORKDIR "/src/dash"

View File

@ -1,4 +1,3 @@
version: "3.9"
services:
guix_ubuntu:
build:

View File

@ -9,19 +9,10 @@ if [[ ! -d "${WORKSPACE_PATH}" || ! "${WORKSPACE_PATH}" = /* || ! -f "${WORKSPAC
exit 1
fi
XCODE_VERSION="15.0"
XCODE_RELEASE="15A240d"
XCODE_ARCHIVE="Xcode-${XCODE_VERSION}-${XCODE_RELEASE}-extracted-SDK-with-libcxx-headers"
XCODE_SOURCE="${XCODE_SOURCE:-https://bitcoincore.org/depends-sources/sdks}"
export SDK_PATH="${SDK_PATH:-${WORKSPACE_PATH}/depends/SDKs}"
export SDK_SRCS="${SDK_PATH:-${WORKSPACE_PATH}/depends/sdk-sources}"
# Check if macOS SDK is present, if not, download it
if [[ ! -d "${SDK_PATH}/${XCODE_ARCHIVE}" ]]; then
echo "Preparing macOS SDK..."
mkdir -p "${SDK_PATH}"
curl -L "${XCODE_SOURCE}/${XCODE_ARCHIVE}.tar.gz" | tar -xz -C "${SDK_PATH}"
fi
./contrib/containers/guix/scripts/setup-sdk
# Add safe.directory option only when WORKSPACE_PATH was specified via cmd-line arguments (happens in CI)
if [[ -n "${1}" ]]; then

View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Copyright (c) 2024 The Dash Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C.UTF-8
set -eo pipefail
SDK_URL="${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}"
SDK_PATH="${SDK_PATH:-depends/SDKs}"
SDK_SRCS="${SDK_SOURCES:-depends/sdk-sources}"
XCODE_VERSION="${XCODE_VERSION:-15.0}"
XCODE_RELEASE="${XCODE_RELEASE:-15A240d}"
XCODE_ARCHIVE="Xcode-${XCODE_VERSION}-${XCODE_RELEASE}-extracted-SDK-with-libcxx-headers"
XCODE_AR_PATH="${SDK_SRCS}/${XCODE_ARCHIVE}.tar.gz"
if [ ! -d "${SDK_PATH}/${XCODE_ARCHIVE}" ]; then
if [ ! -f "${XCODE_AR_PATH}" ]; then
echo "Downloading macOS SDK..."
mkdir -p "${SDK_SRCS}"
curl --location --fail "${SDK_URL}/${XCODE_ARCHIVE}.tar.gz" -o "${XCODE_AR_PATH}"
fi
echo "Extracting macOS SDK..."
mkdir -p "${SDK_PATH}"
tar -C "${SDK_PATH}" -xf "${XCODE_AR_PATH}"
fi

View File

@ -159,9 +159,15 @@ $(package)_config_opts_linux += -dbus-runtime
ifneq ($(LTO),)
$(package)_config_opts_linux += -ltcg
endif
$(package)_config_opts_linux += -platform linux-g++ -xplatform bitcoin-linux-g++
ifneq (,$(findstring -stdlib=libc++,$($(1)_cxx)))
$(package)_config_opts_x86_64_linux = -xplatform linux-clang-libc++
ifneq (,$(findstring clang,$($(package)_cxx)))
ifneq (,$(findstring -stdlib=libc++,$($(package)_cxx)))
$(package)_config_opts_linux += -platform linux-clang-libc++ -xplatform linux-clang-libc++
else
$(package)_config_opts_linux += -platform linux-clang -xplatform linux-clang
endif
else
$(package)_config_opts_linux += -platform linux-g++ -xplatform bitcoin-linux-g++
endif
$(package)_config_opts_mingw32 = -no-opengl

View File

@ -398,6 +398,7 @@ BITCOIN_CORE_H = \
wallet/ismine.h \
wallet/load.h \
wallet/rpcwallet.h \
wallet/rpc/util.h \
wallet/salvage.h \
wallet/scriptpubkeyman.h \
wallet/sqlite.h \
@ -586,8 +587,8 @@ libbitcoin_wallet_a_SOURCES = \
wallet/hdchain.cpp \
wallet/interfaces.cpp \
wallet/load.cpp \
wallet/rpc/util.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/scriptpubkeyman.cpp \
wallet/wallet.cpp \
wallet/walletdb.cpp \

View File

@ -6,6 +6,7 @@
#include <interfaces/chain.h>
#include <node/context.h>
#include <wallet/coinselection.h>
#include <wallet/spend.h>
#include <wallet/wallet.h>
#include <set>
@ -17,7 +18,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<st
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
tx.vout.resize(1);
tx.vout[0].nValue = nValue;
wtxs.push_back(std::make_unique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx))));
wtxs.push_back(std::make_unique<CWalletTx>(MakeTransactionRef(std::move(tx))));
}
// Simple benchmark for wallet coin selection. Note that it maybe be necessary
@ -45,7 +46,7 @@ static void CoinSelection(benchmark::Bench& bench)
// Create coins
std::vector<COutput> coins;
for (const auto& wtx : wtxs) {
coins.emplace_back(wtx.get(), 0 /* iIn */, 6 * 24 /* nDepthIn */, true /* spendable */, true /* solvable */, true /* safe */);
coins.emplace_back(wallet, *wtx, 0 /* iIn */, 6 * 24 /* nDepthIn */, true /* spendable */, true /* solvable */, true /* safe */);
}
const CoinEligibilityFilter filter_standard(1, 6, 0);
const CoinSelectionParams coin_selection_params(/* use_bnb= */ true, /* change_output_size= */ 34,
@ -56,7 +57,7 @@ static void CoinSelection(benchmark::Bench& bench)
std::set<CInputCoin> setCoinsRet;
CAmount nValueRet;
bool bnb_used;
bool success = wallet.SelectCoinsMinConf(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used);
bool success = AttemptSelection(wallet, 1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used);
assert(success);
assert(nValueRet == 1003 * COIN);
assert(setCoinsRet.size() == 2);

View File

@ -9,6 +9,7 @@
#include <test/util/setup_common.h>
#include <test/util/wallet.h>
#include <validationinterface.h>
#include <wallet/receive.h>
#include <wallet/wallet.h>
#include <optional>
@ -34,11 +35,11 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
}
SyncWithValidationInterfaceQueue();
auto bal = wallet.GetBalance(); // Cache
auto bal = GetBalance(wallet); // Cache
bench.minEpochIterations(epoch_iters).run([&] {
if (set_dirty) wallet.MarkDirty();
bal = wallet.GetBalance();
bal = GetBalance(wallet);
if (add_mine) assert(bal.m_mine_trusted > 0);
if (add_watchonly) assert(bal.m_watchonly_trusted > 0);
});

View File

@ -220,6 +220,16 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
tx.nLockTime = (unsigned int) newLocktime;
}
template <typename T>
static T TrimAndParse(const std::string& int_str, const std::string& err)
{
const auto parsed{ToIntegral<T>(TrimString(int_str))};
if (!parsed.has_value()) {
throw std::runtime_error(err + " '" + int_str + "'");
}
return parsed.value();
}
static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
{
std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
@ -245,8 +255,9 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
// extract the optional sequence number
uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL;
if (vStrInputParts.size() > 2)
nSequenceIn = std::stoul(vStrInputParts[2]);
if (vStrInputParts.size() > 2) {
nSequenceIn = TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid TX sequence id");
}
// append to transaction input list
CTxIn txin(txid, vout, CScript(), nSequenceIn);
@ -324,10 +335,10 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
// Extract REQUIRED
uint32_t required = stoul(vStrInputParts[1]);
const uint32_t required{TrimAndParse<uint32_t>(vStrInputParts.at(1), "invalid multisig required number")};
// Extract NUMKEYS
uint32_t numkeys = stoul(vStrInputParts[2]);
const uint32_t numkeys{TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid multisig total number")};
// Validate there are the correct number of pubkeys
if (vStrInputParts.size() < numkeys + 3)

View File

@ -11,11 +11,18 @@
#include <compat/compat.h>
#include <logging.h>
#include <util/strencodings.h>
#include <clientversion.h>
#include <key.h>
#include <pubkey.h>
#include <tinyformat.h>
#include <util/system.h>
#include <util/translation.h>
#include <util/url.h>
#include <wallet/wallettool.h>
#include <exception>
#include <string>
#include <tuple>
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
UrlDecodeFn* const URL_DECODE = nullptr;

View File

@ -314,8 +314,8 @@ void CRollingBloomFilter::insert(Span<const unsigned char> vKey)
/* FastMod works with the upper bits of h, so it is safe to ignore that the lower bits of h are already used for bit. */
uint32_t pos = FastRange32(h, data.size());
/* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;
data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;
data[pos & ~1U] = (data[pos & ~1U] & ~(uint64_t{1} << bit)) | (uint64_t(nGeneration & 1)) << bit;
data[pos | 1] = (data[pos | 1] & ~(uint64_t{1} << bit)) | (uint64_t(nGeneration >> 1)) << bit;
}
}
@ -326,7 +326,7 @@ bool CRollingBloomFilter::contains(Span<const unsigned char> vKey) const
int bit = h & 0x3F;
uint32_t pos = FastRange32(h, data.size());
/* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {
if (!(((data[pos & ~1U] | data[pos | 1]) >> bit) & 1)) {
return false;
}
}

View File

@ -44,6 +44,7 @@
#endif // ENABLE_WALLET
#include <boost/signals2/connection.hpp>
#include <chrono>
#include <memory>
#include <QApplication>
@ -397,10 +398,10 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead
connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
window->message(title, message, style);
});
QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
QTimer::singleShot(100ms, paymentServer, &PaymentServer::uiReady);
}
#endif
pollShutdownTimer->start(200);
pollShutdownTimer->start(SHUTDOWN_POLLING_DELAY);
} else {
Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown
quit(); // Exit first main loop invocation

View File

@ -21,6 +21,7 @@
#include <netbase.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <util/time.h>
#include <validation.h>
#include <stdint.h>
@ -323,7 +324,7 @@ static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_
const bool throttle = (sync_state != SynchronizationState::POST_INIT && !fHeader) || sync_state == SynchronizationState::INIT_REINDEX;
const int64_t now = throttle ? GetTimeMillis() : 0;
int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
if (throttle && now < nLastUpdateNotification + count_milliseconds(MODEL_UPDATE_DELAY)) {
return;
}

View File

@ -6,10 +6,16 @@
#ifndef BITCOIN_QT_GUICONSTANTS_H
#define BITCOIN_QT_GUICONSTANTS_H
#include <chrono>
#include <cstdint>
/* Milliseconds between model updates */
static const int MODEL_UPDATE_DELAY = 250;
using namespace std::chrono_literals;
/* A delay between model updates */
static constexpr auto MODEL_UPDATE_DELAY{250ms};
/* A delay between shutdown pollings */
static constexpr auto SHUTDOWN_POLLING_DELAY{200ms};
/* AskPassphraseDialog -- Maximum passphrase length */
static const int MAX_PASSPHRASE_SIZE = 1024;

View File

@ -24,6 +24,8 @@
#include <util/underlying.h>
#include <QButtonGroup>
#include <chrono>
#include <QDataWidgetMapper>
#include <QDir>
#include <QIntValidator>
@ -457,7 +459,7 @@ void OptionsDialog::showRestartWarning(bool fPersistent)
ui->statusLabel->setText(tr("This change would require a client restart."));
// clear non-persistent status label after 10 seconds
// Todo: should perhaps be a class attribute, if we extend the use of statusLabel
QTimer::singleShot(10000, this, &OptionsDialog::clearStatusLabel);
QTimer::singleShot(10s, this, &OptionsDialog::clearStatusLabel);
}
}

View File

@ -24,10 +24,11 @@
#include <node/interface_ui.h>
#include <policy/fees.h>
#include <txmempool.h>
#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/fees.h>
#include <wallet/wallet.h>
#include <validation.h>
#include <chrono>
#include <array>
#include <fstream>
@ -1080,7 +1081,7 @@ SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QStri
int SendConfirmationDialog::exec()
{
updateYesButton();
countDownTimer.start(1000);
countDownTimer.start(1s);
return QMessageBox::exec();
}

View File

@ -19,6 +19,8 @@
#include <wallet/wallet.h>
#include <walletinitinterface.h>
#include <chrono>
#include <QApplication>
#include <QTimer>
#include <QMessageBox>
@ -39,7 +41,7 @@ void EditAddressAndSubmit(
dialog->findChild<QLineEdit*>("labelEdit")->setText(label);
dialog->findChild<QValidatedLineEdit*>("addressEdit")->setText(address);
ConfirmMessage(&warning_text, 5);
ConfirmMessage(&warning_text, 5ms);
dialog->accept();
QCOMPARE(warning_text, expected_msg);
}

View File

@ -2,6 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chrono>
#include <QApplication>
#include <QMessageBox>
#include <QPushButton>
@ -9,7 +11,7 @@
#include <QTimer>
#include <QWidget>
void ConfirmMessage(QString* text, int msec)
void ConfirmMessage(QString* text, std::chrono::milliseconds msec)
{
QTimer::singleShot(msec, [text]() {
for (QWidget* widget : QApplication::topLevelWidgets()) {

View File

@ -5,7 +5,11 @@
#ifndef BITCOIN_QT_TEST_UTIL_H
#define BITCOIN_QT_TEST_UTIL_H
#include <QString>
#include <chrono>
QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE
/**
* Press "Ok" button in message box dialog.
@ -13,6 +17,6 @@
* @param text - Optionally store dialog text.
* @param msec - Number of milliseconds to pause before triggering the callback.
*/
void ConfirmMessage(QString* text = nullptr, int msec = 0);
void ConfirmMessage(QString* text, std::chrono::milliseconds msec);
#endif // BITCOIN_QT_TEST_UTIL_H

View File

@ -25,6 +25,7 @@
#include <qt/recentrequeststablemodel.h>
#include <qt/receiverequestdialog.h>
#include <chrono>
#include <memory>
#include <QAbstractButton>

View File

@ -23,6 +23,7 @@
#include <optional>
#include <QCalendarWidget>
#include <chrono>
#include <QComboBox>
#include <QDateTimeEdit>
#include <QDesktopServices>
@ -114,8 +115,8 @@ TransactionView::TransactionView(QWidget* parent) :
amountWidget->setObjectName("amountWidget");
hlayout->addWidget(amountWidget);
// Delay before filtering transactions in ms
static const int input_filter_delay = 200;
// Delay before filtering transactions
static constexpr auto input_filter_delay{200ms};
QTimer* amount_typing_delay = new QTimer(this);
amount_typing_delay->setSingleShot(true);

View File

@ -21,6 +21,7 @@
#include <wallet/wallet.h>
#include <algorithm>
#include <chrono>
#include <QApplication>
#include <QMessageBox>
@ -271,12 +272,12 @@ void CreateWalletActivity::createWallet()
flags |= WALLET_FLAG_DESCRIPTORS;
}
QTimer::singleShot(500, worker(), [this, name, flags] {
QTimer::singleShot(500ms, worker(), [this, name, flags] {
std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message);
if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
QTimer::singleShot(500, this, &CreateWalletActivity::finish);
QTimer::singleShot(500ms, this, &CreateWalletActivity::finish);
});
}

View File

@ -874,29 +874,30 @@ static RPCHelpMan decoderawtransaction()
static RPCHelpMan decodescript()
{
return RPCHelpMan{"decodescript",
"\nDecode a hex-encoded script.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
return RPCHelpMan{
"decodescript",
"\nDecode a hex-encoded script.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "asm", "Script public key"},
{RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"},
{RPCResult::Type::STR, "address", /* optional */ true, "Dash address (only if a well-defined address exists)"},
{RPCResult::Type::NUM, "reqSigs", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures"},
{RPCResult::Type::ARR, "addresses", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of Dash addresses",
{
{RPCResult::Type::STR, "asm", "Script public key"},
{RPCResult::Type::STR, "type", "The output type (e.g. "+GetAllOutputTypes()+")"},
{RPCResult::Type::STR, "address", /* optional */ true, "Dash address (only if a well-defined address exists)"},
{RPCResult::Type::NUM, "reqSigs", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures"},
{RPCResult::Type::ARR, "addresses", /* optional */ true, "(DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of Dash addresses",
{
{RPCResult::Type::STR, "address", "Dash address"},
}},
{RPCResult::Type::STR, "p2sh", "address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH)"},
}
},
RPCExamples{
HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
},
{RPCResult::Type::STR, "address", "Dash address"},
}},
{RPCResult::Type::STR, "p2sh", "address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH)"},
},
},
RPCExamples{
HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
RPCTypeCheck(request.params, {UniValue::VSTR});
@ -911,11 +912,10 @@ static RPCHelpMan decodescript()
}
ScriptPubKeyToUniv(script, r, /* fIncludeHex */ false);
UniValue type;
std::vector<std::vector<unsigned char>> solutions_data;
const TxoutType which_type{Solver(script, solutions_data)};
type = find_value(r, "type");
if (type.isStr() && type.get_str() != "scripthash") {
if (which_type != TxoutType::SCRIPTHASH) {
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
// don't return the address for a P2SH of the P2SH.
r.pushKV("p2sh", EncodeDestination(ScriptHash(script)));

View File

@ -461,7 +461,7 @@ ssize_t FuzzedFileProvider::write(void* cookie, const char* buf, size_t size)
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
return 0;
}
fuzzed_file->m_offset += n;
return n;

View File

@ -25,7 +25,9 @@
#include <wallet/fees.h>
#include <wallet/ismine.h>
#include <wallet/load.h>
#include <wallet/receive.h>
#include <wallet/rpcwallet.h>
#include <wallet/spend.h>
#include <wallet/wallet.h>
#include <memory>
@ -76,9 +78,9 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
fOutputDenomFound = true;
}
}
result.credit = wtx.GetCredit(ISMINE_ALL);
result.debit = wtx.GetDebit(ISMINE_ALL);
result.change = wtx.GetChange();
result.credit = CachedTxGetCredit(wallet, wtx, ISMINE_ALL);
result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL);
result.change = CachedTxGetChange(wallet, wtx);
result.time = wtx.GetTxTime();
result.value_map = wtx.mapValue;
result.is_coinbase = wtx.IsCoinBase();
@ -96,15 +98,15 @@ WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
{
WalletTxStatus result;
result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height : std::numeric_limits<int>::max();
result.blocks_to_maturity = wtx.GetBlocksToMaturity();
result.depth_in_main_chain = wtx.GetDepthInMainChain();
result.blocks_to_maturity = wallet.GetTxBlocksToMaturity(wtx);
result.depth_in_main_chain = wallet.GetTxDepthInMainChain(wtx);
result.time_received = wtx.nTimeReceived;
result.lock_time = wtx.tx->nLockTime;
result.is_final = wallet.chain().checkFinalTx(*wtx.tx);
result.is_trusted = wtx.IsTrusted();
result.is_trusted = CachedTxIsTrusted(wallet, wtx);
result.is_abandoned = wtx.isAbandoned();
result.is_coinbase = wtx.IsCoinBase();
result.is_in_main_chain = wtx.IsInMainChain();
result.is_in_main_chain = wallet.IsTxInMainChain(wtx);
result.is_chainlocked = wtx.IsChainLocked();
result.is_islocked = wtx.IsLockedByInstantSend();
return result;
@ -274,7 +276,7 @@ public:
ReserveDestination m_dest(m_wallet.get());
CTransactionRef tx;
FeeCalculation fee_calc_out;
if (!m_wallet->CreateTransaction(recipients, tx, fee, change_pos,
if (!CreateTransaction(*m_wallet, recipients, tx, fee, change_pos,
fail_reason, coin_control, fee_calc_out, sign)) {
return {};
}
@ -378,7 +380,7 @@ public:
}
WalletBalances getBalances() override
{
const auto bal = m_wallet->GetBalance();
const auto bal = GetBalance(*m_wallet);
WalletBalances result;
result.balance = bal.m_mine_trusted;
result.unconfirmed_balance = bal.m_mine_untrusted_pending;
@ -404,7 +406,7 @@ public:
}
CAmount getBalance() override
{
return m_wallet->GetBalance().m_mine_trusted;
return GetBalance(*m_wallet).m_mine_trusted;
}
CAmount getAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfirmed) override
{
@ -436,13 +438,13 @@ public:
if (coin_control.IsUsingCoinJoin()) {
return m_wallet->GetBalance(0, coin_control.m_avoid_address_reuse, false, &coin_control).m_anonymized;
} else {
return m_wallet->GetAvailableBalance(&coin_control);
return GetAvailableBalance(*m_wallet, &coin_control);
}
}
isminetype txinIsMine(const CTxIn& txin) override
{
LOCK(m_wallet->cs_wallet);
return m_wallet->IsMine(txin);
return InputIsMine(*m_wallet, txin);
}
isminetype txoutIsMine(const CTxOut& txout) override
{
@ -457,13 +459,13 @@ public:
CAmount getCredit(const CTxOut& txout, isminefilter filter) override
{
LOCK(m_wallet->cs_wallet);
return m_wallet->GetCredit(txout, filter);
return OutputGetCredit(*m_wallet, txout, filter);
}
CoinsList listCoins() override
{
LOCK(m_wallet->cs_wallet);
CoinsList result;
for (const auto& entry : m_wallet->ListCoins()) {
for (const auto& entry : ListCoins(*m_wallet)) {
auto& group = result[entry.first];
for (const auto& coin : entry.second) {
group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i),
@ -481,7 +483,7 @@ public:
result.emplace_back();
auto it = m_wallet->mapWallet.find(output.hash);
if (it != m_wallet->mapWallet.end()) {
int depth = it->second.GetDepthInMainChain();
int depth = m_wallet->GetTxDepthInMainChain(it->second);
if (depth >= 0) {
result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth);
}

View File

@ -14,6 +14,7 @@
#include <util/string.h>
#include <util/system.h>
#include <util/translation.h>
#include <wallet/spend.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>

122
src/wallet/rpc/util.cpp Normal file
View File

@ -0,0 +1,122 @@
// Copyright (c) 2011-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <wallet/rpc/util.h>
#include <rpc/util.h>
#include <util/url.h>
#include <wallet/context.h>
#include <wallet/wallet.h>
#include <univalue.h>
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
if (avoid_reuse && !can_avoid_reuse) {
throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
}
return avoid_reuse;
}
/** Used by RPC commands that have an include_watchonly parameter.
* We default to true for watchonly wallets if include_watchonly isn't
* explicitly set.
*/
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
{
if (include_watchonly.isNull()) {
// if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
}
// otherwise return whatever include_watchonly was set to
return include_watchonly.get_bool();
}
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
return true;
}
return false;
}
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
WalletContext& context = EnsureWalletContext(request.context);
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
const std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}
std::vector<std::shared_ptr<CWallet>> wallets = GetWallets(context);
if (wallets.size() == 1) {
return wallets[0];
}
if (wallets.empty()) {
throw JSONRPCError(
RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
}
throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}
void EnsureWalletIsUnlocked(const CWallet& wallet)
{
if (wallet.IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
}
}
WalletContext& EnsureWalletContext(const std::any& context)
{
auto wallet_context = util::AnyPtr<WalletContext>(context);
if (!wallet_context) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
}
return *wallet_context;
}
// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
{
LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man && also_create) {
spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
}
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}
const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet)
{
const LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}
std::string LabelFromValue(const UniValue& value)
{
std::string label = value.get_str();
if (label == "*")
throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
return label;
}

38
src/wallet/rpc/util.h Normal file
View File

@ -0,0 +1,38 @@
// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_WALLET_RPC_UTIL_H
#define BITCOIN_WALLET_RPC_UTIL_H
#include <any>
#include <memory>
#include <string>
class CWallet;
class JSONRPCRequest;
class LegacyScriptPubKeyMan;
class UniValue;
struct WalletContext;
extern const std::string HELP_REQUIRING_PASSPHRASE;
/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
*
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return nullptr if no wallet should be used, or a pointer to the CWallet
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name);
void EnsureWalletIsUnlocked(const CWallet&);
WalletContext& EnsureWalletContext(const std::any& context);
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);
const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wallet);
bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param);
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet);
std::string LabelFromValue(const UniValue& value);
#endif // BITCOIN_WALLET_RPC_UTIL_H

View File

@ -30,8 +30,11 @@
#include <wallet/coincontrol.h>
#include <wallet/context.h>
#include <wallet/load.h>
#include <wallet/receive.h>
#include <wallet/rpcwallet.h>
#include <wallet/scriptpubkeyman.h>
#include <wallet/rpc/util.h>
#include <wallet/spend.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
#include <wallet/walletutil.h>
@ -49,35 +52,6 @@
using interfaces::FoundBlock;
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
static inline bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
if (avoid_reuse && !can_avoid_reuse) {
throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
}
return avoid_reuse;
}
/** Used by RPC commands that have an include_watchonly parameter.
* We default to true for watchonly wallets if include_watchonly isn't
* explicitly set.
*/
static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
{
if (include_watchonly.isNull()) {
// if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
}
// otherwise return whatever include_watchonly was set to
return include_watchonly.get_bool();
}
/** Checks if a CKey is in the given CWallet compressed or otherwise*/
bool HaveKey(const SigningProvider& wallet, const CKey& key)
@ -87,72 +61,11 @@ bool HaveKey(const SigningProvider& wallet, const CKey& key)
return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
}
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
return true;
}
return false;
}
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}
std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
if (wallets.size() == 1) {
return wallets[0];
}
if (wallets.empty()) {
throw JSONRPCError(
RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
}
throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}
void EnsureWalletIsUnlocked(const CWallet& wallet)
{
if (wallet.IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
}
}
// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
{
LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
if (!spk_man && also_create) {
spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
}
if (!spk_man) {
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
return *spk_man;
}
WalletContext& EnsureWalletContext(const CoreContext& context)
{
auto* wallet_context = GetContext<WalletContext>(context);
if (!wallet_context) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
}
return *wallet_context;
}
static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniValue& entry)
static void WalletTxToJSON(const JSONRPCRequest& request, interfaces::Chain& chain, const CWalletTx& wtx, UniValue& entry)
{
int confirms = wtx.GetDepthInMainChain();
interfaces::Chain& chain = wallet.chain();
int confirms = wallet.GetTxDepthInMainChain(wtx);
bool fLocked = chain.isInstantSendLockedTx(wtx.GetHash());
bool chainlock = false;
if (confirms > 0) {
@ -175,12 +88,12 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa
CHECK_NONFATAL(chain.findBlock(wtx.m_confirm.hashBlock, FoundBlock().time(block_time)));
entry.pushKV("blocktime", block_time);
} else {
entry.pushKV("trusted", wtx.IsTrusted());
entry.pushKV("trusted", CachedTxIsTrusted(wallet, wtx));
}
uint256 hash = wtx.GetHash();
entry.pushKV("txid", hash.GetHex());
UniValue conflicts(UniValue::VARR);
for (const uint256& conflict : wtx.GetConflicts())
for (const uint256& conflict : wallet.GetTxConflicts(wtx))
conflicts.push_back(conflict.GetHex());
entry.pushKV("walletconflicts", conflicts);
entry.pushKV("time", wtx.GetTxTime());
@ -191,14 +104,6 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa
}
static std::string LabelFromValue(const UniValue& value)
{
std::string label = value.get_str();
if (label == "*")
throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
return label;
}
/**
* Update coin control with fee estimation based on the given parameters
*
@ -399,7 +304,7 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
bilingual_str error;
CTransactionRef tx;
FeeCalculation fee_calc_out;
const bool fCreated = wallet.CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true);
const bool fCreated = CreateTransaction(wallet, recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true);
if (!fCreated) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
}
@ -571,8 +476,8 @@ static RPCHelpMan listaddressgroupings()
LOCK(pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR);
std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
std::map<CTxDestination, CAmount> balances = GetAddressBalances(*pwallet);
for (const std::set<CTxDestination>& grouping : GetAddressGroupings(*pwallet)) {
UniValue jsonGrouping(UniValue::VARR);
for (const CTxDestination& address : grouping)
{
@ -729,7 +634,7 @@ static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool b
if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx)) {
continue;
}
if (wtx.GetDepthInMainChain() < min_depth && !(fAddLocked && wtx.IsLockedByInstantSend())) continue;
if (wallet.GetTxDepthInMainChain(wtx) < min_depth && !(fAddLocked && wtx.IsLockedByInstantSend())) continue;
for (const CTxOut& txout : wtx.tx->vout) {
CTxDestination address;
@ -875,7 +780,7 @@ static RPCHelpMan getbalance()
bool include_watchonly = ParseIncludeWatchonly(request.params[3], *pwallet);
bool avoid_reuse = GetAvoidReuseFlag(*pwallet, request.params[4]);
const auto bal = pwallet->GetBalance(min_depth, avoid_reuse, fAddLocked);
const auto bal = GetBalance(*pwallet, min_depth, avoid_reuse, fAddLocked);
return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
},
@ -900,7 +805,7 @@ static RPCHelpMan getunconfirmedbalance()
LOCK(pwallet->cs_wallet);
return ValueFromAmount(pwallet->GetBalance().m_mine_untrusted_pending);
return ValueFromAmount(GetBalance(*pwallet).m_mine_untrusted_pending);
},
};
}
@ -1126,7 +1031,7 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, bool
if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx))
continue;
int nDepth = wtx.GetDepthInMainChain();
int nDepth = wallet.GetTxDepthInMainChain(wtx);
if ((nDepth < nMinDepth) && !(fAddLocked && wtx.IsLockedByInstantSend()))
continue;
@ -1359,9 +1264,9 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
std::list<COutputEntry> listReceived;
std::list<COutputEntry> listSent;
wtx.GetAmounts(listReceived, listSent, nFee, filter_ismine);
CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, filter_ismine);
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
bool involvesWatchonly = CachedTxIsFromMe(wallet, wtx, ISMINE_WATCH_ONLY);
// Sent
if (!filter_label)
@ -1383,14 +1288,14 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
entry.pushKV("vout", s.vout);
entry.pushKV("fee", ValueFromAmount(-nFee));
if (fLong)
WalletTxToJSON(wallet.chain(), wtx, entry);
WalletTxToJSON(wallet, wtx, entry);
entry.pushKV("abandoned", wtx.isAbandoned());
ret.push_back(entry);
}
}
// Received
if (listReceived.size() > 0 && ((wtx.GetDepthInMainChain() >= nMinDepth) || wtx.IsLockedByInstantSend()))
if (listReceived.size() > 0 && ((wallet.GetTxDepthInMainChain(wtx) >= nMinDepth) || wtx.IsLockedByInstantSend()))
{
for (const COutputEntry& r : listReceived)
{
@ -1409,9 +1314,9 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
MaybePushAddress(entry, r.destination);
if (wtx.IsCoinBase())
{
if (wtx.GetDepthInMainChain() < 1)
if (wallet.GetTxDepthInMainChain(wtx) < 1)
entry.pushKV("category", "orphan");
else if (wtx.IsImmatureCoinBase())
else if (wallet.IsTxImmatureCoinBase(wtx))
entry.pushKV("category", "immature");
else
entry.pushKV("category", "generate");
@ -1430,7 +1335,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
}
entry.pushKV("vout", r.vout);
if (fLong)
WalletTxToJSON(wallet.chain(), wtx, entry);
WalletTxToJSON(wallet, wtx, entry);
ret.push_back(entry);
}
}
@ -1673,7 +1578,7 @@ static RPCHelpMan listsinceblock()
for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) {
const CWalletTx& tx = pairWtx.second;
if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {
ListTransactions(wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
}
}
@ -1793,16 +1698,16 @@ static RPCHelpMan gettransaction()
}
const CWalletTx& wtx = it->second;
CAmount nCredit = wtx.GetCredit(filter);
CAmount nDebit = wtx.GetDebit(filter);
CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, filter);
CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, filter);
CAmount nNet = nCredit - nDebit;
CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
CAmount nFee = (CachedTxIsFromMe(*pwallet, wtx, filter) ? wtx.tx->GetValueOut() - nDebit : 0);
entry.pushKV("amount", ValueFromAmount(nNet - nFee));
if (wtx.IsFromMe(filter))
if (CachedTxIsFromMe(*pwallet, wtx, filter))
entry.pushKV("fee", ValueFromAmount(nFee));
WalletTxToJSON(pwallet->chain(), wtx, entry);
WalletTxToJSON(*pwallet, wtx, entry);
UniValue details(UniValue::VARR);
ListTransactions(*pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
@ -2517,7 +2422,7 @@ static RPCHelpMan getbalances()
LOCK(wallet.cs_wallet);
const auto bal = wallet.GetBalance();
const auto bal = GetBalance(wallet);
UniValue balances{UniValue::VOBJ};
{
UniValue balances_mine{UniValue::VOBJ};
@ -2527,7 +2432,7 @@ static RPCHelpMan getbalances()
if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
// If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
// the total balance, and then subtract bal to get the reused address balance.
const auto full_bal = wallet.GetBalance(0, false);
const auto full_bal = GetBalance(wallet, 0, false);
balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
}
balances_mine.pushKV("coinjoin", ValueFromAmount(bal.m_anonymized));
@ -2610,7 +2515,7 @@ static RPCHelpMan getwalletinfo()
bool fHDEnabled = spk_man && spk_man->GetHDChain(hdChainCurrent);
UniValue obj(UniValue::VOBJ);
const auto bal = pwallet->GetBalance();
const auto bal = GetBalance(*pwallet);
int64_t kp_oldest = pwallet->GetOldestKeyPoolTime();
obj.pushKV("walletname", pwallet->GetName());
obj.pushKV("walletversion", pwallet->GetVersion());
@ -3326,7 +3231,7 @@ static RPCHelpMan listunspent()
coinControl.m_include_unsafe_inputs = include_unsafe;
LOCK(pwallet->cs_wallet);
pwallet->AvailableCoins(vecOutputs, &coinControl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount);
AvailableCoins(*pwallet, vecOutputs, &coinControl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount);
}
LOCK(pwallet->cs_wallet);
@ -3505,7 +3410,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
bilingual_str error;
if (!wallet.FundTransaction(tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
if (!FundTransaction(wallet, tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
throw JSONRPCError(RPC_WALLET_ERROR, error.original);
}
}
@ -4019,7 +3924,7 @@ RPCHelpMan getaddressinfo()
UniValue detail = DescribeWalletAddress(*pwallet, dest);
ret.pushKVs(detail);
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
ret.pushKV("ischange", ScriptIsChange(*pwallet, scriptPubKey));
ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
if (spk_man) {

View File

@ -8,35 +8,10 @@
#include <context.h>
#include <span.h>
#include <memory>
#include <string>
#include <vector>
class CRPCCommand;
class CWallet;
class JSONRPCRequest;
class LegacyScriptPubKeyMan;
class UniValue;
class CTransaction;
struct PartiallySignedTransaction;
struct WalletContext;
static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
Span<const CRPCCommand> GetWalletRPCCommands();
/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
*
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return nullptr if no wallet should be used, or a pointer to the CWallet
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
void EnsureWalletIsUnlocked(const CWallet&);
WalletContext& EnsureWalletContext(const CoreContext& context);
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);
RPCHelpMan getaddressinfo();
RPCHelpMan getrawchangeaddress();
RPCHelpMan addmultisigaddress();

View File

@ -12,6 +12,7 @@
#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/coinselection.h>
#include <wallet/spend.h>
#include <wallet/test/wallet_test_fixture.h>
#include <wallet/wallet.h>
@ -80,7 +81,7 @@ static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount
wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
wtx->m_is_cache_empty = false;
}
COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
COutput output(wallet, *wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
coins.push_back(output);
}
@ -255,7 +256,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 1 * CENT, 2 * CENT, selection, value_ret, not_input_fees));
}
// Make sure that effective value is working in SelectCoinsMinConf when BnB is used
// Make sure that effective value is working in AttemptSelection when BnB is used
CoinSelectionParams coin_selection_params_bnb(/* use_bnb= */ true, /* change_output_size= */ 0,
/* change_spend_size= */ 0, /* effective_feerate= */ CFeeRate(3000),
/* long_term_feerate= */ CFeeRate(1000), /* discard_feerate= */ CFeeRate(1000),
@ -273,14 +274,14 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(coins, *wallet, 1);
coins.at(0).nInputBytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail
BOOST_CHECK(!wallet->SelectCoinsMinConf(1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used));
BOOST_CHECK(!wallet->AttemptSelection(1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used));
// Test fees subtracted from output:
coins.clear();
add_coin(coins, *wallet, 1 * CENT);
coins.at(0).nInputBytes = 40;
coin_selection_params_bnb.m_subtract_fee_outputs = true;
BOOST_CHECK(wallet->SelectCoinsMinConf(1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
}
@ -302,7 +303,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_control.fAllowOtherInputs = true;
coin_control.Select(COutPoint(coins.at(0).tx->GetHash(), coins.at(0).i));
coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
BOOST_CHECK(wallet->SelectCoins(coins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb, bnb_used));
BOOST_CHECK(SelectCoins(*wallet, coins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb, bnb_used));
BOOST_CHECK(bnb_used);
BOOST_CHECK(coin_selection_params_bnb.use_bnb);
}
@ -326,24 +327,24 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
coins.clear();
// with an empty wallet we can't even pay one cent
BOOST_CHECK(!wallet->SelectCoinsMinConf( 1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!wallet->AttemptSelection( 1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
add_coin(coins, *wallet, 1*CENT, 4); // add a new 1 cent coin
// with a new 1 cent coin, we still can't find a mature 1 cent
BOOST_CHECK(!wallet->SelectCoinsMinConf( 1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!wallet->AttemptSelection( 1 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// but we can find a new 1 cent
BOOST_CHECK(wallet->SelectCoinsMinConf( 1 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection( 1 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
add_coin(coins, *wallet, 2*CENT); // add a mature 2 cent coin
// we can't make 3 cents of mature coins
BOOST_CHECK(!wallet->SelectCoinsMinConf( 3 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!wallet->AttemptSelection( 3 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// we can make 3 cents of new coins
BOOST_CHECK(wallet->SelectCoinsMinConf( 3 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection( 3 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);
add_coin(coins, *wallet, 5*CENT); // add a mature 5 cent coin,
@ -353,33 +354,33 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
// we can't make 38 cents only if we disallow new coins:
BOOST_CHECK(!wallet->SelectCoinsMinConf(38 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!wallet->AttemptSelection(38 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// we can't even make 37 cents if we don't allow new coins even if they're from us
BOOST_CHECK(!wallet->SelectCoinsMinConf(38 * CENT, filter_standard_extra, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!wallet->AttemptSelection(38 * CENT, filter_standard_extra, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// but we can make 37 cents if we accept new coins from ourself
BOOST_CHECK(wallet->SelectCoinsMinConf(37 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(37 * CENT, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);
// and we can make 38 cents if we accept all new coins
BOOST_CHECK(wallet->SelectCoinsMinConf(38 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(38 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
BOOST_CHECK(wallet->SelectCoinsMinConf(34 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(34 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
BOOST_CHECK(wallet->SelectCoinsMinConf( 7 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection( 7 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
BOOST_CHECK(wallet->SelectCoinsMinConf( 8 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection( 8 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(nValueRet == 8 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
BOOST_CHECK(wallet->SelectCoinsMinConf( 9 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection( 9 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@ -393,30 +394,30 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, 30*CENT); // now we have 6+7+8+20+30 = 71 cents total
// check that we have 71 and not 72
BOOST_CHECK(wallet->SelectCoinsMinConf(71 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!wallet->SelectCoinsMinConf(72 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(71 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!wallet->AttemptSelection(72 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
BOOST_CHECK(wallet->SelectCoinsMinConf(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
add_coin(coins, *wallet, 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
BOOST_CHECK(wallet->SelectCoinsMinConf(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
add_coin(coins, *wallet, 18*CENT); // now we have 5+6+7+8+18+20+30
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
BOOST_CHECK(wallet->SelectCoinsMinConf(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(16 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins
// now try making 11 cents. we should get 5+6
BOOST_CHECK(wallet->SelectCoinsMinConf(11 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(11 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
@ -425,11 +426,11 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, 2*COIN);
add_coin(coins, *wallet, 3*COIN);
add_coin(coins, *wallet, 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
BOOST_CHECK(wallet->SelectCoinsMinConf(95 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(95 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
BOOST_CHECK(wallet->SelectCoinsMinConf(195 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(195 * CENT, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@ -444,14 +445,14 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
// we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly
BOOST_CHECK(wallet->SelectCoinsMinConf(MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE);
// but if we add a bigger coin, small change is avoided
add_coin(coins, *wallet, 1111*MIN_CHANGE);
// try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
BOOST_CHECK(wallet->SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// if we add more small coins:
@ -459,7 +460,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, MIN_CHANGE * 7 / 10);
// and try again to make 1.0 * MIN_CHANGE
BOOST_CHECK(wallet->SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// run the 'mtgox' test (see https://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
@ -468,7 +469,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
for (int j = 0; j < 20; j++)
add_coin(coins, *wallet, 50000 * COIN);
BOOST_CHECK(wallet->SelectCoinsMinConf(500000 * COIN, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(500000 * COIN, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins
@ -481,7 +482,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, MIN_CHANGE * 6 / 10);
add_coin(coins, *wallet, MIN_CHANGE * 7 / 10);
add_coin(coins, *wallet, 1111 * MIN_CHANGE);
BOOST_CHECK(wallet->SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(1 * MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@ -491,7 +492,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, MIN_CHANGE * 6 / 10);
add_coin(coins, *wallet, MIN_CHANGE * 8 / 10);
add_coin(coins, *wallet, 1111 * MIN_CHANGE);
BOOST_CHECK(wallet->SelectCoinsMinConf(MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(MIN_CHANGE, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6
@ -502,12 +503,12 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
add_coin(coins, *wallet, MIN_CHANGE * 100);
// trying to make 100.01 from these three coins
BOOST_CHECK(wallet->SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(MIN_CHANGE * 10001 / 100, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
BOOST_CHECK(wallet->SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(MIN_CHANGE * 9990 / 100, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
}
@ -521,7 +522,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
for (int i = 0; i < RUN_TESTS; i++) {
BOOST_CHECK(wallet->SelectCoinsMinConf(2000, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(2000, filter_confirmed, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
if (amt - 2000 < MIN_CHANGE) {
// needs more than one input:
@ -547,8 +548,8 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
for (int i = 0; i < RUN_TESTS; i++) {
// picking 50 from 100 coins doesn't depend on the shuffle,
// but does depend on randomness in the stochastic approximation code
BOOST_CHECK(wallet->SelectCoinsMinConf(50 * COIN, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->SelectCoinsMinConf(50 * COIN, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(50 * COIN, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(50 * COIN, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0;
@ -556,8 +557,8 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
BOOST_CHECK(wallet->SelectCoinsMinConf(COIN, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->SelectCoinsMinConf(COIN, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(COIN, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(COIN, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
if (equal_sets(setCoinsRet, setCoinsRet2))
fails++;
}
@ -579,8 +580,8 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
BOOST_CHECK(wallet->SelectCoinsMinConf(90*CENT, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->SelectCoinsMinConf(90*CENT, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(90*CENT, filter_standard, coins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(90*CENT, filter_standard, coins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
if (equal_sets(setCoinsRet, setCoinsRet2))
fails++;
}
@ -606,7 +607,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
add_coin(coins, *wallet, 1000 * COIN);
add_coin(coins, *wallet, 3 * COIN);
BOOST_CHECK(wallet->SelectCoinsMinConf(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK(wallet->AttemptSelection(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
}
@ -656,8 +657,8 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
CoinSet out_set;
CAmount out_value = 0;
bool bnb_used = false;
BOOST_CHECK(wallet->SelectCoinsMinConf(target, filter_standard, coins, out_set, out_value, coin_selection_params_bnb, bnb_used) ||
wallet->SelectCoinsMinConf(target, filter_standard, coins, out_set, out_value, coin_selection_params_knapsack, bnb_used));
BOOST_CHECK(AttemptSelection(wallet, target, filter_standard, coins, out_set, out_value, coin_selection_params_bnb, bnb_used) ||
AttemptSelection(wallet, target, filter_standard, coins, out_set, out_value, coin_selection_params_knapsack, bnb_used));
BOOST_CHECK_GE(out_value, target);
}
}

View File

@ -23,12 +23,12 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx1;
s_prev_tx1 >> prev_tx1;
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx1));
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(prev_tx1));
CDataStream s_prev_tx2(ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx2;
s_prev_tx2 >> prev_tx2;
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(&m_wallet, prev_tx2));
m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(prev_tx2));
// Add scripts
CScript rs1;

View File

@ -25,8 +25,9 @@
#include <util/translation.h>
#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/receive.h>
#include <wallet/spend.h>
#include <wallet/test/wallet_test_fixture.h>
#include <boost/test/unit_test.hpp>
#include <univalue.h>
@ -123,7 +124,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK(result.last_failed_block.IsNull());
BOOST_CHECK(result.last_scanned_block.IsNull());
BOOST_CHECK(!result.last_scanned_height);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 0);
BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 0);
}
// Verify ScanForWalletTransactions picks up transactions in both the old
@ -142,7 +143,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK(result.last_failed_block.IsNull());
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 1000 * COIN);
BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 1000 * COIN);
}
// Prune the older block file.
@ -170,7 +171,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash());
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 500 * COIN);
BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 500 * COIN);
}
// Prune the remaining block file.
@ -196,7 +197,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash());
BOOST_CHECK(result.last_scanned_block.IsNull());
BOOST_CHECK(!result.last_scanned_height);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 0);
BOOST_CHECK_EQUAL(GetBalance(wallet).m_mine_immature, 0);
}
}
@ -412,7 +413,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
CWallet wallet(m_node.chain.get(), m_node.coinjoin_loader.get(), "", CreateDummyWalletDatabase());
auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
CWalletTx wtx(&wallet, m_coinbase_txns.back());
CWalletTx wtx(m_coinbase_txns.back());
LOCK2(wallet.cs_wallet, spk_man->cs_KeyStore);
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
@ -422,13 +423,13 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
// Call GetImmatureCredit() once before adding the key to the wallet to
// cache the current immature credit amount, which is 0.
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0);
BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 0);
// Invalidate the cached value, add the key, and make sure a new immature
// credit amount is calculated.
wtx.MarkDirty();
BOOST_CHECK(spk_man->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()));
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 500*COIN);
BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 500*COIN);
}
static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
@ -613,7 +614,7 @@ public:
bilingual_str error;
CCoinControl dummy;
FeeCalculation fee_calc_out;
BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, fee, changePos, error, dummy, fee_calc_out));
BOOST_CHECK(CreateTransaction(*wallet, {recipient}, tx, fee, changePos, error, dummy, fee_calc_out));
wallet->CommitTransaction(tx, {}, {});
CMutableTransaction blocktx;
{
@ -634,7 +635,7 @@ public:
std::unique_ptr<CWallet> wallet;
};
BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
{
std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString();
@ -643,14 +644,14 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
std::map<CTxDestination, std::vector<COutput>> list;
{
LOCK(wallet->cs_wallet);
list = wallet->ListCoins();
list = ListCoins(*wallet);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);
// Check initial balance from one mature coinbase transaction.
BOOST_CHECK_EQUAL(500 * COIN, wallet->GetAvailableBalance());
BOOST_CHECK_EQUAL(500 * COIN, GetAvailableBalance(*wallet));
// Add a transaction creating a change address, and confirm ListCoins still
// returns the coin associated with the change address underneath the
@ -659,7 +660,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});
{
LOCK(wallet->cs_wallet);
list = wallet->ListCoins();
list = ListCoins(*wallet);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
@ -669,7 +670,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
{
LOCK(wallet->cs_wallet);
std::vector<COutput> available;
wallet->AvailableCoins(available);
AvailableCoins(*wallet, available);
BOOST_CHECK_EQUAL(available.size(), 2U);
}
for (const auto& group : list) {
@ -681,14 +682,14 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
{
LOCK(wallet->cs_wallet);
std::vector<COutput> available;
wallet->AvailableCoins(available);
AvailableCoins(*wallet, available);
BOOST_CHECK_EQUAL(available.size(), 0U);
}
// Confirm ListCoins still returns same result as before, despite coins
// being locked.
{
LOCK(wallet->cs_wallet);
list = wallet->ListCoins();
list = ListCoins(*wallet);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);

View File

@ -617,7 +617,7 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
const uint256& wtxid = it->second;
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
if (mit != mapWallet.end()) {
int depth = mit->second.GetDepthInMainChain();
int depth = GetTxDepthInMainChain(mit->second);
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
return true; // Spent
}
@ -905,7 +905,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
}
// Inserts only if not already there, returns tx inserted or tx found
auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, tx));
auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx));
CWalletTx& wtx = (*ret.first).second;
bool fInsertedNew = ret.second;
bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
@ -1014,7 +1014,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx)
{
const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(this, nullptr));
const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(nullptr));
CWalletTx& wtx = ins.first->second;
if (!fill_wtx(wtx, ins.second)) {
return false;
@ -1112,7 +1112,7 @@ bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
{
LOCK(cs_wallet);
const CWalletTx* wtx = GetWalletTx(hashTx);
return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() == 0 && !wtx->InMempool();
return wtx && !wtx->isAbandoned() && GetTxDepthInMainChain(*wtx) == 0 && !wtx->InMempool();
}
bool CWallet::TransactionCanBeResent(const uint256& hashTx) const
@ -1145,7 +1145,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
auto it = mapWallet.find(hashTx);
assert(it != mapWallet.end());
const CWalletTx& origtx = it->second;
if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool() || origtx.IsLockedByInstantSend()) {
if (GetTxDepthInMainChain(origtx) != 0 || origtx.InMempool() || origtx.IsLockedByInstantSend()) {
return false;
}
@ -1158,7 +1158,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
auto it = mapWallet.find(now);
assert(it != mapWallet.end());
CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain();
int currentconfirm = GetTxDepthInMainChain(wtx);
// If the orig tx was not in block, none of its spends can be
assert(currentconfirm <= 0);
// if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
@ -1228,7 +1228,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
auto it = mapWallet.find(now);
assert(it != mapWallet.end());
CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain();
int currentconfirm = GetTxDepthInMainChain(wtx);
if (conflictconfirms < currentconfirm) {
// Block is 'more conflicted' than current confirm; update.
// Mark transaction as conflicted with this block.
@ -2141,7 +2141,7 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = item.second;
assert(wtx.GetHash() == wtxid);
int nDepth = wtx.GetDepthInMainChain();
int nDepth = GetTxDepthInMainChain(wtx);
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.IsLockedByInstantSend() && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
@ -2152,7 +2152,7 @@ void CWallet::ReacceptWalletTransactions()
for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
CWalletTx& wtx = *(item.second);
bilingual_str unused_err_string;
wtx.SubmitMemoryPoolAndRelay(unused_err_string, false);
SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, false);
}
}
@ -2177,7 +2177,7 @@ bool CWalletTx::SubmitMemoryPoolAndRelay(bilingual_str& err_string, bool relay)
if (!CanBeResent()) return false;
// Submit transaction to mempool for relay
pwallet->WalletLogPrintf("Submitting wtx %s to mempool for relay\n", GetHash().ToString());
WalletLogPrintf("Submitting wtx %s to mempool for relay\n", wtx.GetHash().ToString());
// We must set fInMempool here - while it will be re-set to true by the
// entered-mempool callback, if we did not there would be a race where a
// user could call sendmoney in a loop and hit spurious out of funds errors
@ -2187,19 +2187,18 @@ bool CWalletTx::SubmitMemoryPoolAndRelay(bilingual_str& err_string, bool relay)
// Irrespective of the failure reason, un-marking fInMempool
// out-of-order is incorrect - it should be unmarked when
// TransactionRemovedFromMempool fires.
bool ret = pwallet->chain().broadcastTransaction(tx, pwallet->m_default_max_tx_fee, relay, err_string);
fInMempool |= ret;
bool ret = chain().broadcastTransaction(wtx.tx, m_default_max_tx_fee, relay, err_string);
wtx.fInMempool |= ret;
return ret;
}
std::set<uint256> CWalletTx::GetConflicts() const
std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const
{
std::set<uint256> result;
if (pwallet != nullptr)
{
AssertLockHeld(pwallet->cs_wallet);
uint256 myHash = GetHash();
result = pwallet->GetConflicts(myHash);
uint256 myHash = wtx.GetHash();
result = GetConflicts(myHash);
result.erase(myHash);
}
return result;
@ -2485,11 +2484,11 @@ void CWallet::ResendWalletTransactions()
for (std::pair<const uint256, CWalletTx>& item : mapWallet) {
CWalletTx& wtx = item.second;
// Attempt to rebroadcast all txes more than 5 minutes older than
// the last block. SubmitMemoryPoolAndRelay() will not rebroadcast
// the last block. SubmitTxMemoryPoolAndRelay() will not rebroadcast
// any confirmed or conflicting txs.
if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
bilingual_str unused_err_string;
if (wtx.SubmitMemoryPoolAndRelay(unused_err_string, true)) ++submitted_tx_count;
if (SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, true)) ++submitted_tx_count;
}
} // cs_wallet
@ -2882,7 +2881,7 @@ static bool isGroupISLocked(const OutputGroup& group, interfaces::Chain& chain)
});
}
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins,
bool CWallet::AttemptSelection(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins,
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used, CoinType nCoinType) const
{
setCoinsRet.clear();
@ -3015,32 +3014,32 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
// If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
// confirmations on outputs received from other wallets and only spend confirmed change.
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 6, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
if (AttemptSelection(value_to_select, CoinEligibilityFilter(1, 6, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
if (AttemptSelection(value_to_select, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
// Fall back to using zero confirmation change (but with as few ancestors in the mempool as
// possible) if we cannot fund the transaction otherwise.
if (m_spend_zero_conf_change) {
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)),
if (AttemptSelection(value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) return true;
if (AttemptSelection(value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true;
}
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2),
if (AttemptSelection(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true;
}
// If partial groups are allowed, relax the requirement of spending OutputGroups (groups
// of UTXOs sent to the same address, which are obviously controlled by a single wallet)
// in their entirety.
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
if (AttemptSelection(value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true;
}
// Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
// received from other wallets.
if (coin_control.m_include_unsafe_inputs
&& SelectCoinsMinConf(value_to_select,
&& AttemptSelection(value_to_select,
CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true;
@ -3048,7 +3047,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
// Try with unlimited ancestors/descendants. The transaction will still need to meet
// mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but
// OutputGroups use heuristics that may overestimate ancestor/descendant counts.
if (!fRejectLongChains && SelectCoinsMinConf(value_to_select,
if (!fRejectLongChains && AttemptSelection(value_to_select,
CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true;
@ -3058,7 +3057,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
return false;
}();
// SelectCoinsMinConf clears setCoinsRet, so add the preset inputs from coin_control to the coinset
// AttemptSelection clears setCoinsRet, so add the preset inputs from coin_control to the coinset
util::insert(setCoinsRet, setPresetCoins);
// add preset inputs to the total value selected
@ -3995,7 +3994,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
}
bilingual_str err_string;
if (!wtx.SubmitMemoryPoolAndRelay(err_string, true)) {
if (!SubmitTxMemoryPoolAndRelay(wtx, err_string, true)) {
WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string.original);
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
}
@ -5451,13 +5450,12 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool fInternalIn)
fInternal = fInternalIn;
}
int CWalletTx::GetDepthInMainChain() const
int CWallet::GetTxDepthInMainChain(const CWalletTx& wtx) const
{
assert(pwallet != nullptr);
AssertLockHeld(pwallet->cs_wallet);
if (isUnconfirmed() || isAbandoned()) return 0;
AssertLockHeld(cs_wallet);
if (wtx.isUnconfirmed() || wtx.isAbandoned()) return 0;
return (pwallet->GetLastBlockHeight() - m_confirm.block_height + 1) * (isConflicted() ? -1 : 1);
return (GetLastBlockHeight() - wtx.m_confirm.block_height + 1) * (wtx.isConflicted() ? -1 : 1);
}
bool CWalletTx::IsLockedByInstantSend() const
@ -5484,19 +5482,19 @@ bool CWalletTx::IsChainLocked() const
return fIsChainlocked;
}
int CWalletTx::GetBlocksToMaturity() const
int CWallet::GetTxBlocksToMaturity(const CWalletTx& wtx) const
{
if (!IsCoinBase())
if (!wtx.IsCoinBase())
return 0;
int chain_depth = GetDepthInMainChain();
int chain_depth = GetTxDepthInMainChain(wtx);
assert(chain_depth >= 0); // coinbase tx should not be conflicted
return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
}
bool CWalletTx::IsImmatureCoinBase() const
bool CWallet::IsTxImmatureCoinBase(const CWalletTx& wtx) const
{
// note GetBlocksToMaturity is 0 for non-coinbase tx
return GetBlocksToMaturity() > 0;
return GetTxBlocksToMaturity(wtx) > 0;
}
std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outputs, bool separate_coins, const CFeeRate& effective_feerate, const CFeeRate& long_term_feerate, const CoinEligibilityFilter& filter, bool positive_only) const

View File

@ -541,7 +541,6 @@ public:
bool IsEquivalentTo(const CWalletTx& tx) const;
bool InMempool() const;
bool IsTrusted() const;
int64_t GetTxTime() const;
@ -858,8 +857,6 @@ private:
// ScriptPubKeyMan::GetID. In many cases it will be the hash of an internal structure
std::map<uint256, std::unique_ptr<ScriptPubKeyMan>> m_spk_managers;
bool CreateTransactionInternal(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, FeeCalculation& fee_calc_out, bool sign, int nExtraPayloadSize);
/**
* Catch wallet up to current chain, scanning new blocks, updating the best
* block locator and m_last_block_processed, and registering for
@ -880,17 +877,6 @@ public:
return *m_database;
}
/**
* Select a set of coins such that nValueRet >= nTargetValue and at least
* all coins from coin_control are selected; never select unconfirmed coins if they are not ours
* param@[out] setCoinsRet Populated with inputs including pre-selected inputs from
* coin_control and Coin Selection if successful.
* param@[out] nValueRet Total value of selected coins including pre-selected ones
* from coin_control and Coin Selection if successful.
*/
bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet,
const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Get a name for this wallet for logging/debugging purposes.
*/
const std::string& GetName() const { return m_name; }
@ -972,25 +958,37 @@ public:
bool coinjoin_available() { return m_coinjoin_loader != nullptr; }
const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool IsTrusted(const CWalletTx& wtx, std::set<uint256>& trusted_parents) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! check whether we support the named feature
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return IsFeatureSupported(nWalletVersion, wf); }
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
// "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
// resolve the issue of member access into incomplete type CWallet. Note
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
// in place.
std::set<uint256> GetTxConflicts(const CWalletTx& wtx) const NO_THREAD_SAFETY_ANALYSIS;
/**
* populate vCoins with vector of available COutputs.
* Return depth of transaction in blockchain:
* <0 : conflicts with a transaction this deep in the blockchain
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/
void AvailableCoins(std::vector<COutput>& vCoins, const CCoinControl* coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
// "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
// resolve the issue of member access into incomplete type CWallet. Note
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
// in place.
int GetTxDepthInMainChain(const CWalletTx& wtx) const NO_THREAD_SAFETY_ANALYSIS;
bool IsTxInMainChain(const CWalletTx& wtx) const { return GetTxDepthInMainChain(wtx) > 0; }
/**
* Return list of available coins and locked coins grouped by non-change output address.
* @return number of blocks to maturity for this transaction:
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
* >0 : is a coinbase transaction which matures in this many blocks
*/
std::map<CTxDestination, std::vector<COutput>> ListCoins() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Find non-change parent output.
*/
const CTxOut& FindNonChangeParentOutput(const CTransaction& tx, int output) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
int GetTxBlocksToMaturity(const CWalletTx& wtx) const;
bool IsTxImmatureCoinBase(const CWalletTx& wtx) const;
/**
* Shuffle and select coins until nTargetValue is reached while avoiding
@ -1003,7 +1001,7 @@ public:
* param@[out] setCoinsRet Populated with the coins selected if successful.
* param@[out] nValueRet Used to return the total value of selected coins.
*/
bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used, CoinType nCoinType = CoinType::ALL_COINS) const;
bool AttemptSelection(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used, CoinType nCoinType = CoinType::ALL_COINS) const;
// Coin selection
bool SelectTxDSInsByDenomination(int nDenom, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet);
@ -1030,8 +1028,6 @@ public:
bool IsSpentKey(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool separate_coins, const CFeeRate& effective_feerate, const CFeeRate& long_term_feerate, const CoinEligibilityFilter& filter, bool positive_only) const;
bool IsLockedCoin(uint256 hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void LockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void UnlockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@ -1115,31 +1111,12 @@ public:
void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void ResendWalletTransactions();
struct Balance {
CAmount m_mine_trusted{0}; //!< Trusted, at depth=GetBalance.min_depth or more
CAmount m_mine_untrusted_pending{0}; //!< Untrusted, but in mempool (pending)
CAmount m_mine_immature{0}; //!< Immature coinbases in the main chain
CAmount m_watchonly_trusted{0};
CAmount m_watchonly_untrusted_pending{0};
CAmount m_watchonly_immature{0};
CAmount m_anonymized{0};
CAmount m_denominated_trusted{0};
CAmount m_denominated_untrusted_pending{0};
};
Balance GetBalance(const int min_depth = 0, const bool avoid_reuse = true, const bool fAddLocked = false, const CCoinControl* coinControl = nullptr) const;
CAmount GetAnonymizableBalance(bool fSkipDenominated = false, bool fSkipUnconfirmed = true) const;
float GetAverageAnonymizedRounds() const;
CAmount GetNormalizedAnonymizedBalance() const;
bool GetBudgetSystemCollateralTX(CTransactionRef& tx, uint256 hash, CAmount amount, const COutPoint& outpoint=COutPoint()/*defaults null*/);
CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const;
/**
* Insert additional inputs into the transaction by
* calling CreateTransaction();
*/
bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl);
/** Fetch the inputs and sign with SIGHASH_ALL. */
bool SignTransaction(CMutableTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Sign the tx given the input coins and sighash. */
@ -1171,12 +1148,6 @@ public:
bool bip32derivs = true,
size_t* n_signed = nullptr) const;
/**
* Create a new transaction paying the recipients with a set of coins
* selected by SelectCoins(); Also create the change output, when needed
* @note passing nChangePosInOut as -1 will result in setting a random position
*/
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, FeeCalculation& fee_calc_out, bool sign = true, int nExtraPayloadSize = 0);
/**
* Submit the transaction to the node's mempool and then relay to peers.
* Should be called after CreateTransaction unless you want to abort
@ -1188,6 +1159,9 @@ public:
*/
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm);
/** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */
bool SubmitTxMemoryPoolAndRelay(const CWalletTx& wtx, std::string& err_string, bool relay) const;
bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, bool use_max_sig = false) const
{
std::vector<CTxOut> v_txouts(txouts.size());
@ -1230,9 +1204,6 @@ public:
int64_t GetOldestKeyPoolTime() const;
std::set<std::set<CTxDestination>> GetAddressGroupings() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::map<CTxDestination, CAmount> GetAddressBalances() const;
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
/**
@ -1246,25 +1217,16 @@ public:
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Returns amount of debit if the input matches the
* filter, otherwise returns 0
*/
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
bool IsChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool IsChange(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
CAmount GetChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
/** Returns whether all of the inputs match the filter */
bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
CAmount GetChange(const CTransaction& tx) const;
void chainStateFlushed(const CBlockLocator& loc) override;
DBErrors LoadWallet();
@ -1564,15 +1526,6 @@ public:
}
}
};
/** Calculate the size of the transaction assuming all signatures are max size
* Use DummySignatureCreator, which inserts 71 byte signatures everywhere.
* NOTE: this requires that all inputs must be in mapWallet (eg the tx should
* be IsAllFromMe). */
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig = false);
//! Add wallet name to persistent configuration so it will be loaded on startup.
bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name);

View File

@ -953,7 +953,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
uint256 hash;
ssKey >> hash;
vTxHash.push_back(hash);
vWtx.emplace_back(nullptr /* wallet */, nullptr /* tx */);
vWtx.emplace_back(nullptr /* tx */);
ssValue >> vWtx.back();
}
}

View File

@ -2,6 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
#include <wallet/wallettool.h>
#include <fs.h>
#include <util/translation.h>
#include <util/system.h>

View File

@ -5,11 +5,12 @@
#ifndef BITCOIN_WALLET_WALLETTOOL_H
#define BITCOIN_WALLET_WALLETTOOL_H
#include <wallet/wallet.h>
#include <string>
class ArgsManager;
namespace WalletTool {
void WalletShowInfo(CWallet* wallet_instance);
bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command);
} // namespace WalletTool

View File

@ -66,10 +66,16 @@ def cli_get_info_string_to_dict(cli_get_info_string):
class TestBitcoinCli(BitcoinTestFramework):
def is_specified_wallet_compiled(self):
if self.options.descriptors:
return self.is_sqlite_compiled()
else:
return self.is_bdb_compiled()
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
if self.is_wallet_compiled():
if self.is_specified_wallet_compiled():
self.requires_wallet = True
def skip_test_if_missing_module(self):
@ -122,7 +128,7 @@ class TestBitcoinCli(BitcoinTestFramework):
assert_raises_process_error(1, "Invalid value for -color option. Valid values: always, auto, never.", self.nodes[0].cli('-getinfo', '-color=foo').send_cli)
self.log.info("Test -getinfo returns expected network and blockchain info")
if self.is_wallet_compiled():
if self.is_specified_wallet_compiled():
self.nodes[0].encryptwallet(password)
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
@ -147,7 +153,7 @@ class TestBitcoinCli(BitcoinTestFramework):
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
assert_equal(cli_get_info["Proxies"], "127.0.0.1:9050 (ipv4, ipv6, onion, cjdns), 127.0.0.1:7656 (i2p)")
if self.is_wallet_compiled():
if self.is_specified_wallet_compiled():
self.log.info("Test -getinfo and dash-cli getwalletinfo return expected wallet info")
assert_equal(Decimal(cli_get_info['Balance']), BALANCE)
assert 'Balances' not in cli_get_info_string

View File

@ -6,8 +6,11 @@
from decimal import Decimal
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, create_confirmed_utxos, create_lots_of_big_transactions, gen_return_txouts
from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, gen_return_txouts
from test_framework.wallet import MiniWallet
class MempoolLimitTest(BitcoinTestFramework):
def set_test_params(self):
@ -20,55 +23,59 @@ class MempoolLimitTest(BitcoinTestFramework):
]]
self.supports_cli = False
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def send_large_txs(self, node, miniwallet, txouts, fee_rate, tx_batch_size):
for _ in range(tx_batch_size):
tx = miniwallet.create_self_transfer(from_node=node, fee_rate=fee_rate)['tx']
for txout in txouts:
tx.vout.append(txout)
miniwallet.sendrawtransaction(from_node=node, tx_hex=tx.serialize().hex())
def run_test(self):
txouts = gen_return_txouts()
relayfee = self.nodes[0].getnetworkinfo()['relayfee']
node=self.nodes[0]
miniwallet = MiniWallet(node)
relayfee = node.getnetworkinfo()['relayfee']
self.log.info('Check that mempoolminfee is minrelytxfee')
assert_equal(self.nodes[0].getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_equal(self.nodes[0].getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
self.log.info('Check that mempoolminfee is minrelaytxfee')
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
txids = []
utxos = create_confirmed_utxos(self, relayfee, self.nodes[0], 491)
tx_batch_size = 25
num_of_batches = 3
# Generate UTXOs to flood the mempool
# 1 to create a tx initially that will be evicted from the mempool later
# 3 batches of multiple transactions with a fee rate much higher than the previous UTXO
# And 1 more to verify that this tx does not get added to the mempool with a fee rate less than the mempoolminfee
self.generate(miniwallet, 1 + (num_of_batches * tx_batch_size) + 1)
# Mine 99 blocks so that the UTXOs are allowed to be spent
self.generate(node, COINBASE_MATURITY - 1)
self.log.info('Create a mempool tx that will be evicted')
us0 = utxos.pop()
inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}]
outputs = {self.nodes[0].getnewaddress() : 0.0001}
tx = self.nodes[0].createrawtransaction(inputs, outputs)
self.nodes[0].settxfee(relayfee) # specifically fund this tx with low fee
txF = self.nodes[0].fundrawtransaction(tx)
self.nodes[0].settxfee(0) # return to automatic fee selection
txFS = self.nodes[0].signrawtransactionwithwallet(txF['hex'])
txid = self.nodes[0].sendrawtransaction(txFS['hex'])
tx_to_be_evicted_id = miniwallet.send_self_transfer(from_node=node, fee_rate=relayfee)["txid"]
relayfee = self.nodes[0].getnetworkinfo()['relayfee']
base_fee = relayfee*100
for i in range (3):
txids.append([])
txids[i] = create_lots_of_big_transactions(self.nodes[0], txouts, utxos[30*i:30*i+30], 30, (i+1)*base_fee)
# Increase the tx fee rate massively to give the subsequent transactions a higher priority in the mempool
base_fee = relayfee * 1000
self.log.info("Fill up the mempool with txs with higher fee rate")
for batch_of_txid in range(num_of_batches):
fee_rate=(batch_of_txid + 1) * base_fee
self.send_large_txs(node, miniwallet, txouts, fee_rate, tx_batch_size)
self.log.info('The tx should be evicted by now')
assert txid not in self.nodes[0].getrawmempool()
txdata = self.nodes[0].gettransaction(txid)
assert txdata['confirmations'] == 0 #confirmation should still be 0
# The number of transactions created should be greater than the ones present in the mempool
assert_greater_than(tx_batch_size * num_of_batches, len(node.getrawmempool()))
# Initial tx created should not be present in the mempool anymore as it had a lower fee rate
assert tx_to_be_evicted_id not in node.getrawmempool()
self.log.info('Check that mempoolminfee is larger than minrelytxfee')
assert_equal(self.nodes[0].getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_greater_than(self.nodes[0].getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
self.log.info('Check that mempoolminfee is larger than minrelaytxfee')
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
# Deliberately try to create a tx with a fee less than the minimum mempool fee to assert that it does not get added to the mempool
self.log.info('Create a mempool tx that will not pass mempoolminfee')
us0 = utxos.pop()
inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}]
outputs = {self.nodes[0].getnewaddress() : 0.0001}
tx = self.nodes[0].createrawtransaction(inputs, outputs)
# specifically fund this tx with a fee < mempoolminfee, >= than minrelaytxfee
txF = self.nodes[0].fundrawtransaction(tx, {'feeRate': relayfee})
txFS = self.nodes[0].signrawtransactionwithwallet(txF['hex'])
assert_raises_rpc_error(-26, "mempool min fee not met", self.nodes[0].sendrawtransaction, txFS['hex'])
assert_raises_rpc_error(-26, "mempool min fee not met", miniwallet.send_self_transfer, from_node=node, fee_rate=relayfee, mempool_valid=False)
if __name__ == '__main__':
MempoolLimitTest().main()

View File

@ -3,14 +3,26 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import random
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.messages import (
COIN,
MAX_MONEY,
uint256_to_string,
)
from test_framework.util import (
assert_equal,
assert_is_hex_string,
assert_raises_rpc_error,
)
'''
rpc_coinjoin.py
Tests CoinJoin basic RPC
'''
# See coinjoin/options.h
COINJOIN_ROUNDS_DEFAULT = 4
COINJOIN_ROUNDS_MAX = 16
COINJOIN_ROUNDS_MIN = 2
COINJOIN_TARGET_MAX = int(MAX_MONEY / COIN)
COINJOIN_TARGET_MIN = 2
class CoinJoinTest(BitcoinTestFramework):
def set_test_params(self):
@ -19,45 +31,128 @@ class CoinJoinTest(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self):
self.test_coinjoin_start_stop()
self.test_coinjoin_setamount()
self.test_coinjoin_setrounds()
def setup_nodes(self):
self.add_nodes(self.num_nodes)
self.start_nodes()
def test_coinjoin_start_stop(self):
# Start Mixing
self.nodes[0].coinjoin("start")
# Get CoinJoin info
cj_info = self.nodes[0].getcoinjoininfo()
# Ensure that it started properly
def run_test(self):
node = self.nodes[0]
node.createwallet(wallet_name='w1', blank=True, disable_private_keys=False)
w1 = node.get_wallet_rpc('w1')
self.test_salt_presence(w1)
self.test_coinjoin_start_stop(w1)
self.test_setcoinjoinamount(w1)
self.test_setcoinjoinrounds(w1)
self.test_coinjoinsalt(w1)
w1.unloadwallet()
node.createwallet(wallet_name='w2', blank=True, disable_private_keys=True)
w2 = node.get_wallet_rpc('w2')
self.test_coinjoinsalt_disabled(w2)
w2.unloadwallet()
def test_salt_presence(self, node):
self.log.info('Salt should be automatically generated in new wallet')
# Will raise exception if no salt generated
assert_is_hex_string(node.coinjoinsalt('get'))
def test_coinjoin_start_stop(self, node):
self.log.info('"coinjoin" subcommands should update mixing status')
# Start mix session and ensure it's reported
node.coinjoin('start')
cj_info = node.getcoinjoininfo()
assert_equal(cj_info['enabled'], True)
assert_equal(cj_info['running'], True)
# Repeated start should yield error
assert_raises_rpc_error(-32603, 'Mixing has been started already.', node.coinjoin, 'start')
# Stop mixing
self.nodes[0].coinjoin("stop")
# Get CoinJoin info
cj_info = self.nodes[0].getcoinjoininfo()
# Ensure that it stopped properly
# Stop mix session and ensure it's reported
node.coinjoin('stop')
cj_info = node.getcoinjoininfo()
assert_equal(cj_info['enabled'], True)
assert_equal(cj_info['running'], False)
# Repeated stop should yield error
assert_raises_rpc_error(-32603, 'No mix session to stop', node.coinjoin, 'stop')
def test_coinjoin_setamount(self):
# Try normal values
self.nodes[0].setcoinjoinamount(50)
cj_info = self.nodes[0].getcoinjoininfo()
assert_equal(cj_info['max_amount'], 50)
# Reset mix session
assert_equal(node.coinjoin('reset'), "Mixing was reset")
# Try large values
self.nodes[0].setcoinjoinamount(1200000)
cj_info = self.nodes[0].getcoinjoininfo()
assert_equal(cj_info['max_amount'], 1200000)
def test_setcoinjoinamount(self, node):
self.log.info('"setcoinjoinamount" should update mixing target')
# Test normal and large values
for value in [COINJOIN_TARGET_MIN, 50, 1200000, COINJOIN_TARGET_MAX]:
node.setcoinjoinamount(value)
assert_equal(node.getcoinjoininfo()['max_amount'], value)
# Test values below minimum and above maximum
for value in [COINJOIN_TARGET_MIN - 1, COINJOIN_TARGET_MAX + 1]:
assert_raises_rpc_error(-8, "Invalid amount of DASH as mixing goal amount", node.setcoinjoinamount, value)
def test_coinjoin_setrounds(self):
# Try normal values
self.nodes[0].setcoinjoinrounds(5)
cj_info = self.nodes[0].getcoinjoininfo()
assert_equal(cj_info['max_rounds'], 5)
def test_setcoinjoinrounds(self, node):
self.log.info('"setcoinjoinrounds" should update mixing rounds')
# Test acceptable values
for value in [COINJOIN_ROUNDS_MIN, COINJOIN_ROUNDS_DEFAULT, COINJOIN_ROUNDS_MAX]:
node.setcoinjoinrounds(value)
assert_equal(node.getcoinjoininfo()['max_rounds'], value)
# Test values below minimum and above maximum
for value in [COINJOIN_ROUNDS_MIN - 1, COINJOIN_ROUNDS_MAX + 1]:
assert_raises_rpc_error(-8, "Invalid number of rounds", node.setcoinjoinrounds, value)
def test_coinjoinsalt(self, node):
self.log.info('"coinjoinsalt generate" should fail if salt already present')
assert_raises_rpc_error(-32600, 'Wallet "w1" already has set CoinJoin salt!', node.coinjoinsalt, 'generate')
self.log.info('"coinjoinsalt" subcommands should succeed if no balance and not mixing')
# 'coinjoinsalt generate' should return a new salt if overwrite enabled
s1 = node.coinjoinsalt('get')
assert_equal(node.coinjoinsalt('generate', True), True)
s2 = node.coinjoinsalt('get')
assert s1 != s2
# 'coinjoinsalt get' should fetch newly generated value (i.e. new salt should persist)
node.unloadwallet('w1')
node.loadwallet('w1')
node = self.nodes[0].get_wallet_rpc('w1')
assert_equal(s2, node.coinjoinsalt('get'))
# 'coinjoinsalt set' should work with random hashes
s1 = uint256_to_string(random.getrandbits(256))
node.coinjoinsalt('set', s1)
assert_equal(s1, node.coinjoinsalt('get'))
assert s1 != s2
# 'coinjoinsalt set' shouldn't work with nonsense values
s2 = format(0, '064x')
assert_raises_rpc_error(-8, "Invalid CoinJoin salt value", node.coinjoinsalt, 'set', s2, True)
s2 = s2[0:63] + 'h'
assert_raises_rpc_error(-8, "salt must be hexadecimal string (not '%s')" % s2, node.coinjoinsalt, 'set', s2, True)
self.log.info('"coinjoinsalt generate" and "coinjoinsalt set" should fail if mixing')
# Start mix session
node.coinjoin('start')
assert_equal(node.getcoinjoininfo()['running'], True)
# 'coinjoinsalt generate' and 'coinjoinsalt set' should fail when mixing
assert_raises_rpc_error(-4, 'Wallet "w1" is currently mixing, cannot change salt!', node.coinjoinsalt, 'generate', True)
assert_raises_rpc_error(-4, 'Wallet "w1" is currently mixing, cannot change salt!', node.coinjoinsalt, 'set', s1, True)
# 'coinjoinsalt get' should still work
assert_equal(node.coinjoinsalt('get'), s1)
# Stop mix session
node.coinjoin('stop')
assert_equal(node.getcoinjoininfo()['running'], False)
# 'coinjoinsalt generate' and 'coinjoinsalt set' should start working again
assert_equal(node.coinjoinsalt('generate', True), True)
assert_equal(node.coinjoinsalt('set', s1, True), True)
def test_coinjoinsalt_disabled(self, node):
self.log.info('"coinjoinsalt" subcommands should fail if private keys disabled')
for subcommand in ['generate', 'get']:
assert_raises_rpc_error(-32600, 'Wallet "w2" has private keys disabled, cannot perform CoinJoin!', node.coinjoinsalt, subcommand)
s1 = uint256_to_string(random.getrandbits(256))
assert_raises_rpc_error(-32600, 'Wallet "w2" has private keys disabled, cannot perform CoinJoin!', node.coinjoinsalt, 'set', s1)
if __name__ == '__main__':
CoinJoinTest().main()

View File

@ -22,9 +22,6 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def test_validateaddress(self):
node = self.nodes[0]
@ -50,7 +47,10 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
def run_test(self):
self.test_validateaddress()
self.test_getaddressinfo()
if self.is_wallet_compiled():
self.init_wallet(node=0)
self.test_getaddressinfo()
if __name__ == '__main__':

View File

@ -3,7 +3,16 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Useful Script constants and utils."""
from test_framework.script import CScript, hash160, OP_DUP, OP_HASH160, OP_CHECKSIG, OP_EQUAL, OP_EQUALVERIFY
from test_framework.script import (
CScript,
hash160,
OP_0,
OP_DUP,
OP_HASH160,
OP_CHECKSIG,
OP_EQUAL,
OP_EQUALVERIFY,
)
# To prevent a "tx-size-small" policy rule error, a transaction has to have a
# size of at least 83 bytes (MIN_STANDARD_TX_SIZE in
@ -25,32 +34,38 @@ from test_framework.script import CScript, hash160, OP_DUP, OP_HASH160, OP_CHECK
DUMMY_P2SH_SCRIPT = CScript([b'a' * 22])
DUMMY_2_P2SH_SCRIPT = CScript([b'b' * 22])
def keyhash_to_p2pkh_script(hash, main = False):
def keyhash_to_p2pkh_script(hash):
assert len(hash) == 20
return CScript([OP_DUP, OP_HASH160, hash, OP_EQUALVERIFY, OP_CHECKSIG])
def scripthash_to_p2sh_script(hash, main = False):
def scripthash_to_p2sh_script(hash):
assert len(hash) == 20
return CScript([OP_HASH160, hash, OP_EQUAL])
def key_to_p2pkh_script(key, main = False):
key = check_key(key)
return keyhash_to_p2pkh_script(hash160(key), main)
def script_to_p2sh_script(script, main = False):
def key_to_p2pkh_script(key):
key = check_key(key)
return keyhash_to_p2pkh_script(hash160(key))
def script_to_p2sh_script(script):
script = check_script(script)
return scripthash_to_p2sh_script(hash160(script), main)
return scripthash_to_p2sh_script(hash160(script))
def check_key(key):
if isinstance(key, str):
key = bytes.fromhex(key) # Assuming this is hex string
key = bytes.fromhex(key) # Assuming this is hex string
if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65):
return key
assert False
def check_script(script):
if isinstance(script, str):
script = bytes.fromhex(script) # Assuming this is hex string
script = bytes.fromhex(script) # Assuming this is hex string
if isinstance(script, bytes) or isinstance(script, CScript):
return script
assert False

View File

@ -473,12 +473,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def import_deterministic_coinbase_privkeys(self):
for i in range(len(self.nodes)):
self.init_wallet(i)
self.init_wallet(node=i)
def init_wallet(self, i):
wallet_name = self.default_wallet_name if self.wallet_names is None else self.wallet_names[i] if i < len(self.wallet_names) else False
def init_wallet(self, *, node):
wallet_name = self.default_wallet_name if self.wallet_names is None else self.wallet_names[node] if node < len(self.wallet_names) else False
if wallet_name is not False:
n = self.nodes[i]
n = self.nodes[node]
if wallet_name is not None:
n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors, load_on_startup=True)
n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase', rescan=True)

View File

@ -892,8 +892,6 @@ class RPCCoverage():
# Consider RPC generate covered, because it is overloaded in
# test_framework/test_node.py and not seen by the coverage check.
covered_cmds = set({'generate'})
# TODO: implement functional tests for coinjoinsalt
covered_cmds.add('coinjoinsalt')
# TODO: implement functional tests for voteraw
covered_cmds.add('voteraw')
# TODO: implement functional tests for getmerkleblocks

View File

@ -135,9 +135,9 @@ class WalletBackupTest(BitcoinTestFramework):
assert os.path.exists(wallet_file)
def init_three(self):
self.init_wallet(0)
self.init_wallet(1)
self.init_wallet(2)
self.init_wallet(node=0)
self.init_wallet(node=1)
self.init_wallet(node=2)
def run_test(self):
self.log.info("Generating initial blockchain")

View File

@ -617,7 +617,7 @@ class WalletTest(BitcoinTestFramework):
total_txs = len(self.nodes[0].listtransactions("*", 99999))
# Try with walletrejectlongchains
# Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
# Double chain limit but require combining inputs, so we pass AttemptSelection
self.stop_node(0)
extra_args = ["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)]
self.start_node(0, extra_args=extra_args)

View File

@ -23,7 +23,7 @@ class ListDescriptorsTest(BitcoinTestFramework):
self.skip_if_no_sqlite()
# do not create any wallet by default
def init_wallet(self, i):
def init_wallet(self, *, node):
return
def run_test(self):

View File

@ -239,5 +239,16 @@ class UpgradeWalletTest(BitcoinTestFramework):
desc_wallet = self.nodes[0].get_wallet_rpc("desc_upgrade")
self.test_upgradewallet(desc_wallet, previous_version=120200, expected_version=120200)
self.log.info("Checking that descriptor wallets without privkeys do nothing, successfully")
self.nodes[0].createwallet(wallet_name="desc_upgrade_nopriv", descriptors=True, disable_private_keys=True)
desc_wallet = self.nodes[0].get_wallet_rpc("desc_upgrade_nopriv")
self.test_upgradewallet(desc_wallet, previous_version=120200, expected_version=120200)
if self.is_bdb_compiled():
self.log.info("Upgrading a wallet with private keys disabled")
self.nodes[0].createwallet(wallet_name="privkeys_disabled_upgrade", disable_private_keys=True, descriptors=False)
disabled_wallet = self.nodes[0].get_wallet_rpc("privkeys_disabled_upgrade")
self.test_upgradewallet(disabled_wallet, previous_version=120200, expected_version=120200)
if __name__ == '__main__':
UpgradeWalletTest().main()

View File

@ -48,7 +48,6 @@ implicit-integer-sign-change:*/include/c++/
implicit-integer-sign-change:*/new_allocator.h
implicit-integer-sign-change:addrman.h
implicit-integer-sign-change:bech32.cpp
implicit-integer-sign-change:common/bloom.cpp
implicit-integer-sign-change:chain.cpp
implicit-integer-sign-change:chain.h
implicit-integer-sign-change:compat/stdin.cpp

View File

@ -425,6 +425,30 @@
"output_cmp": "txcreatedata2.json",
"description": "Creates a new transaction with one input, one address output and one data (zero value) output (output in json)"
},
{ "exec": "./dash-tx",
"args":
["-create",
"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:11aa"],
"return_code": 1,
"error_txt": "error: invalid TX sequence id '11aa'",
"description": "Try to parse a sequence number outside the allowed range"
},
{ "exec": "./dash-tx",
"args":
["-create",
"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:-1"],
"return_code": 1,
"error_txt": "error: invalid TX sequence id '-1'",
"description": "Try to parse a sequence number outside the allowed range"
},
{ "exec": "./dash-tx",
"args":
["-create",
"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967296"],
"return_code": 1,
"error_txt": "error: invalid TX sequence id '4294967296'",
"description": "Try to parse a sequence number outside the allowed range"
},
{ "exec": "./dash-tx",
"args":
["-create",
@ -433,6 +457,14 @@
"output_cmp": "txcreatedata_seq0.hex",
"description": "Creates a new transaction with one input with sequence number and one address output"
},
{ "exec": "./dash-tx",
"args":
["-create",
"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0: 4294967293 ",
"outaddr=0.18:XijDvbYpPmznwgpWD3DkdYNfGmRP2KoVSk"],
"output_cmp": "txcreatedata_seq0.hex",
"description": "Creates a new transaction with one input with sequence number (+whitespace) and one address output"
},
{ "exec": "./dash-tx",
"args":
["-json",
@ -457,15 +489,27 @@
"output_cmp": "txcreatedata_seq1.json",
"description": "Adds a new input with sequence number to a transaction (output in json)"
},
{ "exec": "./dash-tx",
"args": ["-create", "outmultisig=1:-2:3:02a5:021:02df", "nversion=1"],
"return_code": 1,
"error_txt": "error: invalid multisig required number '-2'",
"description": "Try to parse a multisig number outside the allowed range"
},
{ "exec": "./dash-tx",
"args": ["-create", "outmultisig=1:2:3a:02a5:021:02df", "nversion=1"],
"return_code": 1,
"error_txt": "error: invalid multisig total number '3a'",
"description": "Try to parse a multisig number outside the allowed range"
},
{ "exec": "./dash-tx",
"args": ["-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485", "nversion=1"],
"output_cmp": "txcreatemultisig1.hex",
"description": "Creates a new transaction with a single 2-of-3 multisig output"
},
{ "exec": "./dash-tx",
"args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485", "nversion=1"],
"args": ["-json", "-create", "outmultisig=1: 2: 3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485", "nversion=1"],
"output_cmp": "txcreatemultisig1.json",
"description": "Creates a new transaction with a single 2-of-3 multisig output (output in json)"
"description": "Creates a new transaction with a single 2-of-3 multisig output (with whitespace, output in json)"
},
{ "exec": "./dash-tx",
"args": ["-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:S", "nversion=1"],