mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge #6114: backport: bitcoin#19801, #20556, #21141, #21235, #21331, #21343, #21424, #21691, #21777
4731f7045f
docs: release notes for bitcoin#21141 - walletnotify %h %b (Konstantin Akimov)044ddb4c80
Merge bitcoin/bitcoin#21777: test: Fix feature_notifications.py intermittent issue (MarcoFalke)5336f42ea8
Merge bitcoin/bitcoin#19801: test: check for all possible OP_CLTV fail reasons in feature_cltv.py (BIP 65) (MarcoFalke)1cc6aa6c83
Merge bitcoin/bitcoin#21691: test: Check that no versionbits are re-used (MarcoFalke)b55fdf8e68
Merge #21235: p2p: Clarify disconnect log message in ProcessGetBlockData, remove send bool (MarcoFalke)ddc6fca7f3
Merge #21343: doc: revamp macOS build doc (fanquake)709652bff7
Merge #21141: wallet: Add new format string placeholders for walletnotify (Wladimir J. van der Laan)a3bee9c8ec
Merge #21424: Net processing: Tidy up CNodeState ctor (MarcoFalke)aab2a665c3
Merge #20556: rpc: Properly document return values (submitblock, gettxout, getblocktemplate, scantxoutset) (fanquake)c26722fc0e
Merge #21331: rpc: replace wallet raw pointers with references (#18592 rebased) (MarcoFalke) Pull request description: ## What was done? Backports from bitcoin v22: - bitcoin/bitcoin#21331 - bitcoin/bitcoin#20556 - bitcoin/bitcoin#21424 - bitcoin/bitcoin#21141 - bitcoin/bitcoin#21343 - bitcoin/bitcoin#21235 - bitcoin/bitcoin#21691 - bitcoin/bitcoin#19801 - bitcoin/bitcoin#21777 ## How Has This Been Tested? Run unit and functional tests ## Breaking Changes N/A ## Checklist: - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: UdjinM6: utACK4731f7045f
PastaPastaPasta: utACK4731f7045f
Tree-SHA512: dcee684563e4e07e838e96df0bf5e49d59e8c85aea6beca3239782e7d90a24f13d828b1201073585b888b0b154b4ba8bb90f88a36e3f923ac03b46f595d75500
This commit is contained in:
commit
5211886fb4
336
doc/build-osx.md
336
doc/build-osx.md
@ -1,51 +1,238 @@
|
||||
# macOS Build Instructions and Notes
|
||||
# macOS Build Guide
|
||||
|
||||
**Updated for MacOS [11.2](https://www.apple.com/macos/big-sur/)**
|
||||
|
||||
This guide describes how to build dashd, command-line utilities, and GUI on macOS
|
||||
|
||||
**Note:** The following is for Intel Macs only!
|
||||
|
||||
## Dependencies
|
||||
|
||||
The following dependencies are **required**:
|
||||
|
||||
Library | Purpose | Description
|
||||
-----------------------------------------------------------|------------|----------------------
|
||||
[automake](https://formulae.brew.sh/formula/automake) | Build | Generate makefile
|
||||
[libtool](https://formulae.brew.sh/formula/libtool) | Build | Shared library support
|
||||
[pkg-config](https://formulae.brew.sh/formula/pkg-config) | Build | Configure compiler and linker flags
|
||||
[boost](https://formulae.brew.sh/formula/boost) | Utility | Library for threading, data structures, etc
|
||||
[libevent](https://formulae.brew.sh/formula/libevent) | Networking | OS independent asynchronous networking
|
||||
|
||||
The following dependencies are **optional**:
|
||||
|
||||
Library | Purpose | Description
|
||||
--------------------------------------------------------------- |------------------|----------------------
|
||||
[berkeley-db@4](https://formulae.brew.sh/formula/berkeley-db@4) | Berkeley DB | Wallet storage (only needed when wallet enabled)
|
||||
[qt@5](https://formulae.brew.sh/formula/qt@5) | GUI | GUI toolkit (only needed when GUI enabled)
|
||||
[qrencode](https://formulae.brew.sh/formula/qrencode) | QR codes in GUI | Generating QR codes (only needed when GUI enabled)
|
||||
[zeromq](https://formulae.brew.sh/formula/zeromq) | ZMQ notification | Allows generating ZMQ notifications (requires ZMQ version >= 4.0.0)
|
||||
[sqlite](https://formulae.brew.sh/formula/sqlite) | SQLite DB | Wallet storage (only needed when wallet enabled)
|
||||
[miniupnpc](https://formulae.brew.sh/formula/miniupnpc) | UPnP Support | Firewall-jumping support (needed for port mapping support)
|
||||
[libnatpmp](https://formulae.brew.sh/formula/libnatpmp) | NAT-PMP Support | Firewall-jumping support (needed for port mapping support)
|
||||
[python3](https://formulae.brew.sh/formula/python@3.9) | Testing | Python Interpreter (only needed when running the test suite)
|
||||
|
||||
The following dependencies are **optional** packages required for deploying:
|
||||
|
||||
Library | Purpose | Description
|
||||
----------------------------------------------------|------------------|----------------------
|
||||
[librsvg](https://formulae.brew.sh/formula/librsvg) | Deploy Dependency| Library to render SVG files
|
||||
[ds_store](https://pypi.org/project/ds-store/) | Deploy Dependency| Examine and modify .DS_Store files
|
||||
[mac_alias](https://pypi.org/project/mac-alias/) | Deploy Dependency| Generate/Read binary alias and bookmark records
|
||||
|
||||
See [dependencies.md](dependencies.md) for a complete overview.
|
||||
|
||||
## Preparation
|
||||
|
||||
The commands in this guide should be executed in a Terminal application.
|
||||
The built-in one is located in
|
||||
macOS comes with a built-in Terminal located in:
|
||||
|
||||
```
|
||||
/Applications/Utilities/Terminal.app
|
||||
```
|
||||
|
||||
## Preparation
|
||||
Install the macOS command line tools:
|
||||
### 1. Xcode Command Line Tools
|
||||
|
||||
```shell
|
||||
The Xcode Command Line Tools are a collection of build tools for macOS.
|
||||
These tools must be installed in order to build Dash Core from source.
|
||||
|
||||
To install, run the following command from your terminal:
|
||||
|
||||
``` bash
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
When the popup appears, click `Install`.
|
||||
Upon running the command, you should see a popup appear.
|
||||
Click on `Install` to continue the installation process.
|
||||
|
||||
Then install [Homebrew](https://brew.sh).
|
||||
### 2. Homebrew Package Manager
|
||||
|
||||
## Dependencies
|
||||
```shell
|
||||
brew install automake libtool boost gmp miniupnpc pkg-config python qt@5 libevent libnatpmp qrencode
|
||||
Homebrew is a package manager for macOS that allows one to install packages from the command line easily.
|
||||
While several package managers are available for macOS, this guide will focus on Homebrew as it is the most popular.
|
||||
Since the examples in this guide which walk through the installation of a package will use Homebrew, it is recommended that you install it to follow along.
|
||||
Otherwise, you can adapt the commands to your package manager of choice.
|
||||
|
||||
To install the Homebrew package manager, see: https://brew.sh
|
||||
|
||||
Note: If you run into issues while installing Homebrew or pulling packages, refer to [Homebrew's troubleshooting page](https://docs.brew.sh/Troubleshooting).
|
||||
|
||||
### 3. Install Required Dependencies
|
||||
|
||||
The first step is to download the required dependencies.
|
||||
These dependencies represent the packages required to get a barebones installation up and running.
|
||||
To install, run the following from your terminal:
|
||||
|
||||
``` bash
|
||||
brew install automake libtool boost gmp pkg-config libevent
|
||||
```
|
||||
|
||||
If you run into issues, check [Homebrew's troubleshooting page](https://docs.brew.sh/Troubleshooting).
|
||||
See [dependencies.md](dependencies.md) for a complete overview.
|
||||
### 4. Clone Dash repository
|
||||
|
||||
The wallet support requires one or both of the dependencies ([*SQLite*](#sqlite) and [*Berkeley DB*](#berkeley-db)) in the sections below.
|
||||
To build Dash Core without wallet, see [*Disable-wallet mode*](#disable-wallet-mode).
|
||||
`git` should already be installed by default on your system.
|
||||
Now that all the required dependencies are installed, let's clone the Dash Core repository to a directory.
|
||||
All build scripts and commands will run from this directory.
|
||||
|
||||
#### SQLite
|
||||
``` bash
|
||||
git clone https://github.com/dashpay/dash.git
|
||||
```
|
||||
|
||||
Usually, macOS installation already has a suitable SQLite installation.
|
||||
Also, the Homebrew package could be installed:
|
||||
### 5. Install Optional Dependencies
|
||||
|
||||
```shell
|
||||
#### Wallet Dependencies
|
||||
|
||||
It is not necessary to build wallet functionality to run `dashd` or `dash-qt`.
|
||||
To enable legacy wallets, you must install `berkeley-db@4`.
|
||||
To enable [descriptor wallets](https://github.com/dashpay/dash/blob/master/doc/descriptors.md), `sqlite` is required.
|
||||
Skip `berkeley-db@4` if you intend to *exclusively* use descriptor wallets.
|
||||
|
||||
###### Legacy Wallet Support
|
||||
|
||||
`berkeley-db@4` is required to enable support for legacy wallets.
|
||||
Skip if you don't intend to use legacy wallets.
|
||||
|
||||
``` bash
|
||||
brew install berkeley-db@4
|
||||
```
|
||||
|
||||
###### Descriptor Wallet Support
|
||||
|
||||
Note: Apple has included a useable `sqlite` package since macOS 10.14.
|
||||
You may not need to install this package.
|
||||
|
||||
`sqlite` is required to enable support for descriptor wallets.
|
||||
Skip if you don't intend to use descriptor wallets.
|
||||
|
||||
``` bash
|
||||
brew install sqlite
|
||||
```
|
||||
---
|
||||
|
||||
In that case the Homebrew package will prevail.
|
||||
#### GUI Dependencies
|
||||
|
||||
If you want to build the disk image with `make deploy` (.dmg / optional), you need:
|
||||
[`macdeployqtplus`](../contrib/macdeploy/README.md) dependencies:
|
||||
```shell
|
||||
###### Qt
|
||||
|
||||
Dash Core includes a GUI built with the cross-platform Qt Framework.
|
||||
To compile the GUI, we need to install `qt@5`.
|
||||
Skip if you don't intend to use the GUI.
|
||||
|
||||
``` bash
|
||||
brew install qt@5
|
||||
```
|
||||
|
||||
Note: Building with Qt binaries downloaded from the Qt website is not officially supported.
|
||||
See the notes in [#7714](https://github.com/dashpay/dash/issues/7714).
|
||||
|
||||
###### qrencode
|
||||
|
||||
The GUI can encode addresses in a QR Code. To build in QR support for the GUI, install `qrencode`.
|
||||
Skip if not using the GUI or don't want QR code functionality.
|
||||
|
||||
``` bash
|
||||
brew install qrencode
|
||||
```
|
||||
---
|
||||
|
||||
#### Port Mapping Dependencies
|
||||
|
||||
###### miniupnpc
|
||||
|
||||
miniupnpc may be used for UPnP port mapping.
|
||||
Skip if you do not need this functionality.
|
||||
|
||||
``` bash
|
||||
brew install miniupnpc
|
||||
```
|
||||
|
||||
###### libnatpmp
|
||||
|
||||
libnatpmp may be used for NAT-PMP port mapping.
|
||||
Skip if you do not need this functionality.
|
||||
|
||||
``` bash
|
||||
brew install libnatpmp
|
||||
```
|
||||
|
||||
Note: UPnP and NAT-PMP support will be compiled in and disabled by default.
|
||||
Check out the [further configuration](#further-configuration) section for more information.
|
||||
|
||||
---
|
||||
|
||||
#### ZMQ Dependencies
|
||||
|
||||
Support for ZMQ notifications requires the following dependency.
|
||||
Skip if you do not need ZMQ functionality.
|
||||
|
||||
``` bash
|
||||
brew install zeromq
|
||||
```
|
||||
|
||||
ZMQ is automatically compiled in and enabled if the dependency is detected.
|
||||
Check out the [further configuration](#further-configuration) section for more information.
|
||||
|
||||
For more information on ZMQ, see: [zmq.md](zmq.md)
|
||||
|
||||
---
|
||||
|
||||
#### Test Suite Dependencies
|
||||
|
||||
There is an included test suite that is useful for testing code changes when developing.
|
||||
To run the test suite (recommended), you will need to have Python 3 installed:
|
||||
|
||||
``` bash
|
||||
brew install python
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Deploy Dependencies
|
||||
|
||||
You can deploy a `.dmg` containing the Dash Core application using `make deploy`.
|
||||
This command depends on a couple of python packages, so it is required that you have `python` installed.
|
||||
|
||||
Ensuring that `python` is installed, you can install the deploy dependencies by running the following commands in your terminal:
|
||||
|
||||
``` bash
|
||||
pip3 install ds_store mac_alias
|
||||
```
|
||||
|
||||
#### Berkeley DB
|
||||
## Building Dash Core
|
||||
|
||||
### 1. Configuration
|
||||
|
||||
There are many ways to configure Dash Core, here are a few common examples:
|
||||
|
||||
##### Wallet (BDB + SQlite) Support, No GUI:
|
||||
|
||||
If `berkeley-db@4` is installed, then legacy wallet support will be built.
|
||||
If `berkeley-db@4` is not installed, then this will throw an error.
|
||||
If `sqlite` is installed, then descriptor wallet support will also be built.
|
||||
Additionally, this explicitly disables the GUI.
|
||||
|
||||
``` bash
|
||||
./autogen.sh
|
||||
./configure --with-gui=no
|
||||
```
|
||||
|
||||
###### Berkeley DB
|
||||
|
||||
It is recommended to use Berkeley DB 4.8. If you have to build it yourself,
|
||||
you can use [the installation script included in contrib/](contrib/install_db4.sh)
|
||||
@ -55,59 +242,68 @@ like so:
|
||||
./contrib/install_db4.sh .
|
||||
```
|
||||
|
||||
from the root of the repository.
|
||||
##### Wallet (only SQlite) and GUI Support:
|
||||
|
||||
Also, the Homebrew package could be installed:
|
||||
This explicitly enables the GUI and disables legacy wallet support.
|
||||
If `qt` is not installed, this will throw an error.
|
||||
If `sqlite` is installed then descriptor wallet functionality will be built.
|
||||
If `sqlite` is not installed, then wallet functionality will be disabled.
|
||||
|
||||
```shell
|
||||
brew install berkeley-db4
|
||||
``` bash
|
||||
./autogen.sh
|
||||
./configure --without-bdb --with-gui=yes
|
||||
```
|
||||
|
||||
## Build Dash Core
|
||||
##### No Wallet or GUI
|
||||
|
||||
1. Clone the Dash Core source code:
|
||||
```shell
|
||||
git clone https://github.com/dashpay/dash
|
||||
cd dash
|
||||
```
|
||||
|
||||
2. Build Dash Core:
|
||||
|
||||
Configure and build the headless Dash Core binaries as well as the GUI (if Qt is found).
|
||||
|
||||
You can disable the GUI build by passing `--without-gui` to configure.
|
||||
```shell
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
```
|
||||
|
||||
3. It is recommended to build and run the unit tests:
|
||||
```shell
|
||||
make check
|
||||
```
|
||||
|
||||
4. You can also create a `.dmg` that contains the `.app` bundle (optional):
|
||||
```shell
|
||||
make deploy
|
||||
```
|
||||
|
||||
## Disable-wallet mode
|
||||
When the intention is to run only a P2P node without a wallet, Dash Core may be
|
||||
compiled in disable-wallet mode with:
|
||||
```shell
|
||||
./configure --disable-wallet
|
||||
``` bash
|
||||
./autogen.sh
|
||||
./configure --without-wallet --with-gui=no
|
||||
```
|
||||
|
||||
In this case there is no dependency on [*Berkeley DB*](#berkeley-db) and [*SQLite*](#sqlite).
|
||||
##### Further Configuration
|
||||
|
||||
Mining is also possible in disable-wallet mode using the `getblocktemplate` RPC call.
|
||||
You may want to dig deeper into the configuration options to achieve your desired behavior.
|
||||
Examine the output of the following command for a full list of configuration options:
|
||||
|
||||
## Running
|
||||
``` bash
|
||||
./configure -help
|
||||
```
|
||||
|
||||
Dash Core is now available at `./src/dashd`
|
||||
### 2. Compile
|
||||
|
||||
After configuration, you are ready to compile.
|
||||
Run the following in your terminal to compile Dash Core:
|
||||
|
||||
``` bash
|
||||
make -jx # use -jX here for parallelism
|
||||
make check # Run tests if Python 3 is available
|
||||
```
|
||||
|
||||
### 3. Deploy (optional)
|
||||
|
||||
You can also create a `.dmg` containing the `.app` bundle by running the following command:
|
||||
|
||||
``` bash
|
||||
make deploy
|
||||
```
|
||||
|
||||
## Running Dash Core
|
||||
|
||||
Dash Core should now be available at `./src/dashd`.
|
||||
If you compiled support for the GUI, it should be available at `./src/qt/dash-qt`.
|
||||
|
||||
The first time you run `dashd` or `dash-qt`, it will start downloading the blockchain.
|
||||
This process could take many hours, or even days on slower than average systems.
|
||||
|
||||
By default, blockchain and wallet data files will be stored in:
|
||||
|
||||
``` bash
|
||||
/Users/${USER}/Library/Application Support/Dash/
|
||||
```
|
||||
|
||||
Before running, you may create an empty configuration file:
|
||||
|
||||
```shell
|
||||
mkdir -p "/Users/${USER}/Library/Application Support/DashCore"
|
||||
|
||||
@ -116,9 +312,8 @@ touch "/Users/${USER}/Library/Application Support/DashCore/dash.conf"
|
||||
chmod 600 "/Users/${USER}/Library/Application Support/DashCore/dash.conf"
|
||||
```
|
||||
|
||||
The first time you run dashd, it will start downloading the blockchain. This process could take many hours, or even days on slower than average systems.
|
||||
|
||||
You can monitor the download process by looking at the debug.log file:
|
||||
|
||||
```shell
|
||||
tail -f $HOME/Library/Application\ Support/DashCore/debug.log
|
||||
```
|
||||
@ -126,13 +321,8 @@ tail -f $HOME/Library/Application\ Support/DashCore/debug.log
|
||||
## Other commands:
|
||||
|
||||
```shell
|
||||
./src/dashd -daemon # Starts the dash daemon.
|
||||
./src/dashd -daemon # Starts the dashd daemon.
|
||||
./src/dash-cli --help # Outputs a list of command-line options.
|
||||
./src/dash-cli help # Outputs a list of RPC commands when the daemon is running.
|
||||
./src/qt/dash-qt -server # Starts the dash-qt server mode, allows dash-cli control
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
* Tested on OS X 10.12 Sierra through macOS 10.15 Catalina on 64-bit Intel
|
||||
processors only.
|
||||
* Building with downloaded Qt binaries is not officially supported. See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714).
|
||||
|
6
doc/release-notes-21141.md
Normal file
6
doc/release-notes-21141.md
Normal file
@ -0,0 +1,6 @@
|
||||
## Command-line options
|
||||
### Changes in existing cmd-line options:
|
||||
|
||||
- `-walletnotify=<cmd>` has a new format options "%h" and "%b".
|
||||
%b is replaced by the hash of the block including the transaction (set to 'unconfirmed' if the transaction is not included).
|
||||
%h is replaced by the block height (-1 if not included).
|
@ -826,7 +826,7 @@ struct CNodeState {
|
||||
bool m_protect{false};
|
||||
};
|
||||
|
||||
ChainSyncTimeoutState m_chain_sync{0, nullptr, false, false};
|
||||
ChainSyncTimeoutState m_chain_sync;
|
||||
|
||||
//! Time of last new block announcement
|
||||
int64_t m_last_block_announcement{0};
|
||||
@ -900,11 +900,7 @@ struct CNodeState {
|
||||
//! A rolling bloom filter of all announced tx CInvs to this peer.
|
||||
CRollingBloomFilter m_recently_announced_invs = CRollingBloomFilter{INVENTORY_MAX_RECENT_RELAY, 0.000001};
|
||||
|
||||
CNodeState(bool is_inbound) :
|
||||
m_is_inbound(is_inbound)
|
||||
{
|
||||
m_recently_announced_invs.reset();
|
||||
}
|
||||
CNodeState(bool is_inbound) : m_is_inbound(is_inbound) {}
|
||||
};
|
||||
|
||||
// Keeps track of the time (in microseconds) when transactions were requested last time
|
||||
@ -2385,7 +2381,6 @@ void PeerManagerImpl::RelayAddress(NodeId originator,
|
||||
|
||||
void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv, llmq::CInstantSendManager& isman)
|
||||
{
|
||||
bool send = false;
|
||||
std::shared_ptr<const CBlock> a_recent_block;
|
||||
std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
|
||||
{
|
||||
@ -2419,39 +2414,37 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
|
||||
|
||||
LOCK(cs_main);
|
||||
const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(inv.hash);
|
||||
if (pindex) {
|
||||
send = BlockRequestAllowed(pindex);
|
||||
if (!send) {
|
||||
LogPrint(BCLog::NET,"%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId());
|
||||
if (!pindex) {
|
||||
return;
|
||||
}
|
||||
if (!BlockRequestAllowed(pindex)) {
|
||||
LogPrint(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId());
|
||||
return;
|
||||
}
|
||||
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
|
||||
// disconnect node in case we have reached the outbound limit for serving historical blocks
|
||||
if (send &&
|
||||
m_connman.OutboundTargetReached(true) &&
|
||||
if (m_connman.OutboundTargetReached(true) &&
|
||||
(((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
|
||||
!pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target
|
||||
) {
|
||||
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
|
||||
|
||||
//disconnect node
|
||||
pfrom.fDisconnect = true;
|
||||
send = false;
|
||||
return;
|
||||
}
|
||||
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
|
||||
if (send && !pfrom.HasPermission(NetPermissionFlags::NoBan) && (
|
||||
if (!pfrom.HasPermission(NetPermissionFlags::NoBan) && (
|
||||
(((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (m_chainman.ActiveChain().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
|
||||
)) {
|
||||
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom.GetId());
|
||||
|
||||
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n", pfrom.GetId());
|
||||
//disconnect node and prevent it from stalling (would otherwise wait for the missing block)
|
||||
pfrom.fDisconnect = true;
|
||||
send = false;
|
||||
return;
|
||||
}
|
||||
// Pruned nodes may have deleted the block, so check whether
|
||||
// it's available before trying to send.
|
||||
if (send && (pindex->nStatus & BLOCK_HAVE_DATA))
|
||||
{
|
||||
if (!(pindex->nStatus & BLOCK_HAVE_DATA)) {
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<const CBlock> pblock;
|
||||
if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
|
||||
pblock = a_recent_block;
|
||||
@ -2529,7 +2522,6 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
|
||||
peer.m_continuation_block.SetNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed).
|
||||
|
@ -1494,9 +1494,9 @@ static RPCHelpMan gettxout()
|
||||
{"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
|
||||
{"include_mempool", RPCArg::Type::BOOL, /* default */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
|
||||
RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
|
||||
{RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
|
||||
{RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
|
||||
{RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
|
||||
@ -1512,6 +1512,7 @@ static RPCHelpMan gettxout()
|
||||
}},
|
||||
{RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
|
||||
}},
|
||||
},
|
||||
RPCExamples{
|
||||
"\nGet unspent transactions\n"
|
||||
+ HelpExampleCli("listunspent", "") +
|
||||
@ -2721,9 +2722,14 @@ static RPCHelpMan scantxoutset()
|
||||
},
|
||||
"[scanobjects,...]"},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
|
||||
RPCResult{"When action=='status' and no scan is in progress", RPCResult::Type::NONE, "", ""},
|
||||
RPCResult{"When action=='status' and scan is in progress", RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
{RPCResult::Type::NUM, "progress", "The scan progress"},
|
||||
}},
|
||||
RPCResult{"When action=='start'", RPCResult::Type::OBJ, "", "", {
|
||||
{RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
|
||||
{RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
|
||||
{RPCResult::Type::NUM, "height", "The current block height (index)"},
|
||||
@ -2742,6 +2748,7 @@ static RPCHelpMan scantxoutset()
|
||||
}},
|
||||
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
|
||||
}},
|
||||
},
|
||||
RPCExamples{""},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
|
@ -214,15 +214,13 @@ static bool ValidatePlatformPort(const int32_t port)
|
||||
#ifdef ENABLE_WALLET
|
||||
|
||||
template<typename SpecialTxPayload>
|
||||
static void FundSpecialTx(CWallet* pwallet, CMutableTransaction& tx, const SpecialTxPayload& payload, const CTxDestination& fundDest)
|
||||
static void FundSpecialTx(CWallet& wallet, CMutableTransaction& tx, const SpecialTxPayload& payload, const CTxDestination& fundDest)
|
||||
{
|
||||
CHECK_NONFATAL(pwallet != nullptr);
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
pwallet->BlockUntilSyncedToCurrentChain();
|
||||
wallet.BlockUntilSyncedToCurrentChain();
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
LOCK(wallet.cs_wallet);
|
||||
|
||||
CTxDestination nodest = CNoDestination();
|
||||
if (fundDest == nodest) {
|
||||
@ -253,7 +251,7 @@ static void FundSpecialTx(CWallet* pwallet, CMutableTransaction& tx, const Speci
|
||||
coinControl.fRequireAllInputs = false;
|
||||
|
||||
std::vector<COutput> vecOutputs;
|
||||
pwallet->AvailableCoins(vecOutputs);
|
||||
wallet.AvailableCoins(vecOutputs);
|
||||
|
||||
for (const auto& out : vecOutputs) {
|
||||
CTxDestination txDest;
|
||||
@ -272,7 +270,7 @@ static void FundSpecialTx(CWallet* pwallet, CMutableTransaction& tx, const Speci
|
||||
bilingual_str strFailReason;
|
||||
|
||||
FeeCalculation fee_calc_out;
|
||||
if (!pwallet->CreateTransaction(vecSend, newTx, nFee, nChangePos, strFailReason, coinControl, fee_calc_out, false, tx.vExtraPayload.size())) {
|
||||
if (!wallet.CreateTransaction(vecSend, newTx, nFee, nChangePos, strFailReason, coinControl, fee_calc_out, false, tx.vExtraPayload.size())) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason.original);
|
||||
}
|
||||
|
||||
@ -677,11 +675,11 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
|
||||
const bool isEvoRequested = mnType == MnType::Evo;
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
if (action == ProTxRegisterAction::External || action == ProTxRegisterAction::Fund) {
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
}
|
||||
|
||||
const bool isV19active{DeploymentActiveAfter(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip();), Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
|
||||
@ -796,7 +794,7 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
}
|
||||
|
||||
if (action == ProTxRegisterAction::Fund) {
|
||||
FundSpecialTx(wallet.get(), tx, ptx, fundDest);
|
||||
FundSpecialTx(*pwallet, tx, ptx, fundDest);
|
||||
UpdateSpecialTxInputsHash(tx, ptx);
|
||||
CAmount fundCollateral = GetMnType(mnType).collat_amount;
|
||||
uint32_t collateralIndex = (uint32_t) -1;
|
||||
@ -815,14 +813,14 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
// referencing external collateral
|
||||
|
||||
const bool unlockOnError = [&]() {
|
||||
if (LOCK(wallet->cs_wallet); !wallet->IsLockedCoin(ptx.collateralOutpoint.hash, ptx.collateralOutpoint.n)) {
|
||||
wallet->LockCoin(ptx.collateralOutpoint);
|
||||
if (LOCK(pwallet->cs_wallet); !pwallet->IsLockedCoin(ptx.collateralOutpoint.hash, ptx.collateralOutpoint.n)) {
|
||||
pwallet->LockCoin(ptx.collateralOutpoint);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
try {
|
||||
FundSpecialTx(wallet.get(), tx, ptx, fundDest);
|
||||
FundSpecialTx(*pwallet, tx, ptx, fundDest);
|
||||
UpdateSpecialTxInputsHash(tx, ptx);
|
||||
Coin coin;
|
||||
if (!GetUTXOCoin(chainman.ActiveChainstate(), ptx.collateralOutpoint, coin)) {
|
||||
@ -847,13 +845,13 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
return ret;
|
||||
} else {
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK(pwallet->cs_wallet);
|
||||
// lets prove we own the collateral
|
||||
CScript scriptPubKey = GetScriptForDestination(txDest);
|
||||
std::unique_ptr<SigningProvider> provider = wallet->GetSolvingProvider(scriptPubKey);
|
||||
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
|
||||
|
||||
std::string signed_payload;
|
||||
SigningResult err = wallet->SignMessage(ptx.MakeSignString(), *pkhash, signed_payload);
|
||||
SigningResult err = pwallet->SignMessage(ptx.MakeSignString(), *pkhash, signed_payload);
|
||||
if (err == SigningResult::SIGNING_FAILED) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, SigningResultString(err));
|
||||
} else if (err != SigningResult::OK){
|
||||
@ -868,7 +866,7 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
}
|
||||
} catch (...) {
|
||||
if (unlockOnError) {
|
||||
WITH_LOCK(wallet->cs_wallet, wallet->UnlockCoin(ptx.collateralOutpoint));
|
||||
WITH_LOCK(pwallet->cs_wallet, pwallet->UnlockCoin(ptx.collateralOutpoint));
|
||||
}
|
||||
throw;
|
||||
}
|
||||
@ -903,7 +901,7 @@ static RPCHelpMan protx_register_submit()
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*wallet);
|
||||
|
||||
CMutableTransaction tx;
|
||||
if (!DecodeHexTx(tx, request.params[0].get_str())) {
|
||||
@ -1020,7 +1018,7 @@ static UniValue protx_update_service_common_wrapper(const JSONRPCRequest& reques
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*wallet);
|
||||
|
||||
const bool isV19active{DeploymentActiveAfter(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip();), Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
|
||||
const bool is_bls_legacy = !isV19active;
|
||||
@ -1109,7 +1107,7 @@ static UniValue protx_update_service_common_wrapper(const JSONRPCRequest& reques
|
||||
}
|
||||
}
|
||||
|
||||
FundSpecialTx(wallet.get(), tx, ptx, feeSource);
|
||||
FundSpecialTx(*wallet, tx, ptx, feeSource);
|
||||
|
||||
SignSpecialTxPayloadByHash(tx, ptx, keyOperator);
|
||||
SetTxPayload(tx, ptx);
|
||||
@ -1155,7 +1153,7 @@ static RPCHelpMan protx_update_registrar_wrapper(bool specific_legacy_bls_scheme
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*wallet);
|
||||
|
||||
CProUpRegTx ptx;
|
||||
ptx.proTxHash = ParseHashV(request.params[0], "proTxHash");
|
||||
@ -1217,7 +1215,7 @@ static RPCHelpMan protx_update_registrar_wrapper(bool specific_legacy_bls_scheme
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[4].get_str());
|
||||
}
|
||||
|
||||
FundSpecialTx(wallet.get(), tx, ptx, feeSourceDest);
|
||||
FundSpecialTx(*wallet, tx, ptx, feeSourceDest);
|
||||
SignSpecialTxPayloadByHash(tx, ptx, dmn->pdmnState->keyIDOwner, *wallet);
|
||||
SetTxPayload(tx, ptx);
|
||||
|
||||
@ -1268,10 +1266,10 @@ static RPCHelpMan protx_revoke()
|
||||
CChainstateHelper& chain_helper = *node.chain_helper;
|
||||
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
const bool isV19active{DeploymentActiveAfter(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip();), Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
|
||||
const bool is_bls_legacy = !isV19active;
|
||||
@ -1306,17 +1304,17 @@ static RPCHelpMan protx_revoke()
|
||||
CTxDestination feeSourceDest = DecodeDestination(request.params[3].get_str());
|
||||
if (!IsValidDestination(feeSourceDest))
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Dash address: ") + request.params[3].get_str());
|
||||
FundSpecialTx(wallet.get(), tx, ptx, feeSourceDest);
|
||||
FundSpecialTx(*pwallet, tx, ptx, feeSourceDest);
|
||||
} else if (dmn->pdmnState->scriptOperatorPayout != CScript()) {
|
||||
// Using funds from previousely specified operator payout address
|
||||
CTxDestination txDest;
|
||||
ExtractDestination(dmn->pdmnState->scriptOperatorPayout, txDest);
|
||||
FundSpecialTx(wallet.get(), tx, ptx, txDest);
|
||||
FundSpecialTx(*pwallet, tx, ptx, txDest);
|
||||
} else if (dmn->pdmnState->scriptPayout != CScript()) {
|
||||
// Using funds from previousely specified masternode payout address
|
||||
CTxDestination txDest;
|
||||
ExtractDestination(dmn->pdmnState->scriptPayout, txDest);
|
||||
FundSpecialTx(wallet.get(), tx, ptx, txDest);
|
||||
FundSpecialTx(*pwallet, tx, ptx, txDest);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "No payout or fee source addresses found, can't revoke");
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ static RPCHelpMan gobject_prepare()
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*wallet);
|
||||
|
||||
// ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS
|
||||
|
||||
@ -253,7 +253,7 @@ static RPCHelpMan gobject_list_prepared()
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*wallet);
|
||||
|
||||
int64_t nCount = request.params.empty() ? 10 : ParseInt64V(request.params[0], "count");
|
||||
if (nCount < 0) {
|
||||
@ -546,7 +546,7 @@ static RPCHelpMan gobject_vote_many()
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'");
|
||||
}
|
||||
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*wallet);
|
||||
|
||||
std::map<uint256, CKeyID> votingKeys;
|
||||
|
||||
@ -600,7 +600,7 @@ static RPCHelpMan gobject_vote_alias()
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'");
|
||||
}
|
||||
|
||||
EnsureWalletIsUnlocked(wallet.get());
|
||||
EnsureWalletIsUnlocked(*wallet);
|
||||
|
||||
uint256 proTxHash(ParseHashV(request.params[3], "protx-hash"));
|
||||
auto dmn = node.dmnman->GetListAtChainTip().GetValidMN(proTxHash);
|
||||
|
@ -579,8 +579,10 @@ static RPCHelpMan getblocktemplate()
|
||||
},
|
||||
"\"template_request\""},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
RPCResult{"If the proposal was accepted with mode=='proposal'", RPCResult::Type::NONE, "", ""},
|
||||
RPCResult{"If the proposal was not accepted with mode=='proposal'", RPCResult::Type::STR, "", "According to BIP22"},
|
||||
RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
{RPCResult::Type::ARR, "capabilities", "specific client side supported features",
|
||||
{
|
||||
@ -655,6 +657,7 @@ static RPCHelpMan getblocktemplate()
|
||||
{RPCResult::Type::BOOL, "superblocks_enabled", "true, if superblock payments are enabled"},
|
||||
{RPCResult::Type::STR_HEX, "coinbase_payload", "coinbase transaction payload data encoded in hexadecimal"},
|
||||
}},
|
||||
},
|
||||
RPCExamples{
|
||||
HelpExampleCli("getblocktemplate", "")
|
||||
+ HelpExampleRpc("getblocktemplate", "")
|
||||
@ -1019,7 +1022,10 @@ static RPCHelpMan submitblock()
|
||||
{"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block data to submit"},
|
||||
{"dummy", RPCArg::Type::STR, /* default */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."},
|
||||
},
|
||||
RPCResult{RPCResult::Type::NONE, "", "Returns JSON Null when valid, a string according to BIP22 otherwise"},
|
||||
{
|
||||
RPCResult{"If the block was accepted", RPCResult::Type::NONE, "", ""},
|
||||
RPCResult{"Otherwise", RPCResult::Type::STR, "", "According to BIP22"},
|
||||
},
|
||||
RPCExamples{
|
||||
HelpExampleCli("submitblock", "\"mydata\"")
|
||||
+ HelpExampleRpc("submitblock", "\"mydata\"")
|
||||
|
@ -83,11 +83,9 @@ class VersionBitsTester
|
||||
TestNeverActiveConditionChecker checker_never[CHECKERS];
|
||||
|
||||
// Test counter (to identify failures)
|
||||
int num;
|
||||
int num{1000};
|
||||
|
||||
public:
|
||||
VersionBitsTester() : num(1000) {}
|
||||
|
||||
VersionBitsTester& Reset() {
|
||||
// Have each group of tests be counted by the 1000s part, starting at 1000
|
||||
num = num - (num % 1000) + 1000;
|
||||
@ -259,39 +257,6 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(versionbits_sanity)
|
||||
{
|
||||
// Sanity checks of version bit deployments
|
||||
const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
|
||||
const Consensus::Params &mainnetParams = chainParams->GetConsensus();
|
||||
for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
|
||||
uint32_t bitmask = g_versionbitscache.Mask(mainnetParams, static_cast<Consensus::DeploymentPos>(i));
|
||||
// Make sure that no deployment tries to set an invalid bit.
|
||||
BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask);
|
||||
|
||||
// Check min_activation_height is on a retarget boundary
|
||||
BOOST_CHECK_EQUAL(mainnetParams.vDeployments[i].min_activation_height % mainnetParams.nMinerConfirmationWindow, 0);
|
||||
// Check min_activation_height is 0 for ALWAYS_ACTIVE and never active deployments
|
||||
if (mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE || mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) {
|
||||
BOOST_CHECK_EQUAL(mainnetParams.vDeployments[i].min_activation_height, 0);
|
||||
}
|
||||
|
||||
// Verify that the deployment windows of different deployment using the
|
||||
// same bit are disjoint.
|
||||
// This test may need modification at such time as a new deployment
|
||||
// is proposed that reuses the bit of an activated soft fork, before the
|
||||
// end time of that soft fork. (Alternatively, the end time of that
|
||||
// activated soft fork could be later changed to be earlier to avoid
|
||||
// overlap.)
|
||||
for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) {
|
||||
if (g_versionbitscache.Mask(mainnetParams, static_cast<Consensus::DeploymentPos>(j)) == bitmask) {
|
||||
BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout ||
|
||||
mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that ComputeBlockVersion will set the appropriate bit correctly */
|
||||
static void check_computeblockversion(const Consensus::Params& params, Consensus::DeploymentPos dep)
|
||||
{
|
||||
@ -313,16 +278,25 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus
|
||||
BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(nullptr, params), VERSIONBITS_TOP_BITS);
|
||||
|
||||
// always/never active deployments shouldn't need to be tested further
|
||||
if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE) return;
|
||||
if (nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) return;
|
||||
if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE ||
|
||||
nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(min_activation_height, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_REQUIRE(nStartTime < nTimeout);
|
||||
BOOST_REQUIRE(nStartTime >= 0);
|
||||
BOOST_REQUIRE(nTimeout <= std::numeric_limits<uint32_t>::max() || nTimeout == Consensus::BIP9Deployment::NO_TIMEOUT);
|
||||
BOOST_REQUIRE(0 <= bit && bit < 32);
|
||||
// Make sure that no deployment tries to set an invalid bit.
|
||||
BOOST_REQUIRE(((1 << bit) & VERSIONBITS_TOP_MASK) == 0);
|
||||
BOOST_REQUIRE(min_activation_height >= 0);
|
||||
BOOST_REQUIRE_EQUAL(min_activation_height % window_size, 0);
|
||||
// Check min_activation_height is on a retarget boundary
|
||||
BOOST_REQUIRE_EQUAL(min_activation_height % window_size, 0U);
|
||||
|
||||
const uint32_t bitmask{g_versionbitscache.Mask(params, dep)};
|
||||
BOOST_CHECK_EQUAL(bitmask, uint32_t{1} << bit);
|
||||
|
||||
// In the first chain, test that the bit is set by CBV until it has failed.
|
||||
// In the second chain, test the bit is set by CBV while STARTED and
|
||||
@ -453,8 +427,19 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
|
||||
if (chain_name == CBaseChainParams::DEVNET) gArgs.SoftSetBoolArg("-devnet", true);
|
||||
const auto chainParams = CreateChainParams(*m_node.args, chain_name);
|
||||
if (chain_name == CBaseChainParams::DEVNET) gArgs.ForceRemoveArg("devnet");
|
||||
|
||||
uint32_t chain_all_vbits{0};
|
||||
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
|
||||
check_computeblockversion(chainParams->GetConsensus(), static_cast<Consensus::DeploymentPos>(i));
|
||||
const auto dep = static_cast<Consensus::DeploymentPos>(i);
|
||||
// Check that no bits are re-used (within the same chain). This is
|
||||
// disallowed because the transition to FAILED (on timeout) does
|
||||
// not take precedence over STARTED/LOCKED_IN. So all softforks on
|
||||
// the same bit might overlap, even when non-overlapping start-end
|
||||
// times are picked.
|
||||
const uint32_t dep_mask{g_versionbitscache.Mask(chainParams->GetConsensus(), dep)};
|
||||
BOOST_CHECK(!(chain_all_vbits & dep_mask));
|
||||
chain_all_vbits |= dep_mask;
|
||||
check_computeblockversion(chainParams->GetConsensus(), dep);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
|
||||
argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
||||
argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
|
||||
#if HAVE_SYSTEM
|
||||
argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID and %w is replaced by wallet name. %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
||||
argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID, %w is replaced by wallet name, %b is replaced by the hash of the block including the transaction (set to 'unconfirmed' if the transaction is not included) and %h is replaced by the block height (-1 if not included). %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
||||
#endif
|
||||
|
||||
argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
|
||||
|
@ -96,15 +96,14 @@ RPCHelpMan importprivkey()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
|
||||
}
|
||||
|
||||
EnsureLegacyScriptPubKeyMan(*wallet, true);
|
||||
EnsureLegacyScriptPubKeyMan(*pwallet, true);
|
||||
|
||||
WalletBatch batch(pwallet->GetDatabase());
|
||||
WalletRescanReserver reserver(*pwallet);
|
||||
@ -112,7 +111,7 @@ RPCHelpMan importprivkey()
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
std::string strSecret = request.params[0].get_str();
|
||||
std::string strLabel = "";
|
||||
@ -177,9 +176,8 @@ RPCHelpMan abortrescan()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
|
||||
pwallet->AbortRescan();
|
||||
@ -215,9 +213,9 @@ RPCHelpMan importaddress()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
EnsureLegacyScriptPubKeyMan(*pwallet, true);
|
||||
|
||||
std::string strLabel;
|
||||
@ -300,9 +298,8 @@ RPCHelpMan importprunedfunds()
|
||||
RPCExamples{""},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
CMutableTransaction tx;
|
||||
if (!DecodeHexTx(tx, request.params[0].get_str())) {
|
||||
@ -362,9 +359,8 @@ RPCHelpMan removeprunedfunds()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -409,10 +405,10 @@ RPCHelpMan importpubkey()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
EnsureLegacyScriptPubKeyMan(*wallet, true);
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
EnsureLegacyScriptPubKeyMan(*pwallet, true);
|
||||
|
||||
std::string strLabel;
|
||||
if (!request.params[1].isNull())
|
||||
@ -488,10 +484,10 @@ RPCHelpMan importwallet()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
EnsureLegacyScriptPubKeyMan(*wallet, true);
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
EnsureLegacyScriptPubKeyMan(*pwallet, true);
|
||||
|
||||
if (pwallet->chain().havePruned()) {
|
||||
// Exit early and print an error.
|
||||
@ -511,7 +507,7 @@ RPCHelpMan importwallet()
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
fsbridge::ifstream file;
|
||||
file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
|
||||
@ -650,9 +646,8 @@ RPCHelpMan importelectrumwallet()
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
if (pwallet->chain().havePruned())
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
|
||||
@ -661,11 +656,11 @@ RPCHelpMan importelectrumwallet()
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
|
||||
}
|
||||
|
||||
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*wallet);
|
||||
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
|
||||
|
||||
LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
fsbridge::ifstream file;
|
||||
std::string strFileName = request.params[0].get_str();
|
||||
@ -828,15 +823,14 @@ RPCHelpMan dumpprivkey()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*wallet);
|
||||
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
|
||||
|
||||
LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
std::string strAddress = request.params[0].get_str();
|
||||
CTxDestination dest = DecodeDestination(strAddress);
|
||||
@ -875,15 +869,14 @@ RPCHelpMan dumphdinfo()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*wallet);
|
||||
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
|
||||
CHDChain hdChainCurrent;
|
||||
if (!spk_man.GetHDChain(hdChainCurrent))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "This wallet is not a HD wallet.");
|
||||
@ -941,7 +934,7 @@ RPCHelpMan dumpwallet()
|
||||
|
||||
LOCK(wallet.cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(&wallet);
|
||||
EnsureWalletIsUnlocked(wallet);
|
||||
|
||||
fs::path filepath = request.params[0].get_str();
|
||||
filepath = fs::absolute(filepath);
|
||||
@ -1364,7 +1357,7 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
||||
return warnings;
|
||||
}
|
||||
|
||||
static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
static UniValue ProcessImport(CWallet& wallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
||||
{
|
||||
UniValue warnings(UniValue::VARR);
|
||||
UniValue result(UniValue::VOBJ);
|
||||
@ -1379,7 +1372,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
|
||||
const bool add_keypool = data.exists("keypool") ? data["keypool"].get_bool() : false;
|
||||
|
||||
// Add to keypool only works with privkeys disabled
|
||||
if (add_keypool && !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||
if (add_keypool && !wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Keys can only be imported to the keypool when private keys are disabled");
|
||||
}
|
||||
|
||||
@ -1401,29 +1394,29 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
|
||||
}
|
||||
|
||||
// If private keys are disabled, abort if private keys are being imported
|
||||
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !privkey_map.empty()) {
|
||||
if (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !privkey_map.empty()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
|
||||
}
|
||||
|
||||
// Check whether we have any work to do
|
||||
for (const CScript& script : script_pub_keys) {
|
||||
if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
|
||||
if (wallet.IsMine(script) & ISMINE_SPENDABLE) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script) + "\")");
|
||||
}
|
||||
}
|
||||
|
||||
// All good, time to import
|
||||
pwallet->MarkDirty();
|
||||
if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
|
||||
wallet.MarkDirty();
|
||||
if (!wallet.ImportScripts(import_data.import_scripts, timestamp)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
|
||||
}
|
||||
if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
|
||||
if (!wallet.ImportPrivKeys(privkey_map, timestamp)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
||||
}
|
||||
if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
|
||||
if (!wallet.ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||
}
|
||||
if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) {
|
||||
if (!wallet.ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||
}
|
||||
|
||||
@ -1530,17 +1523,14 @@ RPCHelpMan importmulti()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& mainRequest) -> UniValue
|
||||
{
|
||||
|
||||
|
||||
RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
|
||||
|
||||
const UniValue& requests = mainRequest.params[0];
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(mainRequest);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(mainRequest);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
EnsureLegacyScriptPubKeyMan(*wallet, true);
|
||||
EnsureLegacyScriptPubKeyMan(*pwallet, true);
|
||||
|
||||
//Default options
|
||||
bool fRescan = true;
|
||||
@ -1564,7 +1554,7 @@ RPCHelpMan importmulti()
|
||||
UniValue response(UniValue::VARR);
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
// Verify all timestamps are present before importing any keys.
|
||||
CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(), FoundBlock().time(nLowestTimestamp).mtpTime(now)));
|
||||
@ -1576,7 +1566,7 @@ RPCHelpMan importmulti()
|
||||
|
||||
for (const UniValue& data : requests.getValues()) {
|
||||
const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);
|
||||
const UniValue result = ProcessImport(pwallet, data, timestamp);
|
||||
const UniValue result = ProcessImport(*pwallet, data, timestamp);
|
||||
response.push_back(result);
|
||||
|
||||
if (!fRescan) {
|
||||
@ -1643,7 +1633,7 @@ RPCHelpMan importmulti()
|
||||
};
|
||||
}
|
||||
|
||||
static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
||||
{
|
||||
UniValue warnings(UniValue::VARR);
|
||||
UniValue result(UniValue::VOBJ);
|
||||
@ -1712,7 +1702,7 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue&
|
||||
}
|
||||
|
||||
// If the wallet disabled private keys, abort if private keys exist
|
||||
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !keys.keys.empty()) {
|
||||
if (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !keys.keys.empty()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
|
||||
}
|
||||
|
||||
@ -1736,7 +1726,7 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue&
|
||||
}
|
||||
|
||||
// If private keys are enabled, check some things.
|
||||
if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||
if (!wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||
if (keys.keys.empty()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import descriptor without private keys to a wallet with private keys enabled");
|
||||
}
|
||||
@ -1748,7 +1738,7 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue&
|
||||
WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
|
||||
|
||||
// Check if the wallet already contains the descriptor
|
||||
auto existing_spk_manager = pwallet->GetDescriptorScriptPubKeyMan(w_desc);
|
||||
auto existing_spk_manager = wallet.GetDescriptorScriptPubKeyMan(w_desc);
|
||||
if (existing_spk_manager) {
|
||||
if (!existing_spk_manager->CanUpdateToWalletDescriptor(w_desc, error)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, error);
|
||||
@ -1756,7 +1746,7 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue&
|
||||
}
|
||||
|
||||
// Add descriptor to the wallet
|
||||
auto spk_manager = pwallet->AddWalletDescriptor(w_desc, keys, label, internal);
|
||||
auto spk_manager = wallet.AddWalletDescriptor(w_desc, keys, label, internal);
|
||||
if (spk_manager == nullptr) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Could not add descriptor '%s'", descriptor));
|
||||
}
|
||||
@ -1766,11 +1756,11 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue&
|
||||
if (!w_desc.descriptor->GetOutputType()) {
|
||||
warnings.push_back("Unknown output type, cannot set descriptor to active.");
|
||||
} else {
|
||||
pwallet->AddActiveScriptPubKeyMan(spk_manager->GetID(), internal);
|
||||
wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), internal);
|
||||
}
|
||||
} else {
|
||||
if (w_desc.descriptor->GetOutputType()) {
|
||||
pwallet->DeactivateScriptPubKeyMan(spk_manager->GetID(), internal);
|
||||
wallet.DeactivateScriptPubKeyMan(spk_manager->GetID(), internal);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1836,10 +1826,8 @@ RPCHelpMan importdescriptors() {
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& main_request) -> UniValue
|
||||
{
|
||||
// Acquire the wallet
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(main_request);
|
||||
if (!wallet) return NullUniValue;
|
||||
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(main_request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure wallet is a descriptor wallet
|
||||
if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
|
||||
@ -1861,7 +1849,7 @@ RPCHelpMan importdescriptors() {
|
||||
UniValue response(UniValue::VARR);
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(), FoundBlock().time(lowest_timestamp).mtpTime(now)));
|
||||
|
||||
@ -1869,7 +1857,7 @@ RPCHelpMan importdescriptors() {
|
||||
for (const UniValue& request : requests.getValues()) {
|
||||
// This throws an error if "timestamp" doesn't exist
|
||||
const int64_t timestamp = std::max(GetImportTimestamp(request, now), minimum_timestamp);
|
||||
const UniValue result = ProcessDescriptorImport(pwallet, request, timestamp);
|
||||
const UniValue result = ProcessDescriptorImport(*pwallet, request, timestamp);
|
||||
response.push_back(result);
|
||||
|
||||
if (lowest_timestamp > timestamp ) {
|
||||
|
@ -54,8 +54,8 @@ static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
|
||||
|
||||
static const uint32_t WALLET_DASH_KB_TO_DUFF_B = COIN / 1000; // 1 duff / B = 0.00001 DASH / kB
|
||||
|
||||
static inline bool GetAvoidReuseFlag(const CWallet* const pwallet, const UniValue& param) {
|
||||
bool can_avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
|
||||
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) {
|
||||
@ -70,11 +70,11 @@ static inline bool GetAvoidReuseFlag(const CWallet* const pwallet, const UniValu
|
||||
* We default to true for watchonly wallets if include_watchonly isn't
|
||||
* explicitly set.
|
||||
*/
|
||||
static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& pwallet)
|
||||
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 pwallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
|
||||
return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
|
||||
}
|
||||
|
||||
// otherwise return whatever include_watchonly was set to
|
||||
@ -124,9 +124,9 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques
|
||||
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
|
||||
}
|
||||
|
||||
void EnsureWalletIsUnlocked(const CWallet* pwallet)
|
||||
void EnsureWalletIsUnlocked(const CWallet& wallet)
|
||||
{
|
||||
if (pwallet->IsLocked()) {
|
||||
if (wallet.IsLocked()) {
|
||||
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
|
||||
}
|
||||
}
|
||||
@ -203,13 +203,13 @@ static std::string LabelFromValue(const UniValue& value)
|
||||
/**
|
||||
* Update coin control with fee estimation based on the given parameters
|
||||
*
|
||||
* @param[in] pwallet Wallet pointer
|
||||
* @param[in] wallet Wallet reference
|
||||
* @param[in,out] cc Coin control which is to be updated
|
||||
* @param[in] estimate_mode String value (e.g. "ECONOMICAL")
|
||||
* @param[in] estimate_param Parameter (blocks to confirm, explicit fee rate, etc)
|
||||
* @throws a JSONRPCError if estimate_mode is unknown, or if estimate_param is missing when required
|
||||
*/
|
||||
static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const UniValue& estimate_mode, const UniValue& estimate_param)
|
||||
static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const UniValue& estimate_mode, const UniValue& estimate_param)
|
||||
{
|
||||
if (!estimate_mode.isNull()) {
|
||||
if (!FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) {
|
||||
@ -230,7 +230,7 @@ static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const U
|
||||
cc.m_feerate = CFeeRate(fee_rate);
|
||||
|
||||
} else if (!estimate_param.isNull()) {
|
||||
cc.m_confirm_target = ParseConfirmTarget(estimate_param, pwallet->chain().estimateMaxBlocks());
|
||||
cc.m_confirm_target = ParseConfirmTarget(estimate_param, wallet.chain().estimateMaxBlocks());
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,9 +252,8 @@ RPCHelpMan getnewaddress()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -292,9 +291,8 @@ RPCHelpMan getrawchangeaddress()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -328,9 +326,8 @@ static RPCHelpMan setlabel()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -382,9 +379,9 @@ void ParseRecipients(const UniValue& address_amounts, const UniValue& subtract_f
|
||||
}
|
||||
}
|
||||
|
||||
UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std::vector<CRecipient> &recipients, mapValue_t map_value, bool verbose)
|
||||
UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vector<CRecipient> &recipients, mapValue_t map_value, bool verbose)
|
||||
{
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(wallet);
|
||||
|
||||
if (coin_control.IsUsingCoinJoin()) {
|
||||
map_value["DS"] = "1";
|
||||
@ -396,11 +393,11 @@ UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std
|
||||
bilingual_str error;
|
||||
CTransactionRef tx;
|
||||
FeeCalculation fee_calc_out;
|
||||
bool fCreated = pwallet->CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
|
||||
bool fCreated = wallet.CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, !wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
|
||||
if (!fCreated) {
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
|
||||
}
|
||||
pwallet->CommitTransaction(tx, std::move(map_value), {} /* orderForm */);
|
||||
wallet.CommitTransaction(tx, std::move(map_value), {} /* orderForm */);
|
||||
if (verbose) {
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
entry.pushKV("txid", tx->GetHash().GetHex());
|
||||
@ -456,9 +453,8 @@ static RPCHelpMan sendtoaddress()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -484,14 +480,13 @@ static RPCHelpMan sendtoaddress()
|
||||
coin_control.UseCoinJoin(request.params[6].get_bool());
|
||||
}
|
||||
|
||||
|
||||
coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(pwallet, request.params[9]);
|
||||
coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(*pwallet, request.params[9]);
|
||||
// We also enable partial spend avoidance if reuse avoidance is set.
|
||||
coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
|
||||
|
||||
SetFeeEstimateMode(pwallet, coin_control, request.params[8], request.params[7]);
|
||||
SetFeeEstimateMode(*pwallet, coin_control, request.params[8], request.params[7]);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
UniValue address_amounts(UniValue::VOBJ);
|
||||
const std::string address = request.params[0].get_str();
|
||||
@ -505,7 +500,7 @@ static RPCHelpMan sendtoaddress()
|
||||
ParseRecipients(address_amounts, subtractFeeFromAmount, recipients);
|
||||
bool verbose = request.params[10].isNull() ? false: request.params[10].get_bool();
|
||||
|
||||
return SendMoney(pwallet, coin_control, recipients, mapValue, verbose);
|
||||
return SendMoney(*pwallet, coin_control, recipients, mapValue, verbose);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -554,9 +549,8 @@ static RPCHelpMan listaddressgroupings()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -609,9 +603,8 @@ static RPCHelpMan listaddressbalances()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -657,13 +650,12 @@ static RPCHelpMan signmessage()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
std::string strAddress = request.params[0].get_str();
|
||||
std::string strMessage = request.params[1].get_str();
|
||||
@ -763,9 +755,8 @@ static RPCHelpMan getreceivedbyaddress()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -803,9 +794,8 @@ static RPCHelpMan getreceivedbylabel()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -845,9 +835,8 @@ static RPCHelpMan getbalance()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -873,7 +862,7 @@ static RPCHelpMan getbalance()
|
||||
|
||||
bool include_watchonly = ParseIncludeWatchonly(request.params[3], *pwallet);
|
||||
|
||||
bool avoid_reuse = GetAvoidReuseFlag(pwallet, request.params[4]);
|
||||
bool avoid_reuse = GetAvoidReuseFlag(*pwallet, request.params[4]);
|
||||
const auto bal = pwallet->GetBalance(min_depth, avoid_reuse, fAddLocked);
|
||||
|
||||
return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
|
||||
@ -890,10 +879,8 @@ static RPCHelpMan getunconfirmedbalance()
|
||||
RPCExamples{""},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -961,9 +948,8 @@ static RPCHelpMan sendmany()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -991,13 +977,13 @@ static RPCHelpMan sendmany()
|
||||
coin_control.UseCoinJoin(request.params[7].get_bool());
|
||||
}
|
||||
|
||||
SetFeeEstimateMode(pwallet, coin_control, request.params[9], request.params[8]);
|
||||
SetFeeEstimateMode(*pwallet, coin_control, request.params[9], request.params[8]);
|
||||
|
||||
std::vector<CRecipient> recipients;
|
||||
ParseRecipients(sendTo, subtractFeeFromAmount, recipients);
|
||||
bool verbose = request.params[10].isNull() ? false : request.params[10].get_bool();
|
||||
|
||||
return SendMoney(pwallet, coin_control, recipients, std::move(mapValue), verbose);
|
||||
return SendMoney(*pwallet, coin_control, recipients, std::move(mapValue), verbose);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -1035,9 +1021,8 @@ RPCHelpMan addmultisigaddress()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
|
||||
|
||||
@ -1089,7 +1074,7 @@ struct tallyitem
|
||||
}
|
||||
};
|
||||
|
||||
static UniValue ListReceived(const CWallet * const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
static UniValue ListReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
||||
{
|
||||
// Minimum confirmations
|
||||
int nMinDepth = 1;
|
||||
@ -1105,7 +1090,8 @@ static UniValue ListReceived(const CWallet * const pwallet, const UniValue& para
|
||||
fIncludeEmpty = params[2].get_bool();
|
||||
|
||||
isminefilter filter = ISMINE_SPENDABLE;
|
||||
if (ParseIncludeWatchonly(params[3], *pwallet)) {
|
||||
|
||||
if (ParseIncludeWatchonly(params[3], wallet)) {
|
||||
filter |= ISMINE_WATCH_ONLY;
|
||||
}
|
||||
|
||||
@ -1121,10 +1107,10 @@ static UniValue ListReceived(const CWallet * const pwallet, const UniValue& para
|
||||
|
||||
// Tally
|
||||
std::map<CTxDestination, tallyitem> mapTally;
|
||||
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
|
||||
for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) {
|
||||
const CWalletTx& wtx = pairWtx.second;
|
||||
|
||||
if (wtx.IsCoinBase() || !pwallet->chain().checkFinalTx(*wtx.tx))
|
||||
if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx))
|
||||
continue;
|
||||
|
||||
int nDepth = wtx.GetDepthInMainChain();
|
||||
@ -1141,7 +1127,7 @@ static UniValue ListReceived(const CWallet * const pwallet, const UniValue& para
|
||||
continue;
|
||||
}
|
||||
|
||||
isminefilter mine = pwallet->IsMine(address);
|
||||
isminefilter mine = wallet.IsMine(address);
|
||||
if(!(mine & filter))
|
||||
continue;
|
||||
|
||||
@ -1160,11 +1146,11 @@ static UniValue ListReceived(const CWallet * const pwallet, const UniValue& para
|
||||
|
||||
// Create m_address_book iterator
|
||||
// If we aren't filtering, go from begin() to end()
|
||||
auto start = pwallet->m_address_book.begin();
|
||||
auto end = pwallet->m_address_book.end();
|
||||
auto start = wallet.m_address_book.begin();
|
||||
auto end = wallet.m_address_book.end();
|
||||
// If we are filtering, find() the applicable entry
|
||||
if (has_filtered_address) {
|
||||
start = pwallet->m_address_book.find(filtered_address);
|
||||
start = wallet.m_address_book.find(filtered_address);
|
||||
if (start != end) {
|
||||
end = std::next(start);
|
||||
}
|
||||
@ -1179,7 +1165,7 @@ static UniValue ListReceived(const CWallet * const pwallet, const UniValue& para
|
||||
if (it == mapTally.end() && !fIncludeEmpty)
|
||||
continue;
|
||||
|
||||
isminefilter mine = pwallet->IsMine(address);
|
||||
isminefilter mine = wallet.IsMine(address);
|
||||
if(!(mine & filter))
|
||||
continue;
|
||||
|
||||
@ -1279,9 +1265,8 @@ static RPCHelpMan listreceivedbyaddress()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -1289,7 +1274,7 @@ static RPCHelpMan listreceivedbyaddress()
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
return ListReceived(pwallet, request.params, false);
|
||||
return ListReceived(*pwallet, request.params, false);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -1323,9 +1308,8 @@ static RPCHelpMan listreceivedbylabel()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -1333,7 +1317,7 @@ static RPCHelpMan listreceivedbylabel()
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
return ListReceived(pwallet, request.params, true);
|
||||
return ListReceived(*pwallet, request.params, true);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -1356,7 +1340,7 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
|
||||
* @param filter_ismine The "is mine" filter flags.
|
||||
* @param filter_label Optional label string to filter incoming transactions.
|
||||
*/
|
||||
static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
||||
{
|
||||
CAmount nFee;
|
||||
std::list<COutputEntry> listReceived;
|
||||
@ -1372,21 +1356,21 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
||||
for (const COutputEntry& s : listSent)
|
||||
{
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
if (involvesWatchonly || (pwallet->IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
|
||||
if (involvesWatchonly || (wallet.IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
|
||||
entry.pushKV("involvesWatchonly", true);
|
||||
}
|
||||
MaybePushAddress(entry, s.destination);
|
||||
std::map<std::string, std::string>::const_iterator it = wtx.mapValue.find("DS");
|
||||
entry.pushKV("category", (it != wtx.mapValue.end() && it->second == "1") ? "coinjoin" : "send");
|
||||
entry.pushKV("amount", ValueFromAmount(-s.amount));
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(s.destination);
|
||||
const auto* address_book_entry = wallet.FindAddressBookEntry(s.destination);
|
||||
if (address_book_entry) {
|
||||
entry.pushKV("label", address_book_entry->GetLabel());
|
||||
}
|
||||
entry.pushKV("vout", s.vout);
|
||||
entry.pushKV("fee", ValueFromAmount(-nFee));
|
||||
if (fLong)
|
||||
WalletTxToJSON(pwallet->chain(), wtx, entry);
|
||||
WalletTxToJSON(wallet.chain(), wtx, entry);
|
||||
entry.pushKV("abandoned", wtx.isAbandoned());
|
||||
ret.push_back(entry);
|
||||
}
|
||||
@ -1398,7 +1382,7 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
||||
for (const COutputEntry& r : listReceived)
|
||||
{
|
||||
std::string label;
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(r.destination);
|
||||
const auto* address_book_entry = wallet.FindAddressBookEntry(r.destination);
|
||||
if (address_book_entry) {
|
||||
label = address_book_entry->GetLabel();
|
||||
}
|
||||
@ -1406,7 +1390,7 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
||||
continue;
|
||||
}
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
if (involvesWatchonly || (pwallet->IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
|
||||
if (involvesWatchonly || (wallet.IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
|
||||
entry.pushKV("involvesWatchonly", true);
|
||||
}
|
||||
MaybePushAddress(entry, r.destination);
|
||||
@ -1429,7 +1413,7 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
||||
}
|
||||
entry.pushKV("vout", r.vout);
|
||||
if (fLong)
|
||||
WalletTxToJSON(pwallet->chain(), wtx, entry);
|
||||
WalletTxToJSON(wallet.chain(), wtx, entry);
|
||||
ret.push_back(entry);
|
||||
}
|
||||
}
|
||||
@ -1508,9 +1492,8 @@ static RPCHelpMan listtransactions()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -1551,7 +1534,7 @@ static RPCHelpMan listtransactions()
|
||||
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
|
||||
{
|
||||
CWalletTx *const pwtx = (*it).second;
|
||||
ListTransactions(pwallet, *pwtx, 0, true, ret, filter, filter_label);
|
||||
ListTransactions(*pwallet, *pwtx, 0, true, ret, filter, filter_label);
|
||||
if ((int)ret.size() >= (nCount+nFrom)) break;
|
||||
}
|
||||
}
|
||||
@ -1672,7 +1655,7 @@ static RPCHelpMan listsinceblock()
|
||||
const CWalletTx& tx = pairWtx.second;
|
||||
|
||||
if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
|
||||
ListTransactions(&wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
|
||||
ListTransactions(wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1689,7 +1672,7 @@ static RPCHelpMan listsinceblock()
|
||||
if (it != wallet.mapWallet.end()) {
|
||||
// We want all transactions regardless of confirmation count to appear here,
|
||||
// even negative confirmation ones, hence the big negative.
|
||||
ListTransactions(&wallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
|
||||
ListTransactions(wallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
|
||||
}
|
||||
}
|
||||
blockId = block.hashPrevBlock;
|
||||
@ -1764,9 +1747,8 @@ static RPCHelpMan gettransaction()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -1803,7 +1785,7 @@ static RPCHelpMan gettransaction()
|
||||
WalletTxToJSON(pwallet->chain(), wtx, entry);
|
||||
|
||||
UniValue details(UniValue::VARR);
|
||||
ListTransactions(pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
|
||||
ListTransactions(*pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
|
||||
entry.pushKV("details", details);
|
||||
|
||||
std::string strHex = EncodeHexTx(*wtx.tx);
|
||||
@ -1838,9 +1820,8 @@ static RPCHelpMan abandontransaction()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -1877,9 +1858,8 @@ static RPCHelpMan backupwallet()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -1913,9 +1893,8 @@ static RPCHelpMan keypoolrefill()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
if (pwallet->IsLegacy() && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
|
||||
@ -1931,7 +1910,7 @@ static RPCHelpMan keypoolrefill()
|
||||
kpSize = (unsigned int)request.params[0].get_int();
|
||||
}
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
pwallet->TopUpKeyPool(kpSize);
|
||||
|
||||
if (pwallet->GetKeyPoolSize() < (pwallet->IsHDEnabled() ? kpSize * 2 : kpSize)) {
|
||||
@ -2068,9 +2047,8 @@ static RPCHelpMan walletpassphrasechange()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -2122,9 +2100,8 @@ static RPCHelpMan walletlock()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -2167,9 +2144,8 @@ static RPCHelpMan encryptwallet()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -2241,9 +2217,8 @@ static RPCHelpMan lockunspent()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -2356,9 +2331,8 @@ static RPCHelpMan listlockunspent()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -2397,9 +2371,8 @@ static RPCHelpMan settxfee()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -2603,9 +2576,8 @@ static RPCHelpMan getwalletinfo()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
@ -2938,9 +2910,8 @@ static RPCHelpMan setwalletflag()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
|
||||
std::string flag_str = request.params[0].get_str();
|
||||
@ -3243,9 +3214,8 @@ static RPCHelpMan listunspent()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
int nMinDepth = 1;
|
||||
if (!request.params[0].isNull()) {
|
||||
@ -3405,11 +3375,11 @@ static RPCHelpMan listunspent()
|
||||
};
|
||||
}
|
||||
|
||||
void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, UniValue options, CCoinControl& coinControl)
|
||||
void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, UniValue options, CCoinControl& coinControl)
|
||||
{
|
||||
// Make sure the results are valid at least up to the most recent block
|
||||
// the user could have gotten from another RPC command prior to now
|
||||
pwallet->BlockUntilSyncedToCurrentChain();
|
||||
wallet.BlockUntilSyncedToCurrentChain();
|
||||
|
||||
change_position = -1;
|
||||
bool lockUnspents = false;
|
||||
@ -3467,7 +3437,7 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
|
||||
}
|
||||
|
||||
const UniValue include_watching_option = options.exists("include_watching") ? options["include_watching"] : options["includeWatching"];
|
||||
coinControl.fAllowWatchOnly = ParseIncludeWatchonly(include_watching_option, *pwallet);
|
||||
coinControl.fAllowWatchOnly = ParseIncludeWatchonly(include_watching_option, wallet);
|
||||
|
||||
if (options.exists("lockUnspents") || options.exists("lock_unspents")) {
|
||||
lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
|
||||
@ -3491,12 +3461,12 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
|
||||
if (options.exists("subtractFeeFromOutputs") || options.exists("subtract_fee_from_outputs") )
|
||||
subtractFeeFromOutputs = (options.exists("subtract_fee_from_outputs") ? options["subtract_fee_from_outputs"] : options["subtractFeeFromOutputs"]).get_array();
|
||||
|
||||
SetFeeEstimateMode(pwallet, coinControl, options["estimate_mode"], options["conf_target"]);
|
||||
SetFeeEstimateMode(wallet, coinControl, options["estimate_mode"], options["conf_target"]);
|
||||
|
||||
}
|
||||
} else {
|
||||
// if options is null and not a bool
|
||||
coinControl.fAllowWatchOnly = ParseIncludeWatchonly(NullUniValue, *pwallet);
|
||||
coinControl.fAllowWatchOnly = ParseIncludeWatchonly(NullUniValue, wallet);
|
||||
}
|
||||
|
||||
if (tx.vout.size() == 0)
|
||||
@ -3518,7 +3488,7 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
|
||||
|
||||
bilingual_str error;
|
||||
|
||||
if (!pwallet->FundTransaction(tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
|
||||
if (!wallet.FundTransaction(tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, error.original);
|
||||
}
|
||||
}
|
||||
@ -3586,12 +3556,10 @@ static RPCHelpMan fundrawtransaction()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
|
||||
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
// parse hex string from parameter
|
||||
CMutableTransaction tx;
|
||||
@ -3604,7 +3572,7 @@ static RPCHelpMan fundrawtransaction()
|
||||
CCoinControl coin_control;
|
||||
// Automatically select (additional) coins. Can be overridden by options.add_inputs.
|
||||
coin_control.m_add_inputs = true;
|
||||
FundTransaction(pwallet, tx, fee, change_position, request.params[1], coin_control);
|
||||
FundTransaction(*pwallet, tx, fee, change_position, request.params[1], coin_control);
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("hex", EncodeHexTx(CTransaction(tx)));
|
||||
@ -3673,9 +3641,8 @@ RPCHelpMan signrawtransactionwithwallet()
|
||||
|
||||
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
CMutableTransaction mtx;
|
||||
if (!DecodeHexTx(mtx, request.params[0].get_str())) {
|
||||
@ -3684,7 +3651,7 @@ RPCHelpMan signrawtransactionwithwallet()
|
||||
|
||||
// Sign the transaction
|
||||
LOCK(pwallet->cs_wallet);
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
// Fetch previous transactions (inputs):
|
||||
std::map<COutPoint, Coin> coins;
|
||||
@ -3731,9 +3698,8 @@ static RPCHelpMan rescanblockchain()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
WalletRescanReserver reserver(*pwallet);
|
||||
if (!reserver.reserve()) {
|
||||
@ -3908,15 +3874,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static UniValue DescribeWalletAddress(const CWallet* const pwallet, const CTxDestination& dest)
|
||||
static UniValue DescribeWalletAddress(const CWallet& wallet, const CTxDestination& dest)
|
||||
{
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
UniValue detail = DescribeAddress(dest);
|
||||
CScript script = GetScriptForDestination(dest);
|
||||
std::unique_ptr<SigningProvider> provider = nullptr;
|
||||
if (pwallet) {
|
||||
provider = pwallet->GetSolvingProvider(script);
|
||||
}
|
||||
provider = wallet.GetSolvingProvider(script);
|
||||
ret.pushKVs(detail);
|
||||
ret.pushKVs(std::visit(DescribeWalletAddressVisitor(provider.get()), dest));
|
||||
return ret;
|
||||
@ -3983,9 +3947,8 @@ RPCHelpMan getaddressinfo()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -4030,7 +3993,7 @@ RPCHelpMan getaddressinfo()
|
||||
|
||||
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
|
||||
|
||||
UniValue detail = DescribeWalletAddress(pwallet, dest);
|
||||
UniValue detail = DescribeWalletAddress(*pwallet, dest);
|
||||
ret.pushKVs(detail);
|
||||
|
||||
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
|
||||
@ -4094,9 +4057,8 @@ static RPCHelpMan getaddressesbylabel()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -4156,9 +4118,8 @@ static RPCHelpMan listlabels()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
const CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
@ -4272,9 +4233,8 @@ static RPCHelpMan send()
|
||||
}, true
|
||||
);
|
||||
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
UniValue options = request.params[3];
|
||||
if (options.exists("feeRate") || options.exists("fee_rate") || options.exists("estimate_mode") || options.exists("conf_target")) {
|
||||
@ -4313,7 +4273,7 @@ static RPCHelpMan send()
|
||||
// Automatically select coins, unless at least one is manually selected. Can
|
||||
// be overriden by options.add_inputs.
|
||||
coin_control.m_add_inputs = rawTx.vin.size() == 0;
|
||||
FundTransaction(pwallet, rawTx, fee, change_position, options, coin_control);
|
||||
FundTransaction(*pwallet, rawTx, fee, change_position, options, coin_control);
|
||||
|
||||
bool add_to_wallet = true;
|
||||
if (options.exists("add_to_wallet")) {
|
||||
@ -4384,9 +4344,8 @@ static RPCHelpMan sethdseed()
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
// TODO: add mnemonic feature to sethdseed or remove it in favour of upgradetohd
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
|
||||
|
||||
@ -4404,7 +4363,7 @@ static RPCHelpMan sethdseed()
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed. The wallet already has a seed");
|
||||
}
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
bool flush_key_pool = true;
|
||||
if (!request.params[0].isNull()) {
|
||||
@ -4612,7 +4571,7 @@ static RPCHelpMan walletcreatefundedpsbt()
|
||||
// Automatically select coins, unless at least one is manually selected. Can
|
||||
// be overridden by options.add_inputs.
|
||||
coin_control.m_add_inputs = rawTx.vin.size() == 0;
|
||||
FundTransaction(&wallet, rawTx, fee, change_position, request.params[3], coin_control);
|
||||
FundTransaction(*pwallet, rawTx, fee, change_position, request.params[3], coin_control);
|
||||
|
||||
// Make a blank psbt
|
||||
PartiallySignedTransaction psbtx{rawTx};
|
||||
@ -4662,13 +4621,12 @@ static RPCHelpMan upgradewallet()
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!wallet) return NullUniValue;
|
||||
CWallet* const pwallet = wallet.get();
|
||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!pwallet) return NullUniValue;
|
||||
|
||||
RPCTypeCheck(request.params, {UniValue::VNUM}, true);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
|
||||
int version = 0;
|
||||
if (!request.params[0].isNull()) {
|
||||
|
@ -33,7 +33,7 @@ Span<const CRPCCommand> GetWalletRPCCommands();
|
||||
*/
|
||||
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
|
||||
|
||||
void EnsureWalletIsUnlocked(const CWallet *);
|
||||
void EnsureWalletIsUnlocked(const CWallet&);
|
||||
WalletContext& EnsureWalletContext(const CoreContext& context);
|
||||
LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false);
|
||||
|
||||
|
@ -938,6 +938,14 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
|
||||
if (!strCmd.empty())
|
||||
{
|
||||
ReplaceAll(strCmd, "%s", hash.GetHex());
|
||||
if (confirm.status == CWalletTx::Status::CONFIRMED)
|
||||
{
|
||||
ReplaceAll(strCmd, "%b", confirm.hashBlock.GetHex());
|
||||
ReplaceAll(strCmd, "%h", ToString(confirm.block_height));
|
||||
} else {
|
||||
ReplaceAll(strCmd, "%b", "unconfirmed");
|
||||
ReplaceAll(strCmd, "%h", "-1");
|
||||
}
|
||||
#ifndef WIN32
|
||||
// Substituting the wallet name isn't currently supported on windows
|
||||
// because windows shell escaping has not been implemented yet:
|
||||
|
@ -8,10 +8,23 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height
|
||||
1351.
|
||||
"""
|
||||
|
||||
from test_framework.blocktools import create_coinbase, create_block, create_transaction
|
||||
from test_framework.messages import CTransaction, msg_block
|
||||
from test_framework.blocktools import (
|
||||
create_block,
|
||||
create_coinbase,
|
||||
create_transaction,
|
||||
)
|
||||
from test_framework.messages import (
|
||||
CTransaction,
|
||||
msg_block,
|
||||
)
|
||||
from test_framework.p2p import P2PInterface
|
||||
from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP, CScriptNum
|
||||
from test_framework.script import (
|
||||
CScript,
|
||||
CScriptNum,
|
||||
OP_1NEGATE,
|
||||
OP_CHECKLOCKTIMEVERIFY,
|
||||
OP_DROP,
|
||||
)
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
@ -24,34 +37,56 @@ from io import BytesIO
|
||||
CLTV_HEIGHT = 1351
|
||||
|
||||
|
||||
def cltv_invalidate(tx):
|
||||
'''Modify the signature in vin 0 of the tx to fail CLTV
|
||||
|
||||
Prepends -1 CLTV DROP in the scriptSig itself.
|
||||
|
||||
TODO: test more ways that transactions using CLTV could be invalid (eg
|
||||
locktime requirements fail, sequence time requirements fail, etc).
|
||||
'''
|
||||
tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] +
|
||||
list(CScript(tx.vin[0].scriptSig)))
|
||||
|
||||
def cltv_validate(node, tx, height):
|
||||
'''Modify the signature in vin 0 of the tx to pass CLTV
|
||||
Prepends <height> CLTV DROP in the scriptSig, and sets
|
||||
the locktime to height'''
|
||||
tx.vin[0].nSequence = 0
|
||||
tx.nLockTime = height
|
||||
# Helper function to modify a transaction by
|
||||
# 1) prepending a given script to the scriptSig of vin 0 and
|
||||
# 2) (optionally) modify the nSequence of vin 0 and the tx's nLockTime
|
||||
def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None):
|
||||
if nsequence is not None:
|
||||
tx.vin[0].nSequence = nsequence
|
||||
tx.nLockTime = nlocktime
|
||||
|
||||
# Need to re-sign, since nSequence and nLockTime changed
|
||||
signed_result = node.signrawtransactionwithwallet(tx.serialize().hex())
|
||||
new_tx = CTransaction()
|
||||
new_tx.deserialize(BytesIO(hex_str_to_bytes(signed_result['hex'])))
|
||||
else:
|
||||
new_tx = tx
|
||||
|
||||
new_tx.vin[0].scriptSig = CScript([CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP] +
|
||||
list(CScript(new_tx.vin[0].scriptSig)))
|
||||
new_tx.vin[0].scriptSig = CScript(prepend_scriptsig + list(CScript(new_tx.vin[0].scriptSig)))
|
||||
return new_tx
|
||||
|
||||
|
||||
def cltv_invalidate(node, tx, failure_reason):
|
||||
# Modify the signature in vin 0 and nSequence/nLockTime of the tx to fail CLTV
|
||||
#
|
||||
# According to BIP65, OP_CHECKLOCKTIMEVERIFY can fail due the following reasons:
|
||||
# 1) the stack is empty
|
||||
# 2) the top item on the stack is less than 0
|
||||
# 3) the lock-time type (height vs. timestamp) of the top stack item and the
|
||||
# nLockTime field are not the same
|
||||
# 4) the top stack item is greater than the transaction's nLockTime field
|
||||
# 5) the nSequence field of the txin is 0xffffffff
|
||||
assert failure_reason in range(5)
|
||||
scheme = [
|
||||
# | Script to prepend to scriptSig | nSequence | nLockTime |
|
||||
# +-------------------------------------------------+------------+--------------+
|
||||
[[OP_CHECKLOCKTIMEVERIFY], None, None],
|
||||
[[OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP], None, None],
|
||||
[[CScriptNum(1000), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 1296688602], # timestamp of genesis block
|
||||
[[CScriptNum(1000), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 500],
|
||||
[[CScriptNum(500), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 500],
|
||||
][failure_reason]
|
||||
|
||||
return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
|
||||
|
||||
|
||||
def cltv_validate(node, tx, height):
|
||||
# Modify the signature in vin 0 and nSequence/nLockTime of the tx to pass CLTV
|
||||
scheme = [[CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, height]
|
||||
|
||||
return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
|
||||
|
||||
|
||||
class BIP65Test(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
@ -66,8 +101,7 @@ class BIP65Test(BitcoinTestFramework):
|
||||
self.rpc_timeout = 480
|
||||
|
||||
def test_cltv_info(self, *, is_active):
|
||||
assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'],
|
||||
{
|
||||
assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'], {
|
||||
"active": is_active,
|
||||
"height": CLTV_HEIGHT,
|
||||
"type": "buried",
|
||||
@ -86,18 +120,22 @@ class BIP65Test(BitcoinTestFramework):
|
||||
self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(CLTV_HEIGHT - 2)]
|
||||
self.nodeaddress = self.nodes[0].getnewaddress()
|
||||
|
||||
self.log.info("Test that an invalid-according-to-CLTV transaction can still appear in a block")
|
||||
self.log.info("Test that invalid-according-to-CLTV transactions can still appear in a block")
|
||||
|
||||
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[0],
|
||||
# create one invalid tx per CLTV failure reason (5 in total) and collect them
|
||||
invalid_ctlv_txs = []
|
||||
for i in range(5):
|
||||
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[i],
|
||||
self.nodeaddress, amount=1.0)
|
||||
cltv_invalidate(spendtx)
|
||||
spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
|
||||
spendtx.rehash()
|
||||
invalid_ctlv_txs.append(spendtx)
|
||||
|
||||
tip = self.nodes[0].getbestblockhash()
|
||||
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
|
||||
block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time)
|
||||
block.nVersion = 3
|
||||
block.vtx.append(spendtx)
|
||||
block.vtx.extend(invalid_ctlv_txs)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.solve()
|
||||
|
||||
@ -118,24 +156,35 @@ class BIP65Test(BitcoinTestFramework):
|
||||
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
|
||||
peer.sync_with_ping()
|
||||
|
||||
self.log.info("Test that invalid-according-to-cltv transactions cannot appear in a block")
|
||||
self.log.info("Test that invalid-according-to-CLTV transactions cannot appear in a block")
|
||||
block.nVersion = 4
|
||||
block.vtx.append(CTransaction()) # dummy tx after coinbase that will be replaced later
|
||||
|
||||
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[1],
|
||||
# create and test one invalid tx per CLTV failure reason (5 in total)
|
||||
for i in range(5):
|
||||
spendtx = create_transaction(self.nodes[0], self.coinbase_txids[10+i],
|
||||
self.nodeaddress, amount=1.0)
|
||||
cltv_invalidate(spendtx)
|
||||
spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
|
||||
spendtx.rehash()
|
||||
|
||||
expected_cltv_reject_reason = [
|
||||
"non-mandatory-script-verify-flag (Operation not valid with the current stack size)",
|
||||
"non-mandatory-script-verify-flag (Negative locktime)",
|
||||
"non-mandatory-script-verify-flag (Locktime requirement not satisfied)",
|
||||
"non-mandatory-script-verify-flag (Locktime requirement not satisfied)",
|
||||
"non-mandatory-script-verify-flag (Locktime requirement not satisfied)",
|
||||
][i]
|
||||
# First we show that this tx is valid except for CLTV by getting it
|
||||
# rejected from the mempool for exactly that reason.
|
||||
assert_raises_rpc_error(-26, 'non-mandatory-script-verify-flag (Negative locktime)', self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
||||
assert_raises_rpc_error(-26, expected_cltv_reject_reason, self.nodes[0].sendrawtransaction, spendtx.serialize().hex(), 0)
|
||||
|
||||
# Now we verify that a block with this transaction is also invalid.
|
||||
block.vtx.append(spendtx)
|
||||
block.vtx[1] = spendtx
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.solve()
|
||||
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputScripts on {} failed with non-mandatory-script-verify-flag (Negative locktime)'.format(block.vtx[-1].hash)]):
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputScripts on {} failed with {}'.format(
|
||||
block.vtx[-1].hash, expected_cltv_reject_reason)]):
|
||||
peer.send_and_ping(msg_block(block))
|
||||
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
|
||||
peer.sync_with_ping()
|
||||
|
@ -19,7 +19,7 @@ from test_framework.util import (
|
||||
FILE_CHAR_START = 32 if os.name == 'nt' else 1
|
||||
FILE_CHAR_END = 128
|
||||
FILE_CHARS_DISALLOWED = '/\\?%*:|"<>' if os.name == 'nt' else '/'
|
||||
|
||||
UNCONFIRMED_HASH_STRING = 'unconfirmed'
|
||||
|
||||
def notify_outputname(walletname, txid):
|
||||
return txid if os.name == 'nt' else '{}_{}'.format(walletname, txid)
|
||||
@ -46,7 +46,7 @@ class NotificationsTest(DashTestFramework):
|
||||
self.extra_args[0].append("-alertnotify=echo > {}".format(os.path.join(self.alertnotify_dir, '%s')))
|
||||
self.extra_args[0].append("-blocknotify=echo > {}".format(os.path.join(self.blocknotify_dir, '%s')))
|
||||
self.extra_args[1].append("-rescan")
|
||||
self.extra_args[1].append("-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))))
|
||||
self.extra_args[1].append("-walletnotify=echo %h_%b > {}".format(os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))))
|
||||
|
||||
# -chainlocknotify on node0, -instantsendnotify on node1
|
||||
self.extra_args[0].append("-chainlocknotify=echo > {}".format(os.path.join(self.chainlocknotify_dir, '%s')))
|
||||
@ -78,12 +78,9 @@ class NotificationsTest(DashTestFramework):
|
||||
self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)
|
||||
|
||||
# directory content should equal the generated transaction hashes
|
||||
txids_rpc = list(map(lambda t: notify_outputname(self.wallet, t['txid']), self.nodes[1].listtransactions("*", block_count)))
|
||||
assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))
|
||||
tx_details = list(map(lambda t: (t['txid'], t['blockheight'], t['blockhash']), self.nodes[1].listtransactions("*", block_count)))
|
||||
self.stop_node(1)
|
||||
|
||||
for tx_file in os.listdir(self.walletnotify_dir):
|
||||
os.remove(os.path.join(self.walletnotify_dir, tx_file))
|
||||
self.expect_wallet_notify(tx_details)
|
||||
|
||||
self.log.info("test -walletnotify after rescan")
|
||||
# restart node to rescan to force wallet notifications
|
||||
@ -94,10 +91,8 @@ class NotificationsTest(DashTestFramework):
|
||||
self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)
|
||||
|
||||
# directory content should equal the generated transaction hashes
|
||||
txids_rpc = list(map(lambda t: notify_outputname(self.wallet, t['txid']), self.nodes[1].listtransactions("*", block_count)))
|
||||
assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))
|
||||
for tx_file in os.listdir(self.walletnotify_dir):
|
||||
os.remove(os.path.join(self.walletnotify_dir, tx_file))
|
||||
tx_details = list(map(lambda t: (t['txid'], t['blockheight'], t['blockhash']), self.nodes[1].listtransactions("*", block_count)))
|
||||
self.expect_wallet_notify(tx_details)
|
||||
|
||||
|
||||
self.log.info("test -chainlocknotify")
|
||||
@ -145,6 +140,29 @@ class NotificationsTest(DashTestFramework):
|
||||
|
||||
# TODO: add test for `-alertnotify` large fork notifications
|
||||
|
||||
def expect_wallet_notify(self, tx_details):
|
||||
self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) >= len(tx_details), timeout=10)
|
||||
# Should have no more and no less files than expected
|
||||
assert_equal(sorted(notify_outputname(self.wallet, tx_id) for tx_id, _, _ in tx_details), sorted(os.listdir(self.walletnotify_dir)))
|
||||
# Should now verify contents of each file
|
||||
for tx_id, blockheight, blockhash in tx_details:
|
||||
fname = os.path.join(self.walletnotify_dir, notify_outputname(self.wallet, tx_id))
|
||||
# Wait for the cached writes to hit storage
|
||||
self.wait_until(lambda: os.path.getsize(fname) > 0, timeout=10)
|
||||
with open(fname, 'rt', encoding='utf-8') as f:
|
||||
text = f.read()
|
||||
# Universal newline ensures '\n' on 'nt'
|
||||
assert_equal(text[-1], '\n')
|
||||
text = text[:-1]
|
||||
if os.name == 'nt':
|
||||
# On Windows, echo as above will append a whitespace
|
||||
assert_equal(text[-1], ' ')
|
||||
text = text[:-1]
|
||||
expected = str(blockheight) + '_' + blockhash
|
||||
assert_equal(text, expected)
|
||||
|
||||
for tx_file in os.listdir(self.walletnotify_dir):
|
||||
os.remove(os.path.join(self.walletnotify_dir, tx_file))
|
||||
|
||||
if __name__ == '__main__':
|
||||
NotificationsTest().main()
|
||||
|
Loading…
Reference in New Issue
Block a user