Merge pull request #5226 from knst/bc-bp-missing-3

backport: bitcoin#13424, #14092, #14380, #14879, #15693, #16185, #16489, #16556, #16806, #16866, #16873, partial #16197, fixes for #10637
This commit is contained in:
UdjinM6 2023-04-06 20:15:22 +03:00 committed by GitHub
commit daa7c032ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 523 additions and 157 deletions

41
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,41 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: Bug
assignees: ''
---
<!-- This issue tracker is only for technical issues related to Dash Core.
General dash questions and/or support requests are best directed to the Dash Forum at https://www.dash.org/forum/
For reporting security issues, please read instructions at https://www.dash.org/bug-bounty/
If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running memtest and observe CPU temperature with a load-test tool such as linpack before creating an issue! -->
<!-- Describe the issue -->
**Expected behavior**
<!--- What behavior did you expect? -->
**Actual behavior**
<!--- What was the actual behavior (provide screenshots if the issue is GUI-related)? -->
**To reproduce**
<!--- How reliably can you reproduce the issue, what are the steps to do so? -->
**System information**
<!-- What version of Dash Core are you using, where did you get it (website, self-compiled, etc)? -->
<!-- What type of machine are you observing the error on (OS/CPU and disk type)? -->
<!-- GUI-related issue? What is your operating system and its version? If Linux, what is your desktop environment and graphical shell? -->
<!-- Any extra information that might be useful in the debugging process. -->
<!--- This is normally the contents of a `debug.log` or `config.log` file. Raw text or a link to a pastebin type site are preferred. -->

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: Feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

View File

@ -2,6 +2,21 @@
# - sudo/dist/group are set so as to get Blue Box VMs, necessary for [loopback]
# IPv6 support
# The test build matrix (stage: test) is constructed to test a wide range of
# configurations, rather than a single pass/fail. This helps to catch build
# failures and logic errors that present on platforms other than the ones the
# author has tested.
#
# Some builders use the dependency-generator in `./depends`, rather than using
# apt-get to install build dependencies. This guarantees that the tester is
# using the same versions as Gitian, so the build results are nearly identical
# to what would be found in a final release.
#
# In order to avoid rebuilding all dependencies for each build, the binaries
# are cached and re-used when possible. Changes in the dependency-generator
# will trigger cache-invalidation and rebuilds as necessary.
#
dist: xenial
os: linux
@ -177,7 +192,7 @@ before_script:
# Build docker image only for develop branch of the main repo
- if [ "$TRAVIS_REPO_SLUG" != "dashpay/dash" -o "$TRAVIS_BRANCH" != "develop" -o "$TRAVIS_PULL_REQUEST" != "false" ]; then export DOCKER_BUILD="false"; echo DOCKER_BUILD=$DOCKER_BUILD; fi
# TODO: Check keys and signed commits
#- if [ "$TRAVIS_REPO_SLUG" = "dashpay/dash" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then while read LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys; fi
#- if [ "$TRAVIS_REPO_SLUG" = "dashpay/dash" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then travis_retry gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $(<contrib/verify-commits/trusted-keys); fi
#- if [ "$TRAVIS_REPO_SLUG" = "dashpay/dash" -a "$TRAVIS_EVENT_TYPE" = "cron" ]; then travis_wait 30 contrib/verify-commits/verify-commits.py; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE

View File

@ -20,6 +20,6 @@ test/lint/lint-all.sh
if [ "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" ] && [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then
git log --merges --before="2 days ago" -1 --format='%H' > ./contrib/verify-commits/trusted-sha512-root-commit
while read -r LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys &&
travis_retry gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $(<contrib/verify-commits/trusted-keys) &&
./contrib/verify-commits/verify-commits.py --clean-merge=2;
fi

View File

@ -9,7 +9,6 @@ export LC_ALL=C.UTF-8
export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev"
export DEP_OPTS="NO_UPNP=1 DEBUG=1"
export TEST_RUNNER_EXTRA="--extended --exclude feature_pruning,feature_dbcrash,wallet_multiwallet.py" # Temporarily suppress ASan heap-use-after-free (see issue #14163)
export RUN_BENCH=true
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --enable-crash-hooks --with-sanitizers=thread"
export CPPFLAGS="-DDEBUG_LOCKORDER -DENABLE_DASH_DEBUG -DARENA_DEBUG"

View File

@ -5,8 +5,9 @@
# See "man systemd.service" for details.
# Note that almost all daemon options could be specified in
# /etc/dash/dash.conf, except for those explicitly specified as arguments
# in ExecStart=
# /etc/dash/dash.conf, but keep in mind those explicitly
# specified as arguments in ExecStart= will override those in the
# config file.
[Unit]
Description=Dash daemon
@ -18,6 +19,10 @@ ExecStart=/usr/bin/dashd -daemon \
-conf=/etc/dash/dash.conf \
-datadir=/var/lib/dashd
# Make sure the config directory is readable by the service user
PermissionsStartOnly=true
ExecStartPre=/bin/chgrp dashcore /etc/dash
# Process management
####################
@ -54,6 +59,9 @@ PrivateTmp=true
# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full
# Deny access to /home, /root and /run/user
ProtectHome=true
# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true

View File

@ -52,7 +52,6 @@ The Dash Core repo's [root README](/README.md) contains relevant information on
- Source Code Documentation ***TODO***
- [Translation Process](translation_process.md)
- [Translation Strings Policy](translation_strings_policy.md)
- [Travis CI](travis-ci.md)
- [JSON-RPC Interface](JSON-RPC-interface.md)
- [Unauthenticated REST Interface](REST-interface.md)
- [Shared Libraries](shared-libraries.md)

View File

@ -59,11 +59,11 @@ Data directory: `/var/lib/dashd`
PID file: `/var/run/dashd/dashd.pid` (OpenRC and Upstart) or `/run/dashd/dashd.pid` (systemd)
Lock file: `/var/lock/subsys/dashd` (CentOS)
The configuration file, PID directory (if applicable) and data directory
should all be owned by the dashcore user and group. It is advised for security
reasons to make the configuration file and data directory only readable by the
dashcore user and group. Access to dash-cli and other dashd rpc clients
can then be controlled by group membership.
The PID directory (if applicable) and data directory should both be owned by the
dashcore user and group. It is advised for security reasons to make the
configuration file and data directory only readable by the dashcore user and
group. Access to dash-cli and other dashd rpc clients can then be
controlled by group membership.
NOTE: When using the systemd .service file, the creation of the aforementioned
directories and the setting of their permissions is automatically handled by

View File

@ -0,0 +1,6 @@
RPC changes
-----------
The `gettransaction` RPC now accepts a third (boolean) argument `verbose`. If
set to `true`, a new `decoded` field will be added to the response containing
the decoded transaction. This field is equivalent to RPC `decoderawtransaction`,
or RPC `getrawtransaction` when `verbose` is passed.

View File

@ -1,42 +0,0 @@
Travis CI
=========
Support for using travis-ci has been added in order to automate pull-testing.
See [travis-ci.org](https://travis-ci.org/) for more info
This procedure is different than the pull-tester that came before it in a few
ways.
There is nothing to administer. This is a major feature as it means
that builds have no local state. Because there is no ability to login to the
builders to install packages (tools, dependencies, etc), the entire build
procedure must instead be controlled by a declarative script `.travis.yml`.
This script declares each build configuration, creates virtual machines as
necessary, builds, then discards the virtual machines.
A build matrix is constructed to test a wide range of configurations, rather
than a single pass/fail. This helps to catch build failures and logic errors
that present on platforms other than the ones the author has tested. This
matrix is defined in the build script and can be changed at any time.
All builders use the dependency-generator in the [depends dir](/depends), rather than
using apt-get to install build dependencies. This guarantees that the tester
is using the same versions as Gitian, so the build results are nearly identical
to what would be found in a final release. However, this also means that builds
will fail if new dependencies are introduced without being added to the
dependency generator.
In order to avoid rebuilding all dependencies for each build, the binaries are
cached and re-used when possible. Changes in the dependency-generator will
trigger cache-invalidation and rebuilds as necessary.
These caches can be manually removed if necessary. This is one of the very few
manual operations that is possible with Travis, and it can be done by the
Dash Core committer via the Travis web interface.
In some cases, secure strings may be needed for hiding sensitive info such as
private keys or URLs. The travis client may be used to create these strings:
http://docs.travis-ci.com/user/encryption-keys/
For the details of the build descriptor, see the official docs:
http://docs.travis-ci.com/user/build-configuration/

View File

@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Copyright (c) 2014-2022 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -66,12 +66,12 @@ static bool AppInit(int argc, char* argv[])
// Process help and version before taking care about datadir
if (HelpRequested(args) || args.IsArgSet("-version")) {
std::string strUsage = PACKAGE_NAME " Daemon version " + FormatFullVersion() + "\n";
std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n";
if (args.IsArgSet("-version")) {
strUsage += FormatParagraph(LicenseInfo()) + "\n";
} else {
strUsage += "\nUsage: dashd [options] Start " PACKAGE_NAME " Daemon\n";
strUsage += "\nUsage: dashd [options] Start " PACKAGE_NAME "\n";
strUsage += "\n" + args.GetHelpMessage();
}
@ -131,7 +131,7 @@ static bool AppInit(int argc, char* argv[])
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
tfm::format(std::cout, PACKAGE_NAME " daemon starting\n");
tfm::format(std::cout, PACKAGE_NAME " starting\n");
// Daemonize
if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)

View File

@ -14,6 +14,22 @@
<string>Tools window</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_alerts">
<property name="visible">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>3</number>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Buttons_2">
<property name="spacing">

View File

@ -251,9 +251,8 @@ void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
void OverviewPage::setClientModel(ClientModel *model)
{
this->clientModel = model;
if(model)
{
// Show warning if this is a prerelease version
if (model) {
// Show warning, for example if this is a prerelease version
connect(model, &ClientModel::alertsChanged, this, &OverviewPage::updateAlerts);
updateAlerts(model->getStatusBarWarnings());
}

View File

@ -1586,6 +1586,13 @@ QWidget#RPCConsole QLabel#peerHeading,
QWidget#RPCConsole QLabel#banHeading {
}
QWidget#RPCConsole QLabel#label_alerts {
background-color: #c79304;
color: #222222;
border-radius: 5px;
padding: 5px;
}
QWidget#RPCConsole QLabel#labelNetwork,
QWidget#RPCConsole QLabel#label_10,
QWidget#RPCConsole QLabel#labelMempoolTitle { /* Margin between Network and Block Chain headers */

View File

@ -250,6 +250,17 @@ QWidget .QFrame#frame_2 QListView { /* Transaction List */
margin-right: 10px;
}
/******************************************************
RPCConsole
******************************************************/
QWidget#RPCConsole QLabel#label_alerts {
background-color: #c79304;
color: #222222;
border-radius: 5px;
padding: 5px;
}
/******************************************************
SendCoinsDialog
******************************************************/

View File

@ -583,6 +583,17 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_t bestblock_date, uint256 bestblock_hash, double verification_progress)
{
clientModel = model;
bool wallet_enabled{false};
#ifdef ENABLE_WALLET
wallet_enabled = WalletModel::isWalletEnabled();
#endif // ENABLE_WALLET
if (model && !wallet_enabled) {
// Show warning, for example if this is a prerelease version
connect(model, &ClientModel::alertsChanged, this, &RPCConsole::updateAlerts);
updateAlerts(model->getStatusBarWarnings());
}
ui->trafficGraph->setClientModel(model);
if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) {
// Keep up to date with client
@ -1441,3 +1452,9 @@ QKeySequence RPCConsole::tabShortcut(TabTypes tab_type) const
assert(false);
}
void RPCConsole::updateAlerts(const QString& warnings)
{
this->ui->label_alerts->setVisible(!warnings.isEmpty());
this->ui->label_alerts->setText(warnings);
}

View File

@ -192,6 +192,9 @@ private:
/** Update UI with latest network info from model. */
void updateNetworkState();
private Q_SLOTS:
void updateAlerts(const QString& warnings);
};
#endif // BITCOIN_QT_RPCCONSOLE_H

View File

@ -374,7 +374,7 @@ static UniValue waitforblock(const JSONRPCRequest& request)
}.Check(request);
int timeout = 0;
uint256 hash = uint256S(request.params[0].get_str());
uint256 hash(ParseHashV(request.params[0], "blockhash"));
if (!request.params[1].isNull())
timeout = request.params[1].get_int();
@ -634,7 +634,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1");
uint256 hash(ParseHashV(request.params[0], "parameter 1"));
const CTxMemPool& mempool = EnsureMemPool(request.context);
LOCK(mempool.cs);
@ -698,7 +698,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1");
uint256 hash(ParseHashV(request.params[0], "parameter 1"));
const CTxMemPool& mempool = EnsureMemPool(request.context);
LOCK(mempool.cs);
@ -749,7 +749,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
},
}.Check(request);
uint256 hash = ParseHashV(request.params[0], "parameter 1");
uint256 hash(ParseHashV(request.params[0], "parameter 1"));
const CTxMemPool& mempool = EnsureMemPool(request.context);
LOCK(mempool.cs);
@ -862,8 +862,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
},
}.Check(request);
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[0], "hash"));
bool fVerbose = true;
if (!request.params[1].isNull())
@ -936,8 +935,7 @@ static UniValue getblockheaders(const JSONRPCRequest& request)
},
}.Check(request);
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[0], "blockhash"));
const CBlockIndex* pblockindex;
const CBlockIndex* tip;
@ -1048,8 +1046,7 @@ static UniValue getmerkleblocks(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Filter is not within size constraints");
}
std::string strHash = request.params[1].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[1], "blockhash"));
const CBlockIndex* pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash);
if (!pblockindex) {
@ -1154,8 +1151,7 @@ static UniValue getblock(const JSONRPCRequest& request)
},
}.Check(request);
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[0], "blockhash"));
int verbosity = 1;
if (!request.params[1].isNull()) {
@ -1356,8 +1352,7 @@ static UniValue gettxout(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[0], "txid"));
int n = request.params[1].get_int();
COutPoint out(hash, n);
bool fMempool = true;
@ -1805,8 +1800,7 @@ static UniValue preciousblock(const JSONRPCRequest& request)
},
}.Check(request);
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CBlockIndex* pblockindex;
{
@ -1841,8 +1835,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
},
}.Check(request);
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CValidationState state;
CBlockIndex* pblockindex;
@ -1881,8 +1874,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
},
}.Check(request);
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[0], "blockhash"));
{
LOCK(cs_main);
@ -1937,7 +1929,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
LOCK(cs_main);
pindex = ::ChainActive().Tip();
} else {
uint256 hash = uint256S(request.params[1].get_str());
uint256 hash(ParseHashV(request.params[1], "blockhash"));
LOCK(cs_main);
pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
if (!pindex) {
@ -2114,8 +2106,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
pindex = ::ChainActive()[height];
} else {
const uint256 hash = ParseHashV(request.params[0], "parameter 1");
const uint256 hash(ParseHashV(request.params[0], "hash_or_height"));
pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@ -2307,8 +2298,7 @@ static UniValue getspecialtxes(const JSONRPCRequest& request)
LOCK(cs_main);
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
uint256 hash(ParseHashV(request.params[0], "blockhash"));
int nTxType = -1;
if (!request.params[1].isNull()) {
@ -2637,7 +2627,7 @@ static UniValue getblockfilter(const JSONRPCRequest& request)
},
}.Check(request);
uint256 block_hash = ParseHashV(request.params[0], "blockhash");
uint256 block_hash(ParseHashV(request.params[0], "blockhash"));
std::string filtertype_name = "basic";
if (!request.params[1].isNull()) {
filtertype_name = request.params[1].get_str();

View File

@ -105,6 +105,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getchaintxstats", 0, "nblocks" },
{ "getmerkleblocks", 2, "count" },
{ "gettransaction", 1, "include_watchonly" },
{ "gettransaction", 2, "verbose" },
{ "getrawtransaction", 1, "verbose" },
{ "createrawtransaction", 0, "inputs" },
{ "createrawtransaction", 1, "outputs" },

View File

@ -640,7 +640,7 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
paramIdx++;
} else {
uint256 collateralHash = ParseHashV(request.params[paramIdx], "collateralHash");
uint256 collateralHash(ParseHashV(request.params[paramIdx], "collateralHash"));
int32_t collateralIndex = ParseInt32V(request.params[paramIdx + 1], "collateralIndex");
if (collateralHash.IsNull() || collateralIndex < 0) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid hash or index: %s-%d", collateralHash.ToString(), collateralIndex));
@ -1405,7 +1405,7 @@ static UniValue protx_info(const JSONRPCRequest& request)
g_txindex->BlockUntilSyncedToCurrentChain();
}
uint256 proTxHash = ParseHashV(request.params[0], "proTxHash");
uint256 proTxHash(ParseHashV(request.params[0], "proTxHash"));
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetMN(proTxHash);
if (!dmn) {

View File

@ -213,7 +213,7 @@ static UniValue gobject_prepare(const JSONRPCRequest& request)
COutPoint outpoint;
outpoint.SetNull();
if (!request.params[5].isNull() && !request.params[6].isNull()) {
uint256 collateralHash = ParseHashV(request.params[5], "outputHash");
uint256 collateralHash(ParseHashV(request.params[5], "outputHash"));
int32_t collateralIndex = ParseInt32V(request.params[6], "outputIndex");
if (collateralHash.IsNull() || collateralIndex < 0) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid hash or index: %s-%d", collateralHash.ToString(), collateralIndex));
@ -427,9 +427,7 @@ static UniValue gobject_vote_conf(const JSONRPCRequest& request)
{
gobject_vote_conf_help(request);
uint256 hash;
hash = ParseHashV(request.params[0], "Object hash");
uint256 hash(ParseHashV(request.params[0], "Object hash"));
std::string strVoteSignal = request.params[1].get_str();
std::string strVoteOutcome = request.params[2].get_str();
@ -605,7 +603,7 @@ static UniValue gobject_vote_many(const JSONRPCRequest& request)
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
uint256 hash = ParseHashV(request.params[0], "Object hash");
uint256 hash(ParseHashV(request.params[0], "Object hash"));
std::string strVoteSignal = request.params[1].get_str();
std::string strVoteOutcome = request.params[2].get_str();
@ -664,7 +662,7 @@ static UniValue gobject_vote_alias(const JSONRPCRequest& request)
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
uint256 hash = ParseHashV(request.params[0], "Object hash");
uint256 hash(ParseHashV(request.params[0], "Object hash"));
std::string strVoteSignal = request.params[1].get_str();
std::string strVoteOutcome = request.params[2].get_str();
@ -682,7 +680,7 @@ static UniValue gobject_vote_alias(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(wallet.get());
uint256 proTxHash = ParseHashV(request.params[3], "protx-hash");
uint256 proTxHash(ParseHashV(request.params[3], "protx-hash"));
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(proTxHash);
if (!dmn) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid or unknown proTxHash");
@ -850,7 +848,7 @@ static UniValue gobject_get(const JSONRPCRequest& request)
gobject_get_help(request);
// COLLECT VARIABLES FROM OUR USER
uint256 hash = ParseHashV(request.params[0], "GovObj hash");
uint256 hash(ParseHashV(request.params[0], "GovObj hash"));
if (g_txindex) {
g_txindex->BlockUntilSyncedToCurrentChain();
@ -943,11 +941,11 @@ static UniValue gobject_getcurrentvotes(const JSONRPCRequest& request)
// COLLECT PARAMETERS FROM USER
uint256 hash = ParseHashV(request.params[0], "Governance hash");
uint256 hash(ParseHashV(request.params[0], "Governance hash"));
COutPoint mnCollateralOutpoint;
if (!request.params[1].isNull() && !request.params[2].isNull()) {
uint256 txid = ParseHashV(request.params[1], "Masternode Collateral hash");
uint256 txid(ParseHashV(request.params[1], "Masternode Collateral hash"));
std::string strVout = request.params[2].get_str();
mnCollateralOutpoint = COutPoint(txid, LocaleIndependentAtoi<uint32_t>(strVout));
}
@ -1076,11 +1074,11 @@ static UniValue voteraw(const JSONRPCRequest& request)
RPCExamples{""}
}.Check(request);
uint256 hashMnCollateralTx = ParseHashV(request.params[0], "mn collateral tx hash");
uint256 hashMnCollateralTx(ParseHashV(request.params[0], "mn collateral tx hash"));
int nMnCollateralTxIndex = request.params[1].get_int();
COutPoint outpoint = COutPoint(hashMnCollateralTx, nMnCollateralTxIndex);
uint256 hashGovObj = ParseHashV(request.params[2], "Governance hash");
uint256 hashGovObj(ParseHashV(request.params[2], "Governance hash"));
std::string strVoteSignal = request.params[3].get_str();
std::string strVoteOutcome = request.params[4].get_str();

View File

@ -420,7 +420,7 @@ static UniValue masternode_payments(const JSONRPCRequest& request)
pindex = ::ChainActive().Tip();
} else {
LOCK(cs_main);
uint256 blockHash = ParseHashV(request.params[0], "blockhash");
uint256 blockHash(ParseHashV(request.params[0], "blockhash"));
pindex = g_chainman.m_blockman.LookupBlockIndex(blockHash);
if (pindex == nullptr) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

View File

@ -476,7 +476,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
LOCK(cs_main);
uint256 hash = ParseHashV(request.params[0].get_str(), "txid");
uint256 hash(ParseHashV(request.params[0].get_str(), "txid"));
CAmount nAmount = request.params[1].get_int64();
EnsureMemPool(request.context).PrioritiseTransaction(hash, nAmount);
@ -726,7 +726,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
// Format: <hashBestChain><nTransactionsUpdatedLast>
std::string lpstr = lpval.get_str();
hashWatchedChain.SetHex(lpstr.substr(0, 64));
hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid");
nTransactionsUpdatedLastLP = LocaleIndependentAtoi<int64_t>(lpstr.substr(64));
}
else

View File

@ -240,7 +240,7 @@ static UniValue quorum_info(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
}
uint256 quorumHash = ParseHashV(request.params[1], "quorumHash");
uint256 quorumHash(ParseHashV(request.params[1], "quorumHash"));
bool includeSkShare = false;
if (!request.params[2].isNull()) {
includeSkShare = ParseBoolV(request.params[2], "includeSkShare");
@ -381,7 +381,7 @@ static UniValue quorum_memberof(const JSONRPCRequest& request)
{
quorum_memberof_help(request);
uint256 protxHash = ParseHashV(request.params[0], "proTxHash");
uint256 protxHash(ParseHashV(request.params[0], "proTxHash"));
int scanQuorumsCount = -1;
if (!request.params[1].isNull()) {
scanQuorumsCount = ParseInt32V(request.params[1], "scanQuorumsCount");
@ -530,8 +530,8 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
}
uint256 id = ParseHashV(request.params[1], "id");
uint256 msgHash = ParseHashV(request.params[2], "msgHash");
uint256 id(ParseHashV(request.params[1], "id"));
uint256 msgHash(ParseHashV(request.params[2], "msgHash"));
if (cmd == "quorumsign") {
uint256 quorumHash;
@ -590,7 +590,7 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, 0) ||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, signOffset);
} else {
uint256 quorumHash = ParseHashV(request.params[4], "quorumHash");
uint256 quorumHash(ParseHashV(request.params[4], "quorumHash"));
llmq::CQuorumCPtr quorum = llmq_ctx.qman->GetQuorum(llmqType, quorumHash);
if (!quorum) {
@ -642,7 +642,7 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
}
uint256 id = ParseHashV(request.params[1], "id");
uint256 id(ParseHashV(request.params[1], "id"));
UniValue ret(UniValue::VOBJ);
@ -723,7 +723,7 @@ static UniValue quorum_getdata(const JSONRPCRequest& request)
NodeId nodeId = ParseInt64V(request.params[0], "nodeId");
Consensus::LLMQType llmqType = static_cast<Consensus::LLMQType>(ParseInt32V(request.params[1], "llmqType"));
uint256 quorumHash = ParseHashV(request.params[2], "quorumHash");
uint256 quorumHash(ParseHashV(request.params[2], "quorumHash"));
uint16_t nDataMask = static_cast<uint16_t>(ParseInt32V(request.params[3], "dataMask"));
uint256 proTxHash;
@ -871,7 +871,7 @@ static UniValue verifychainlock(const JSONRPCRequest& request)
{
verifychainlock_help(request);
const uint256 nBlockHash = ParseHashV(request.params[0], "blockHash");
const uint256 nBlockHash(ParseHashV(request.params[0], "blockHash"));
CBLSSignature chainLockSig;
if (!chainLockSig.SetHexStr(request.params[1].get_str())) {
@ -915,8 +915,8 @@ static UniValue verifyislock(const JSONRPCRequest& request)
{
verifyislock_help(request);
uint256 id = ParseHashV(request.params[0], "id");
uint256 txid = ParseHashV(request.params[1], "txid");
uint256 id(ParseHashV(request.params[0], "id"));
uint256 txid(ParseHashV(request.params[1], "txid"));
CBLSSignature sig;
if (!sig.SetHexStr(request.params[2].get_str())) {

View File

@ -297,10 +297,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
UniValue txids = request.params[0].get_array();
for (unsigned int idx = 0; idx < txids.size(); idx++) {
const UniValue& txid = txids[idx];
if (txid.get_str().length() != 64 || !IsHex(txid.get_str())) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid txid ")+txid.get_str());
}
uint256 hash(uint256S(txid.get_str()));
uint256 hash(ParseHashV(txid, "txid"));
if (setTxids.count(hash)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ")+txid.get_str());
}
@ -312,7 +309,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
uint256 hashBlock;
if (!request.params[1].isNull()) {
LOCK(cs_main);
hashBlock = uint256S(request.params[1].get_str());
hashBlock = ParseHashV(request.params[1], "blockhash");
pblockindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

View File

@ -182,7 +182,7 @@ static RPCHelpMan stop()
// Also accept the hidden 'wait' integer argument (milliseconds)
// For instance, 'stop 1000' makes the call wait 1 second before returning
// to the client (intended for testing)
"\nStop Dash Core server.",
"\nRequest a graceful shutdown of " PACKAGE_NAME ".",
{
{"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "how long to wait in ms", "", {}, /* hidden */ true},
},

View File

@ -88,16 +88,12 @@ CAmount AmountFromValue(const UniValue& value)
uint256 ParseHashV(const UniValue& v, std::string strName)
{
std::string strHex;
if (v.isStr())
strHex = v.get_str();
std::string strHex{v.get_str()};
if (64 != strHex.length())
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex));
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
if (64 != strHex.length())
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
uint256 result;
result.SetHex(strHex);
return result;
return uint256S(strHex);
}
uint256 ParseHashO(const UniValue& o, std::string strKey)
{

View File

@ -358,8 +358,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
LOCK(pwallet->cs_wallet);
uint256 hash;
hash.SetHex(request.params[0].get_str());
uint256 hash(ParseHashV(request.params[0], "txid"));
std::vector<uint256> vHash;
vHash.push_back(hash);
std::vector<uint256> vHashOut;

View File

@ -1582,7 +1582,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
uint256 blockId;
if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
blockId.SetHex(request.params[0].get_str());
blockId = ParseHashV(request.params[0], "blockhash");
height = pwallet->chain().findFork(blockId, &altheight);
if (!height) {
@ -1655,6 +1655,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
{
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
{"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses in balance calculation and details[]"},
{"verbose", RPCArg::Type::BOOL, /* default */ "false", "Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
},
RPCResult{
RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
@ -1688,6 +1689,10 @@ static UniValue gettransaction(const JSONRPCRequest& request)
}},
}},
{RPCResult::Type::STR_HEX, "hex", "Raw data for transaction"},
{RPCResult::Type::OBJ, "decoded", /*optional=*/true, "the decoded transaction (only present when `verbose` is passed), equivalent to the",
{
{RPCResult::Type::ELISION, "", "RPC decoderawtransaction method, or the RPC getrawtransaction method when `verbose` is passed."},
}},
}),
},
RPCExamples{
@ -1707,8 +1712,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
LOCK(pwallet->cs_wallet);
uint256 hash;
hash.SetHex(request.params[0].get_str());
uint256 hash(ParseHashV(request.params[0], "txid"));
isminefilter filter = ISMINE_SPENDABLE;
@ -1716,6 +1720,8 @@ static UniValue gettransaction(const JSONRPCRequest& request)
filter |= ISMINE_WATCH_ONLY;
}
bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
UniValue entry(UniValue::VOBJ);
auto it = pwallet->mapWallet.find(hash);
if (it == pwallet->mapWallet.end()) {
@ -1741,6 +1747,12 @@ static UniValue gettransaction(const JSONRPCRequest& request)
std::string strHex = EncodeHexTx(*wtx.tx);
entry.pushKV("hex", strHex);
if (verbose) {
UniValue decoded(UniValue::VOBJ);
TxToUniv(*wtx.tx, uint256(), decoded, false);
entry.pushKV("decoded", decoded);
}
return entry;
}
@ -1772,8 +1784,7 @@ static UniValue abandontransaction(const JSONRPCRequest& request)
LOCK(pwallet->cs_wallet);
uint256 hash;
hash.SetHex(request.params[0].get_str());
uint256 hash(ParseHashV(request.params[0], "txid"));
if (!pwallet->mapWallet.count(hash)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
@ -2176,17 +2187,13 @@ static UniValue lockunspent(const JSONRPCRequest& request)
{"vout", UniValueType(UniValue::VNUM)},
});
const std::string& txid = find_value(o, "txid").get_str();
if (!IsHex(txid)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
}
const uint256 txid(ParseHashO(o, "txid"));
const int nOutput = find_value(o, "vout").get_int();
if (nOutput < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
}
const COutPoint outpt(uint256S(txid), nOutput);
const COutPoint outpt(txid, nOutput);
const auto it = pwallet->mapWallet.find(outpt.hash);
if (it == pwallet->mapWallet.end()) {
@ -4099,7 +4106,7 @@ static const CRPCCommand commands[] =
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, {} },
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf","addlocked"} },
{ "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf","addlocked"} },
{ "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
{ "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly","verbose"} },
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
{ "wallet", "getbalances", &getbalances, {} },
{ "wallet", "getwalletinfo", &getwalletinfo, {} },

View File

@ -1326,4 +1326,52 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup)
TestUnloadWallet(std::move(wallet));
}
// Explicit calculation which is used to test the wallet constant
// We get the same virtual size due to rounding(weight/4) for both use_max_sig values
static size_t CalculateNestedKeyhashInputSize(bool use_max_sig)
{
// Generate ephemeral valid pubkey
CKey key;
key.MakeNewKey(true);
CPubKey pubkey = key.GetPubKey();
// Generate pubkey hash
uint160 key_hash(Hash160(pubkey.begin(), pubkey.end()));
// Create inner-script to enter into keystore. Key hash can't be 0...
CScript inner_script = CScript() << OP_0 << std::vector<unsigned char>(key_hash.begin(), key_hash.end());
// Create outer P2SH script for the output
CScript script_pubkey = GetScriptForRawPubKey(pubkey);
NodeContext node;
node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get());
auto chain = interfaces::MakeChain(node);
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
AddKey(wallet, key);
auto spk_man = wallet.GetLegacyScriptPubKeyMan();
spk_man->AddCScript(inner_script);
// Fill in dummy signatures for fee calculation.
SignatureData sig_data;
if (!ProduceSignature(*spk_man, use_max_sig ? DUMMY_MAXIMUM_SIGNATURE_CREATOR : DUMMY_SIGNATURE_CREATOR, script_pubkey, sig_data)) {
// We're hand-feeding it correct arguments; shouldn't happen
assert(false);
}
CTxIn tx_in;
UpdateInput(tx_in, sig_data);
return ::GetSerializeSize(tx_in, PROTOCOL_VERSION);
}
static constexpr size_t DUMMY_NESTED_P2PKH_INPUT_SIZE = 113;
BOOST_FIXTURE_TEST_CASE(dummy_input_size_test, TestChain100Setup)
{
std::cerr << "CDEF " << CalculateNestedKeyhashInputSize(false) << std::endl;
BOOST_CHECK_EQUAL(CalculateNestedKeyhashInputSize(false), DUMMY_NESTED_P2PKH_INPUT_SIZE);
BOOST_CHECK_EQUAL(CalculateNestedKeyhashInputSize(true), DUMMY_NESTED_P2PKH_INPUT_SIZE + 1);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -1786,8 +1786,6 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet,
CMutableTransaction txn;
txn.vin.push_back(CTxIn(COutPoint()));
if (!wallet->DummySignInput(txn.vin[0], txout, use_max_sig)) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// implies that we can sign for every input.
return -1;
}
return ::GetSerializeSize(txn.vin[0], PROTOCOL_VERSION);
@ -3404,7 +3402,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
FeeCalculation feeCalc;
CFeeRate discard_rate = coin_control.m_discard_feerate ? *coin_control.m_discard_feerate : GetDiscardRate(*this);
unsigned int nBytes{0};
int nBytes{0};
{
std::vector<CInputCoin> vecCoins;
LOCK(cs_wallet);

View File

@ -30,7 +30,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction, '', 0, 0)
# Test `prioritisetransaction` invalid `txid`
assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].prioritisetransaction, txid='foo', fee_delta=0)
assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].prioritisetransaction, txid='foo', fee_delta=0)
assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000')", self.nodes[0].prioritisetransaction, txid='Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000', fee_delta=0)
txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'

View File

@ -279,7 +279,7 @@ class CompactBlocksTest(BitcoinTestFramework):
block_hash = int(node.generate(1)[0], 16)
# Store the raw block in our internal format.
block = FromHex(CBlock(), node.getblock("%02x" % block_hash, False))
block = FromHex(CBlock(), node.getblock("%064x" % block_hash, False))
for tx in block.vtx:
tx.calc_sha256()
block.rehash()

View File

@ -394,7 +394,7 @@ class SendHeadersTest(BitcoinTestFramework):
block_time += 9
fork_point = self.nodes[0].getblock("%02x" % new_block_hashes[0])["previousblockhash"]
fork_point = self.nodes[0].getblock("%064x" % new_block_hashes[0])["previousblockhash"]
fork_point = int(fork_point, 16)
# Use getblocks/getdata

View File

@ -0,0 +1,176 @@
#!/usr/bin/env python3
# Copyright (c) 2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
Test transaction download behavior
"""
from test_framework.messages import (
CInv,
CTransaction,
FromHex,
MSG_TX,
MSG_TYPE_MASK,
msg_inv,
msg_notfound,
)
from test_framework.mininode import (
P2PInterface,
mininode_lock,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
wait_until,
)
from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
class TestP2PConn(P2PInterface):
def __init__(self):
super().__init__()
self.tx_getdata_count = 0
def on_getdata(self, message):
for i in message.inv:
if i.type & MSG_TYPE_MASK == MSG_TX:
self.tx_getdata_count += 1
# Constants from net_processing
GETDATA_TX_INTERVAL = 60 # seconds
MAX_GETDATA_RANDOM_DELAY = 2 # seconds
INBOUND_PEER_TX_DELAY = 2 # seconds
MAX_GETDATA_IN_FLIGHT = 100
TX_EXPIRY_INTERVAL = GETDATA_TX_INTERVAL * 10
# Python test constants
NUM_INBOUND = 10
MAX_GETDATA_INBOUND_WAIT = GETDATA_TX_INTERVAL + MAX_GETDATA_RANDOM_DELAY + INBOUND_PEER_TX_DELAY
class TxDownloadTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = False
self.num_nodes = 2
def test_tx_requests(self):
self.log.info("Test that we request transactions from all our peers, eventually")
txid = 0xdeadbeef
self.log.info("Announce the txid from each incoming peer to node 0")
msg = msg_inv([CInv(t=1, h=txid)])
for p in self.nodes[0].p2ps:
p.send_message(msg)
p.sync_with_ping()
outstanding_peer_index = [i for i in range(len(self.nodes[0].p2ps))]
def getdata_found(peer_index):
p = self.nodes[0].p2ps[peer_index]
with mininode_lock:
return p.last_message.get("getdata") and p.last_message["getdata"].inv[-1].hash == txid
while outstanding_peer_index:
self.bump_mocktime(MAX_GETDATA_INBOUND_WAIT)
wait_until(lambda: any(getdata_found(i) for i in outstanding_peer_index))
for i in outstanding_peer_index:
if getdata_found(i):
outstanding_peer_index.remove(i)
self.log.info("All outstanding peers received a getdata")
def test_inv_block(self):
self.log.info("Generate a transaction on node 0")
tx = self.nodes[0].createrawtransaction(
inputs=[{ # coinbase
"txid": self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0],
"vout": 0
}],
outputs={ADDRESS_BCRT1_UNSPENDABLE: 500 - 0.00025},
)
tx = self.nodes[0].signrawtransactionwithkey(
hexstring=tx,
privkeys=[self.nodes[0].get_deterministic_priv_key().key],
)['hex']
ctx = FromHex(CTransaction(), tx)
txid = int(ctx.rehash(), 16)
self.log.info(
"Announce the transaction to all nodes from all {} incoming peers, but never send it".format(NUM_INBOUND))
msg = msg_inv([CInv(t=1, h=txid)])
for p in self.peers:
p.send_message(msg)
p.sync_with_ping()
self.bump_mocktime(1)
self.log.info("Put the tx in node 0's mempool")
self.nodes[0].sendrawtransaction(tx)
# Since node 1 is connected outbound to an honest peer (node 0), it
# should get the tx within a timeout. (Assuming that node 0
# announced the tx within the timeout)
# The timeout is the sum of
# * the worst case until the tx is first requested from an inbound
# peer, plus
# * the first time it is re-requested from the outbound peer, plus
# * 2 seconds to avoid races
timeout = 2 + (MAX_GETDATA_RANDOM_DELAY + INBOUND_PEER_TX_DELAY) + (
GETDATA_TX_INTERVAL + MAX_GETDATA_RANDOM_DELAY)
self.log.info("Tx should be received at node 1 after {} seconds".format(timeout))
self.sync_mempools(timeout=timeout)
def test_in_flight_max(self):
self.log.info("Test that we don't request more than {} transactions from any peer, every {} minutes".format(
MAX_GETDATA_IN_FLIGHT, TX_EXPIRY_INTERVAL / 60))
txids = [i for i in range(MAX_GETDATA_IN_FLIGHT + 2)]
p = self.nodes[0].p2ps[0]
with mininode_lock:
p.tx_getdata_count = 0
p.send_message(msg_inv([CInv(t=1, h=i) for i in txids]))
def wait_for_tx_getdata(target):
self.bump_mocktime(1)
return p.tx_getdata_count >= target
wait_until(lambda: wait_for_tx_getdata(MAX_GETDATA_IN_FLIGHT), lock=mininode_lock)
with mininode_lock:
assert_equal(p.tx_getdata_count, MAX_GETDATA_IN_FLIGHT)
self.log.info("Now check that if we send a NOTFOUND for a transaction, we'll get one more request")
p.send_message(msg_notfound(vec=[CInv(t=1, h=txids[0])]))
wait_until(lambda: wait_for_tx_getdata(MAX_GETDATA_IN_FLIGHT + 1), timeout=10, lock=mininode_lock)
with mininode_lock:
assert_equal(p.tx_getdata_count, MAX_GETDATA_IN_FLIGHT + 1)
WAIT_TIME = TX_EXPIRY_INTERVAL // 2 + TX_EXPIRY_INTERVAL
self.log.info("if we wait about {} minutes, we should eventually get more requests".format(WAIT_TIME / 60))
self.bump_mocktime(WAIT_TIME)
wait_until(lambda: wait_for_tx_getdata(MAX_GETDATA_IN_FLIGHT + 2))
def run_test(self):
# Setup the p2p connections
self.peers = []
for node in self.nodes:
for i in range(NUM_INBOUND):
self.peers.append(node.add_p2p_connection(TestP2PConn()))
self.log.info("Nodes are setup with {} incoming connections each".format(NUM_INBOUND))
# Test the in-flight max first, because we want no transactions in
# flight ahead of this test.
self.test_in_flight_max()
self.test_inv_block()
self.test_tx_requests()
if __name__ == '__main__':
TxDownloadTest().main()

View File

@ -142,7 +142,9 @@ class BlockchainTest(BitcoinTestFramework):
# Test `getchaintxstats` invalid `blockhash`
assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].getchaintxstats, blockhash=0)
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0')
assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 1, for '0')", self.nodes[0].getchaintxstats, blockhash='0')
assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getchaintxstats, blockhash='ZZZ0000000000000000000000000000000000000000000000000000000000000')
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0000000000000000000000000000000000000000000000000000000000000000')
blockhash = self.nodes[0].getblockhash(200)
self.nodes[0].invalidateblock(blockhash)
assert_raises_rpc_error(-8, "Block is not in main chain", self.nodes[0].getchaintxstats, blockhash=blockhash)
@ -244,7 +246,9 @@ class BlockchainTest(BitcoinTestFramework):
def _test_getblockheader(self):
node = self.nodes[0]
assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "nonsense")
assert_raises_rpc_error(-8, "hash must be of length 64 (not 8, for 'nonsense')", node.getblockheader, "nonsense")
assert_raises_rpc_error(-8, "hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", node.getblockheader, "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
besthash = node.getbestblockhash()
secondbesthash = node.getblockhash(199)

View File

@ -158,6 +158,10 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].generate(6)
self.sync_all()
# Make sure change address wallet does not have P2SH innerscript access to results in success
# when attempting BnB coin selection
block_height = self.nodes[0].getblockcount()
self.nodes[0].walletcreatefundedpsbt([], [{self.nodes[2].getnewaddress():self.nodes[0].listunspent()[0]["amount"]+1}], block_height+2, {"changeAddress":self.nodes[1].getnewaddress()}, False)
# Regression test for 14473 (mishandling of already-signed witness transaction):
unspent = self.nodes[0].listunspent()[0]

View File

@ -90,8 +90,9 @@ class RawTransactionsTest(BitcoinTestFramework):
txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
assert_raises_rpc_error(-3, "Expected type array", self.nodes[0].createrawtransaction, 'foo', {})
assert_raises_rpc_error(-1, "JSON value is not an object as expected", self.nodes[0].createrawtransaction, ['foo'], {})
assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].createrawtransaction, [{}], {})
assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})
assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].createrawtransaction, [{}], {})
assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})
assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", self.nodes[0].createrawtransaction, [{'txid': 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'}], {})
assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid}], {})
assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 'foo'}], {})
assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': -1}], {})
@ -171,9 +172,10 @@ class RawTransactionsTest(BitcoinTestFramework):
# We should not get the tx if we provide an unrelated block
assert_raises_rpc_error(-5, "No such transaction found", self.nodes[0].getrawtransaction, tx, True, block2)
# An invalid block hash should raise the correct errors
assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", self.nodes[0].getrawtransaction, tx, True, True)
assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", self.nodes[0].getrawtransaction, tx, True, "foobar")
assert_raises_rpc_error(-8, "parameter 3 must be of length 64", self.nodes[0].getrawtransaction, tx, True, "abcd1234")
assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].getrawtransaction, tx, True, True)
assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 6, for 'foobar')", self.nodes[0].getrawtransaction, tx, True, "foobar")
assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')", self.nodes[0].getrawtransaction, tx, True, "abcd1234")
assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getrawtransaction, tx, True, "ZZZ0000000000000000000000000000000000000000000000000000000000000")
assert_raises_rpc_error(-5, "Block hash not found", self.nodes[0].getrawtransaction, tx, True, "0000000000000000000000000000000000000000000000000000000000000000")
# Undo the blocks and check in_active_chain
self.nodes[0].invalidateblock(block1)

View File

@ -69,13 +69,19 @@ class MerkleBlockTest(BitcoinTestFramework):
txid_spent = txin_spent["txid"]
txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2
# Invalid txids
assert_raises_rpc_error(-8, "txid must be of length 64 (not 32, for '00000000000000000000000000000000')", self.nodes[2].gettxoutproof, ["00000000000000000000000000000000"], blockhash)
assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].gettxoutproof, ["ZZZ0000000000000000000000000000000000000000000000000000000000000"], blockhash)
# Invalid blockhashes
assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 32, for '00000000000000000000000000000000')", self.nodes[2].gettxoutproof, [txid_spent], "00000000000000000000000000000000")
assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].gettxoutproof, [txid_spent], "ZZZ0000000000000000000000000000000000000000000000000000000000000")
# We can't find the block from a fully-spent tx
# Doesn't apply to Dash Core - we have txindex always on
# assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[2].gettxoutproof, [txid_spent])
# We can get the proof if we specify the block
assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent])
# We can't get the proof if we specify a non-existent block
assert_raises_rpc_error(-5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent], "00000000000000000000000000000000")
assert_raises_rpc_error(-5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent], "0000000000000000000000000000000000000000000000000000000000000000")
# We can get the proof if the transaction is unspent
assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent])
# We can get the proof if we provide a list of transactions and one of them is unspent. The ordering of the list should not matter.

View File

@ -103,6 +103,7 @@ BASE_SCRIPTS = [
'p2p_timeouts.py',
'feature_bip68_sequence.py',
'mempool_updatefromblock.py',
'p2p_tx_download.py',
'wallet_dump.py',
'wallet_listtransactions.py',
'feature_multikeysporks.py',

View File

@ -121,9 +121,15 @@ class WalletTest(BitcoinTestFramework):
assert_equal([unspent_0], self.nodes[2].listlockunspent())
self.nodes[2].lockunspent(True, [unspent_0])
assert_equal(len(self.nodes[2].listlockunspent()), 0)
assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction",
assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')",
self.nodes[2].lockunspent, False,
[{"txid": "0000000000000000000000000000000000", "vout": 0}])
assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
self.nodes[2].lockunspent, False,
[{"txid": "ZZZ0000000000000000000000000000000000000000000000000000000000000", "vout": 0}])
assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction",
self.nodes[2].lockunspent, False,
[{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0}])
assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds",
self.nodes[2].lockunspent, False,
[{"txid": unspent_0["txid"], "vout": 999}])
@ -490,6 +496,38 @@ class WalletTest(BitcoinTestFramework):
self.nodes[0].setlabel(change, 'foobar')
assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)
# Test gettransaction response with different arguments.
self.log.info("Testing gettransaction response with different arguments...")
self.nodes[0].setlabel(change, 'baz')
baz = self.nodes[0].listtransactions(label="baz", count=1)[0]
expected_receive_vout = {"label": "baz",
"address": baz["address"],
"amount": baz["amount"],
"category": baz["category"],
"vout": baz["vout"]}
expected_fields = frozenset({'amount', 'chainlock', 'confirmations', 'details', 'fee',
'instantlock', 'instantlock_internal',
'hex', 'timereceived', 'time', 'trusted', 'txid', 'walletconflicts'})
verbose_field = "decoded"
expected_verbose_fields = expected_fields | {verbose_field}
self.log.debug("Testing gettransaction response without verbose")
tx = self.nodes[0].gettransaction(txid=txid)
assert_equal(set([*tx]), expected_fields)
assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout)
self.log.debug("Testing gettransaction response with verbose set to False")
tx = self.nodes[0].gettransaction(txid=txid, verbose=False)
assert_equal(set([*tx]), expected_fields)
assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout)
self.log.debug("Testing gettransaction response with verbose set to True")
tx = self.nodes[0].gettransaction(txid=txid, verbose=True)
assert_equal(set([*tx]), expected_verbose_fields)
assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout)
assert_equal(tx[verbose_field], self.nodes[0].decoderawtransaction(tx["hex"]))
if __name__ == '__main__':
WalletTest().main()

View File

@ -66,8 +66,10 @@ class ListSinceBlockTest(BitcoinTestFramework):
"42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4")
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock,
"0000000000000000000000000000000000000000000000000000000000000000")
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock,
assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 11, for 'invalid-hex')", self.nodes[0].listsinceblock,
"invalid-hex")
assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'Z000000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].listsinceblock,
"Z000000000000000000000000000000000000000000000000000000000000000")
def test_reorg(self):
'''