diff --git a/README.md b/README.md
index 238f16e94abc..c224df3b397c 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ There are also [regression and integration tests](/test), written
in Python, that are run automatically on the build server.
These tests can be run (if the [test dependencies](/test) are installed) with: `test/functional/test_runner.py`
-The Travis CI system makes sure that every pull request is built for Windows, Linux, and OS X, and that unit/sanity tests are run automatically.
+The Travis CI system makes sure that every pull request is built for Windows, Linux, and macOS, and that unit/sanity tests are run automatically.
### Manual Quality Assurance (QA) Testing
diff --git a/configure.ac b/configure.ac
index c727c6756331..c11362776296 100644
--- a/configure.ac
+++ b/configure.ac
@@ -281,6 +281,10 @@ AC_LANG_PUSH([C++])
AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""])
if test "x$enable_debug" = xyes; then
+ # Clear default -g -O2 flags
+ if test "x$CXXFLAGS_overridden" = xno; then
+ CXXFLAGS=""
+ fi
# Prefer -Og, fall back to -O0 if that is unavailable.
AX_CHECK_COMPILE_FLAG(
[-Og],
diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py
index f4e77b343c2c..3779c3f48bb9 100755
--- a/contrib/devtools/update-translations.py
+++ b/contrib/devtools/update-translations.py
@@ -30,6 +30,10 @@
LOCALE_DIR = 'src/qt/locale'
# Minimum number of messages for translation to be considered at all
MIN_NUM_MESSAGES = 10
+# Regexp to check for Bitcoin addresses
+ADDRESS_REGEXP = re.compile('([13]|bc1)[a-zA-Z0-9]{30,}')
+# Regexp to check for Dash addresses
+ADDRESS_REGEXP_DASH = re.compile('[X7][a-zA-Z0-9]{30,}')
def check_at_repository_root():
if not os.path.exists('.git'):
@@ -125,6 +129,18 @@ def escape_cdata(text):
text = text.replace('"', '"')
return text
+def contains_bitcoin_addr(text, errors):
+ if text != None and ADDRESS_REGEXP.search(text) != None:
+ errors.append('Translation "%s" contains a bitcoin address. This will be removed.' % (text))
+ return True
+ return False
+
+def contains_dash_addr(text, errors):
+ if text != None and ADDRESS_REGEXP_DASH.search(text) != None:
+ errors.append('Translation "%s" contains a Dash address. This will be removed.' % (text))
+ return True
+ return False
+
def postprocess_translations(reduce_diff_hacks=False):
print('Checking and postprocessing...')
@@ -163,7 +179,8 @@ def postprocess_translations(reduce_diff_hacks=False):
if translation is None:
continue
errors = []
- valid = check_format_specifiers(source, translation, errors, numerus)
+ valid = check_format_specifiers(source, translation, errors, numerus) and not contains_bitcoin_addr(translation, errors)
+ valid = valid and not contains_dash_addr(translation, errors)
for error in errors:
print('%s: %s' % (filename, error))
diff --git a/contrib/init/README.md b/contrib/init/README.md
index e0adc72f3df4..1dc3a1455479 100644
--- a/contrib/init/README.md
+++ b/contrib/init/README.md
@@ -5,7 +5,7 @@ Upstart: dashd.conf
OpenRC: dashd.openrc
dashd.openrcconf
CentOS: dashd.init
-OS X: org.dash.dashd.plist
+macOS: org.dash.dashd.plist
```
have been made available to assist packagers in creating node packages here.
diff --git a/depends/README.md b/depends/README.md
index ba79881e62ce..6a9a87be1616 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -22,7 +22,7 @@ Common `host-platform-triplets` for cross compilation are:
- `i686-w64-mingw32` for Win32
- `x86_64-w64-mingw32` for Win64
-- `x86_64-apple-darwin14` for MacOSX
+- `x86_64-apple-darwin14` for macOS
- `arm-linux-gnueabihf` for Linux ARM 32 bit
- `aarch64-linux-gnu` for Linux ARM 64 bit
- `riscv32-linux-gnu` for Linux RISC-V 32 bit
@@ -57,7 +57,7 @@ The following can be set when running make: make FOO=bar
SOURCES_PATH: downloaded sources will be placed here
BASE_CACHE: built packages will be placed here
- SDK_PATH: Path where sdk's can be found (used by OSX)
+ SDK_PATH: Path where sdk's can be found (used by macOS)
FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up
NO_QT: Don't download/build/cache qt and its dependencies
NO_WALLET: Don't download/build/cache libs needed to enable the wallet
@@ -72,7 +72,7 @@ options will be passed to Dash Core's configure. In this case, `--disable-wallet
Additional targets:
download: run 'make download' to fetch all sources without building them
- download-osx: run 'make download-osx' to fetch all sources needed for osx builds
+ download-osx: run 'make download-osx' to fetch all sources needed for macOS builds
download-win: run 'make download-win' to fetch all sources needed for win builds
download-linux: run 'make download-linux' to fetch all sources needed for linux builds
diff --git a/depends/description.md b/depends/description.md
index 74f9ef3f205e..9fc7093be4f3 100644
--- a/depends/description.md
+++ b/depends/description.md
@@ -7,7 +7,7 @@ In theory, binaries for any target OS/architecture can be created, from a
builder running any OS/architecture. In practice, build-side tools must be
specified when the defaults don't fit, and packages must be amended to work
on new hosts. For now, a build architecture of x86_64 is assumed, either on
-Linux or OSX.
+Linux or macOS.
### No reliance on timestamps
diff --git a/doc/README.md b/doc/README.md
index b9109feeff1f..ec8298b7bbcd 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -18,7 +18,7 @@ Unpack the files into a directory and run:
Unpack the files into a directory, and then run dash-qt.exe.
-### OS X
+### macOS
Drag Dash-Qt to your applications folder, and then run Dash-Qt.
@@ -35,7 +35,7 @@ Building
---------------------
The following are developer notes on how to build Dash Core on your native platform. They are not complete guides, but include notes on the necessary libraries, compile flags, etc.
-- [OS X Build Notes](build-osx.md)
+- [macOS Build Notes](build-osx.md)
- [Unix Build Notes](build-unix.md)
- [Windows Build Notes](build-windows.md)
- [OpenBSD Build Notes](build-openbsd.md)
diff --git a/doc/README_osx.md b/doc/README_osx.md
index 975be4be9ed6..739e22d6341c 100644
--- a/doc/README_osx.md
+++ b/doc/README_osx.md
@@ -1,12 +1,12 @@
-Deterministic OS X DMG Notes.
+Deterministic macOS DMG Notes.
-Working OS X DMGs are created in Linux by combining a recent clang,
+Working macOS DMGs are created in Linux by combining a recent clang,
the Apple binutils (ld, ar, etc) and DMG authoring tools.
Apple uses clang extensively for development and has upstreamed the necessary
functionality so that a vanilla clang can take advantage. It supports the use
of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary
-when building for OS X.
+when building for macOS.
Apple's version of binutils (called cctools) contains lots of functionality
missing in the FSF's binutils. In addition to extra linker options for
@@ -38,7 +38,7 @@ Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.1
Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file.
To create a tarball suitable for Gitian input, there are two options:
-Using Mac OS X, you can mount the dmg, and then create it with:
+Using macOS, you can mount the dmg, and then create it with:
```
$ hdiutil attach Xcode_7.3.1.dmg
$ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk
@@ -81,7 +81,7 @@ Background images and other features can be added to DMG files by inserting a
.DS_Store before creation. This is generated by the script
contrib/macdeploy/custom_dsstore.py.
-As of OS X Mavericks (10.9), using an Apple-blessed key to sign binaries is a
+As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a
requirement in order to satisfy the new Gatekeeper requirements. Because this
private key cannot be shared, we'll have to be a bit creative in order for the
build process to remain somewhat deterministic. Here's how it works:
diff --git a/doc/build-osx.md b/doc/build-osx.md
index 35a912488697..fe90bfe81587 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -1,11 +1,11 @@
-Mac OS X Build Instructions and Notes
+macOS Build Instructions and Notes
====================================
The commands in this guide should be executed in a Terminal application.
The built-in one is located in `/Applications/Utilities/Terminal.app`.
Preparation
-----------
-Install the OS X command line tools:
+Install the macOS command line tools:
`xcode-select --install`
diff --git a/doc/gitian-building.md b/doc/gitian-building.md
index c32955dfdfe2..c418e59b974f 100644
--- a/doc/gitian-building.md
+++ b/doc/gitian-building.md
@@ -360,7 +360,7 @@ offline.
Building Dash Core
----------------
-To build Dash Core (for Linux, OS X and Windows) just follow the steps under 'perform
+To build Dash Core (for Linux, macOS and Windows) just follow the steps under 'perform
Gitian builds' in [doc/release-process.md](release-process.md#setup-and-perform-gitian-builds) in the Dash Core repository.
This may take some time as it will build all the dependencies needed for each descriptor.
diff --git a/doc/init.md b/doc/init.md
index e20d3501e8ca..071435fea0b5 100644
--- a/doc/init.md
+++ b/doc/init.md
@@ -15,7 +15,7 @@ Service User
All three Linux startup configurations assume the existence of a "dashcore" user
and group. They must be created before attempting to use these scripts.
-The OS X configuration assumes dashd will be set up for the current user.
+The macOS configuration assumes dashd will be set up for the current user.
Configuration
---------------------------------
@@ -65,7 +65,7 @@ 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.
-### Mac OS X
+### macOS
Binary: `/usr/local/bin/dashd`
Configuration file: `~/Library/Application Support/DashCore/dash.conf`
@@ -111,7 +111,7 @@ Using this script, you can adjust the path and flags to the dashd program by
setting the DASHD and FLAGS environment variables in the file
/etc/sysconfig/dashd. You can also use the DAEMONOPTS environment variable here.
-### Mac OS X
+### macOS
Copy org.dash.dashd.plist into ~/Library/LaunchAgents. Load the launch agent by
running `launchctl load ~/Library/LaunchAgents/org.dash.dashd.plist`.
diff --git a/doc/release-process.md b/doc/release-process.md
index 425ecba97e0d..5ea90f7fe711 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -85,7 +85,7 @@ Ensure gitian-builder is up-to-date:
echo '5a60e0a4b3e0b4d655317b2f12a810211c50242138322b16e7e01c6fbb89d92f inputs/osslsigncode-2.0.tar.gz' | sha256sum -c
popd
-Create the OS X SDK tarball, see the [OS X readme](README_osx.md) for details, and copy it into the inputs directory.
+Create the macOS SDK tarball, see the [macOS readme](README_osx.md) for details, and copy it into the inputs directory.
### Optional: Seed the Gitian sources cache and offline git repositories
@@ -107,7 +107,7 @@ NOTE: Offline builds must use the --url flag to ensure Gitian fetches only from
The gbuild invocations below DO NOT DO THIS by default.
-### Build and sign Dash Core for Linux, Windows, and OS X:
+### Build and sign Dash Core for Linux, Windows, and macOS:
pushd ./gitian-builder
./bin/gbuild --num-make 2 --memory 3000 --commit dash=v${VERSION} ../dash/contrib/gitian-descriptors/gitian-linux.yml
@@ -130,7 +130,7 @@ Build output expected:
1. source tarball (`dash-${VERSION}.tar.gz`)
2. linux 32-bit and 64-bit dist tarballs (`dash-${VERSION}-linux[32|64].tar.gz`)
3. windows 32-bit and 64-bit unsigned installers and dist zips (`dash-${VERSION}-win[32|64]-setup-unsigned.exe`, `dash-${VERSION}-win[32|64].zip`)
- 4. OS X unsigned installer and dist tarball (`dash-${VERSION}-osx-unsigned.dmg`, `dash-${VERSION}-osx64.tar.gz`)
+ 4. macOS unsigned installer and dist tarball (`dash-${VERSION}-osx-unsigned.dmg`, `dash-${VERSION}-osx64.tar.gz`)
5. Gitian signatures (in `gitian.sigs/${VERSION}-/(your Gitian key)/`)
### Verify other gitian builders signatures to your own. (Optional)
@@ -160,13 +160,13 @@ Commit your signature to gitian.sigs:
git push # Assuming you can push to the gitian.sigs tree
popd
-Codesigner only: Create Windows/OS X detached signatures:
+Codesigner only: Create Windows/macOS detached signatures:
- Only one person handles codesigning. Everyone else should skip to the next step.
-- Only once the Windows/OS X builds each have 3 matching signatures may they be signed with their respective release keys.
+- Only once the Windows/macOS builds each have 3 matching signatures may they be signed with their respective release keys.
-Codesigner only: Sign the osx binary:
+Codesigner only: Sign the macOS binary:
- transfer dashcore-osx-unsigned.tar.gz to osx for signing
+ transfer dashcore-osx-unsigned.tar.gz to macOS for signing
tar xf dashcore-osx-unsigned.tar.gz
./detached-sig-create.sh -s "Key ID" -o runtime
Enter the keychain password and authorize the signature
@@ -191,12 +191,12 @@ Codesigner only: Commit the detached codesign payloads:
git tag -s v${VERSION} HEAD
git push the current branch and new tag
-Non-codesigners: wait for Windows/OS X detached signatures:
+Non-codesigners: wait for Windows/macOS detached signatures:
-- Once the Windows/OS X builds each have 3 matching signatures, they will be signed with their respective release keys.
+- Once the Windows/macOS builds each have 3 matching signatures, they will be signed with their respective release keys.
- Detached signatures will then be committed to the [dash-detached-sigs](https://github.com/dashpay/dash-detached-sigs) repository, which can be combined with the unsigned apps to create signed binaries.
-Create (and optionally verify) the signed OS X binary:
+Create (and optionally verify) the signed macOS binary:
pushd ./gitian-builder
./bin/gbuild -i --commit signature=v${VERSION} ../dash/contrib/gitian-descriptors/gitian-osx-signer.yml
@@ -215,7 +215,7 @@ Create (and optionally verify) the signed Windows binaries:
mv build/out/dash-*win32-setup.exe ../dash-${VERSION}-win32-setup.exe
popd
-Commit your signature for the signed OS X/Windows binaries:
+Commit your signature for the signed macOS/Windows binaries:
pushd gitian.sigs
git add ${VERSION}-osx-signed/"${SIGNER}"
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index e1dbff91ec01..9d5053c2175b 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -195,8 +195,8 @@ if EMBEDDED_UNIVALUE
endif
%.cpp.test: %.cpp
- @echo Running tests: `cat $< | grep "BOOST_FIXTURE_TEST_SUITE(\|BOOST_AUTO_TEST_SUITE(" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1` from $<
- $(AM_V_at)$(TEST_BINARY) -l test_suite -t "`cat $< | grep "BOOST_FIXTURE_TEST_SUITE(\|BOOST_AUTO_TEST_SUITE(" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1`" > $<.log 2>&1 || (cat $<.log && false)
+ @echo Running tests: `cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1` from $<
+ $(AM_V_at)$(TEST_BINARY) -l test_suite -t "`cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1`" > $<.log 2>&1 || (cat $<.log && false)
test/data/%.json.h: test/data/%.json
@$(MKDIR_P) $(@D)
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index d4b0ec6152de..311ac9a40438 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -64,14 +64,6 @@ class base_uint
explicit base_uint(const std::string& str);
- bool operator!() const
- {
- for (int i = 0; i < WIDTH; i++)
- if (pn[i] != 0)
- return false;
- return true;
- }
-
const base_uint operator~() const
{
base_uint ret;
diff --git a/src/bench/bench_dash.cpp b/src/bench/bench_dash.cpp
index fcbc5f50ac10..749085d3fd9f 100644
--- a/src/bench/bench_dash.cpp
+++ b/src/bench/bench_dash.cpp
@@ -6,12 +6,11 @@
#include
#include
+#include
#include
-#include
+#include
#include
-#include
-
-#include
+#include
#include
@@ -48,17 +47,25 @@ static void SetupBenchArgs()
gArgs.AddArg("-plot-plotlyurl=", strprintf("URL to use for plotly.js (default: %s)", DEFAULT_PLOT_PLOTLYURL), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-plot-width=", strprintf("Plot width in pixel (default: %u)", DEFAULT_PLOT_WIDTH), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-plot-height=", strprintf("Plot height in pixel (default: %u)", DEFAULT_PLOT_HEIGHT), false, OptionsCategory::OPTIONS);
+
+ // Hidden
+ gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
+ gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
}
int main(int argc, char** argv)
{
SetupBenchArgs();
- gArgs.ParseParameters(argc, argv);
+ std::string error;
+ if (!gArgs.ParseParameters(argc, argv, error)) {
+ fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ return EXIT_FAILURE;
+ }
if (HelpRequested(gArgs)) {
std::cout << gArgs.GetHelpMessage();
- return 0;
+ return EXIT_SUCCESS;
}
// Set the datadir after parsing the bench options
@@ -82,8 +89,11 @@ int main(int argc, char** argv)
std::string scaling_str = gArgs.GetArg("-scaling", DEFAULT_BENCH_SCALING);
bool is_list_only = gArgs.GetBoolArg("-list", false);
- double scaling_factor = boost::lexical_cast(scaling_str);
-
+ double scaling_factor;
+ if (!ParseDouble(scaling_str, &scaling_factor)) {
+ fprintf(stderr, "Error parsing scaling factor as double: %s\n", scaling_str.c_str());
+ return EXIT_FAILURE;
+ }
std::unique_ptr printer(new benchmark::ConsolePrinter());
std::string printer_arg = gArgs.GetArg("-printer", DEFAULT_BENCH_PRINTER);
@@ -103,4 +113,6 @@ int main(int argc, char** argv)
CleanupBLSTests();
ECC_Stop();
+
+ return EXIT_SUCCESS;
}
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 86b2d8700060..d68795bd0371 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -37,24 +37,22 @@ static void CoinSelection(benchmark::State& state)
std::vector groups;
LOCK(wallet.cs_wallet);
- while (state.KeepRunning()) {
- // Add coins.
- for (int i = 0; i < 1000; i++)
- addCoin(1000 * COIN, wallet, groups);
- addCoin(3 * COIN, wallet, groups);
+ // Add coins.
+ for (int i = 0; i < 1000; ++i) {
+ addCoin(1000 * COIN, wallet, groups);
+ }
+ addCoin(3 * COIN, wallet, groups);
+ const CoinEligibilityFilter filter_standard(1, 6, 0);
+ const CoinSelectionParams coin_selection_params(true, 34, 148, CFeeRate(0), 0);
+ while (state.KeepRunning()) {
std::set setCoinsRet;
CAmount nValueRet;
bool bnb_used;
- CoinEligibilityFilter filter_standard(1, 6, 0);
- CoinSelectionParams coin_selection_params(false, 34, 148, CFeeRate(0), 0);
- bool success = wallet.SelectCoinsMinConf(1003 * COIN, filter_standard, groups, setCoinsRet, nValueRet, coin_selection_params, bnb_used)
- || wallet.SelectCoinsMinConf(1003 * COIN, filter_standard, groups, setCoinsRet, nValueRet, coin_selection_params, bnb_used);
+ bool success = wallet.SelectCoinsMinConf(1003 * COIN, filter_standard, groups, setCoinsRet, nValueRet, coin_selection_params, bnb_used);
assert(success);
assert(nValueRet == 1003 * COIN);
assert(setCoinsRet.size() == 2);
-
- groups.clear();
}
}
diff --git a/src/coinjoin/coinjoin-client.cpp b/src/coinjoin/coinjoin-client.cpp
index e03fdd349d09..0dfe53edeb07 100644
--- a/src/coinjoin/coinjoin-client.cpp
+++ b/src/coinjoin/coinjoin-client.cpp
@@ -449,7 +449,7 @@ bool CCoinJoinClientSession::SendDenominate(const std::vector pwalletIn, con
SignatureData sigdata;
bool res = ProduceSignature(*pwallet, DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigdata);
assert(res);
- UpdateTransaction(dummyTx, nIn, sigdata);
+ UpdateInput(dummyTx.vin[nIn], sigdata);
nIn++;
}
}
diff --git a/src/coinjoin/coinjoin.h b/src/coinjoin/coinjoin.h
index 6912110b6f6a..e5b926934943 100644
--- a/src/coinjoin/coinjoin.h
+++ b/src/coinjoin/coinjoin.h
@@ -154,7 +154,7 @@ class CCoinJoinAccept
friend bool operator==(const CCoinJoinAccept& a, const CCoinJoinAccept& b)
{
- return a.nDenom == b.nDenom && a.txCollateral == b.txCollateral;
+ return a.nDenom == b.nDenom && CTransaction(a.txCollateral) == CTransaction(b.txCollateral);
}
};
diff --git a/src/dash-cli.cpp b/src/dash-cli.cpp
index 7ea565af51c7..cf97031aa0b4 100644
--- a/src/dash-cli.cpp
+++ b/src/dash-cli.cpp
@@ -43,6 +43,7 @@ static void SetupCliArgs()
gArgs.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-rpcclienttimeout=", strprintf("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-rpcconnect=", strprintf("Send commands to node running on (default: %s)", DEFAULT_RPCCONNECT), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-rpccookiefile=", _("Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)"), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-rpcpassword=", "Password for JSON-RPC connections", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-rpcport=", strprintf("Connect to JSON-RPC on (default: %u or testnet: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-rpcuser=", "Username for JSON-RPC connections", false, OptionsCategory::OPTIONS);
@@ -52,6 +53,22 @@ static void SetupCliArgs()
gArgs.AddArg("-stdinrpcpass", strprintf("Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password."), false, OptionsCategory::OPTIONS);
SetupChainParamsBaseOptions();
+
+ // Hidden
+ gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
+ gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
+}
+
+/** libevent event log callback */
+static void libevent_log_cb(int severity, const char *msg)
+{
+#ifndef EVENT_LOG_ERR // EVENT_LOG_ERR was added in 2.0.19; but before then _EVENT_LOG_ERR existed.
+# define EVENT_LOG_ERR _EVENT_LOG_ERR
+#endif
+ // Ignore everything other than errors
+ if (severity >= EVENT_LOG_ERR) {
+ throw std::runtime_error(strprintf("libevent error: %s", msg));
+ }
}
//////////////////////////////////////////////////////////////////////////////
@@ -83,7 +100,11 @@ static int AppInitRPC(int argc, char* argv[])
// Parameters
//
SetupCliArgs();
- gArgs.ParseParameters(argc, argv);
+ std::string error;
+ if (!gArgs.ParseParameters(argc, argv, error)) {
+ fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ return EXIT_FAILURE;
+ }
if (gArgs.IsArgSet("-printcrashinfo")) {
std::cout << GetCrashInfoStrFromSerializedStr(gArgs.GetArg("-printcrashinfo", "")) << std::endl;
@@ -114,10 +135,8 @@ static int AppInitRPC(int argc, char* argv[])
fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return EXIT_FAILURE;
}
- try {
- gArgs.ReadConfigFiles();
- } catch (const std::exception& e) {
- fprintf(stderr,"Error reading configuration file: %s\n", e.what());
+ if (!gArgs.ReadConfigFiles(error, true)) {
+ fprintf(stderr, "Error reading configuration file: %s\n", error.c_str());
return EXIT_FAILURE;
}
if (!datadirFromCmdLine && !fs::is_directory(GetDataDir(false))) {
@@ -517,6 +536,7 @@ int main(int argc, char* argv[])
fprintf(stderr, "Error: Initializing networking failed\n");
return EXIT_FAILURE;
}
+ event_set_log_callback(&libevent_log_cb);
try {
int ret = AppInitRPC(argc, argv);
diff --git a/src/dash-tx.cpp b/src/dash-tx.cpp
index fd4152b1d7e3..5fe7e7d6f552 100644
--- a/src/dash-tx.cpp
+++ b/src/dash-tx.cpp
@@ -61,6 +61,10 @@ static void SetupBitcoinTxArgs()
gArgs.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", false, OptionsCategory::REGISTER_COMMANDS);
gArgs.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", false, OptionsCategory::REGISTER_COMMANDS);
+
+ // Hidden
+ gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
+ gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
}
//
@@ -73,7 +77,11 @@ static int AppInitRawTx(int argc, char* argv[])
// Parameters
//
SetupBitcoinTxArgs();
- gArgs.ParseParameters(argc, argv);
+ std::string error;
+ if (!gArgs.ParseParameters(argc, argv, error)) {
+ fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ return EXIT_FAILURE;
+ }
if (gArgs.IsArgSet("-printcrashinfo")) {
std::cout << GetCrashInfoStrFromSerializedStr(gArgs.GetArg("-printcrashinfo", "")) << std::endl;
@@ -501,7 +509,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
// mergedTx will end up with all the signatures; it
// starts as a clone of the raw tx:
CMutableTransaction mergedTx{tx};
- const CTransaction txv{tx};
+ const CMutableTransaction txv{tx};
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
@@ -584,7 +592,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
- const CTxIn& txin = mergedTx.vin[i];
+ CTxIn& txin = mergedTx.vin[i];
const Coin& coin = view.AccessCoin(txin.prevout);
if (coin.IsSpent()) {
continue;
@@ -592,14 +600,12 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
const CScript& prevPubKey = coin.out.scriptPubKey;
const CAmount& amount = coin.out.nValue;
- SignatureData sigdata;
+ SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out);
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
ProduceSignature(keystore, MutableTransactionSignatureCreator(&mergedTx, i, amount, nHashType), prevPubKey, sigdata);
- // ... and merge in other signatures:
- sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
- UpdateTransaction(mergedTx, i, sigdata);
+ UpdateInput(txin, sigdata);
}
tx = mergedTx;
diff --git a/src/dashd.cpp b/src/dashd.cpp
index a5e90b1b3d8b..3dd8012093c8 100644
--- a/src/dashd.cpp
+++ b/src/dashd.cpp
@@ -65,10 +65,11 @@ static bool AppInit(int argc, char* argv[])
//
// If Qt is used, parameters/dash.conf are parsed in qt/dash.cpp's main()
SetupServerArgs();
-#if HAVE_DECL_DAEMON
- gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", false, OptionsCategory::OPTIONS);
-#endif
- gArgs.ParseParameters(argc, argv);
+ std::string error;
+ if (!gArgs.ParseParameters(argc, argv, error)) {
+ fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ return false;
+ }
if (gArgs.IsArgSet("-printcrashinfo")) {
std::cout << GetCrashInfoStrFromSerializedStr(gArgs.GetArg("-printcrashinfo", "")) << std::endl;
@@ -103,11 +104,8 @@ static bool AppInit(int argc, char* argv[])
fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return false;
}
- try
- {
- gArgs.ReadConfigFiles();
- } catch (const std::exception& e) {
- fprintf(stderr,"Error reading configuration file: %s\n", e.what());
+ if (!gArgs.ReadConfigFiles(error)) {
+ fprintf(stderr, "Error reading configuration file: %s\n", error.c_str());
return false;
}
if (!datadirFromCmdLine && !fs::is_directory(GetDataDir(false)))
diff --git a/src/hdchain.cpp b/src/hdchain.cpp
index 192c8dc2e1e5..78a6631698f9 100644
--- a/src/hdchain.cpp
+++ b/src/hdchain.cpp
@@ -55,7 +55,7 @@ void CHDChain::Debug(const std::string& strName) const
std::cout << "seed: " << HexStr(vchSeed).c_str() << std::endl;
CExtKey extkey;
- extkey.SetMaster(vchSeed.data(), vchSeed.size());
+ extkey.SetSeed(vchSeed.data(), vchSeed.size());
std::cout << "extended private masterkey: " << EncodeExtKey(extkey).c_str() << std::endl;
@@ -167,7 +167,7 @@ void CHDChain::DeriveChildExtKey(uint32_t nAccountIndex, bool fInternal, uint32_
CExtKey changeKey; //key at m/purpose'/coin_type'/account'/change
CExtKey childKey; //key at m/purpose'/coin_type'/account'/change/address_index
- masterKey.SetMaster(vchSeed.data(), vchSeed.size());
+ masterKey.SetSeed(vchSeed.data(), vchSeed.size());
// Use hardened derivation for purpose, coin_type and account
// (keys >= 0x80000000 are hardened after bip32)
diff --git a/src/init.cpp b/src/init.cpp
index d1b32f4f6053..800307cf1dac 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -110,7 +110,7 @@ std::unique_ptr peerLogic;
class DummyWalletInit : public WalletInitInterface {
public:
- void AddWalletOptions() const override {}
+ void AddWalletOptions() const override;
bool ParameterInteraction() const override {return true;}
void RegisterRPC(CRPCTable &) const override {}
bool Verify() const override {return true;}
@@ -127,6 +127,21 @@ class DummyWalletInit : public WalletInitInterface {
bool InitAutoBackup() const override {return true;}
};
+void DummyWalletInit::AddWalletOptions() const
+{
+ std::vector opts = {"-createwalletbackups=", "-disablewallet", "-instantsendnotify=",
+ "-keypool=", "-rescan=", "-salvagewallet", "-spendzeroconfchange", "-upgradewallet",
+ "-wallet=", "-walletbackupsdir=", "-walletbroadcast", "-walletdir=",
+ "-walletnotify=", "-zapwallettxes=", "-discardfee=", "-fallbackfee=",
+ "-mintxfee=", "-paytxfee=", "-txconfirmtarget=", "-hdseed=", "-mnemonic=",
+ "-mnemonicpassphrase=", "-usehd", "-keepass", "-keepassid=", "-keepasskey=",
+ "-keepassname=", "-keepassport=", "-enablecoinjoin", "-coinjoinamount=",
+ "-coinjoinautostart", "-coinjoindenomsgoal=", "-coinjoindenomshardcap=", "-coinjoinmultisession",
+ "-coinjoinrounds=", "-coinjoinsessions=", "-dblogsize=", "-flushwallet", "-privdb",
+ "-walletrejectlongchains"};
+ gArgs.AddHiddenArgs(opts);
+}
+
const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();
#endif
@@ -476,6 +491,12 @@ void SetupServerArgs()
const auto regtestLLMQ = CreateChainParams(CBaseChainParams::REGTEST)->GetConsensus().llmqs.at(Consensus::LLMQ_TEST);
+ // Hidden Options
+ std::vector hidden_args = {"-rpcssl", "-benchmark", "-h", "-help", "-socks", "-tor", "-debugnet", "-whitelistalwaysrelay",
+ "-blockminsize", "-dbcrashratio", "-forcecompactdb",
+ // GUI args. These will be overwritten by SetupUIArgs for the GUI
+ "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=", "-min", "-resetguisettings", "-rootcertificates=", "-splash", "-uiplatform"};
+
// Set all of the args and their help
// When adding new options to the categories, please keep and ensure alphabetical ordering.
@@ -503,6 +524,8 @@ void SetupServerArgs()
gArgs.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), false, OptionsCategory::OPTIONS);
#ifndef WIN32
gArgs.AddArg("-pid=", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), false, OptionsCategory::OPTIONS);
+#else
+ hidden_args.emplace_back("-pid");
#endif
gArgs.AddArg("-prune=", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex, -rescan and -disablegovernance=false. "
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
@@ -510,6 +533,8 @@ void SetupServerArgs()
gArgs.AddArg("-syncmempool", strprintf("Sync mempool from other nodes on start (default: %u)", DEFAULT_SYNC_MEMPOOL), false, OptionsCategory::OPTIONS);
#ifndef WIN32
gArgs.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", false, OptionsCategory::OPTIONS);
+#else
+ hidden_args.emplace_back("-sysperms");
#endif
gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS);
@@ -559,6 +584,8 @@ void SetupServerArgs()
#else
gArgs.AddArg("-upnp", strprintf("Use UPnP to map the listening port (default: %u)", 0), false, OptionsCategory::CONNECTION);
#endif
+#else
+ hidden_args.emplace_back("-upnp");
#endif
gArgs.AddArg("-whitebind=", "Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6", false, OptionsCategory::CONNECTION);
gArgs.AddArg("-whitelist=", "Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times."
@@ -568,6 +595,7 @@ void SetupServerArgs()
#if ENABLE_ZMQ
gArgs.AddArg("-zmqpubhashblock=", "Enable publish hash block in ", false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubhashchainlock=", "Enable publish hash block (locked via ChainLocks) in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubhashgovernanceobject=", "Enable publish hash of governance objects (like proposals) in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubhashgovernancevote=", "Enable publish hash of governance votes in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubhashinstantsenddoublespend=", "Enable publish transaction hashes of attempted InstantSend double spend in ", false, OptionsCategory::ZMQ);
@@ -575,10 +603,34 @@ void SetupServerArgs()
gArgs.AddArg("-zmqpubhashtx=", "Enable publish hash transaction in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubhashtxlock=", "Enable publish hash transaction (locked via InstantSend) in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawblock=", "Enable publish raw block in ", false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubrawchainlock=", "Enable publish raw block (locked via ChainLocks) in ", false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubrawchainlocksig=", "Enable publish raw block (locked via ChainLocks) and CLSIG message in ", false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubrawgovernancevote=", "Enable publish raw governance objects (like proposals) in ", false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubrawgovernanceobject=", "Enable publish raw governance votes in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawinstantsenddoublespend=", "Enable publish raw transactions of attempted InstantSend double spend in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawrecoveredsig=", "Enable publish raw recovered signatures (recovered by LLMQs) in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawtx=", "Enable publish raw transaction in ", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawtxlock=", "Enable publish raw transaction (locked via InstantSend) in ", false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubrawtxlocksig=", "Enable publish raw transaction (locked via InstantSend) and ISLOCK in ", false, OptionsCategory::ZMQ);
+#else
+ hidden_args.emplace_back("-zmqpubhashblock=");
+ hidden_args.emplace_back("-zmqpubhashchainlock=");
+ hidden_args.emplace_back("-zmqpubhashgovernanceobject=");
+ hidden_args.emplace_back("-zmqpubhashgovernancevote=");
+ hidden_args.emplace_back("-zmqpubhashinstantsenddoublespend=");
+ hidden_args.emplace_back("-zmqpubhashrecoveredsig=");
+ hidden_args.emplace_back("-zmqpubhashtx=");
+ hidden_args.emplace_back("-zmqpubhashtxlock=");
+ hidden_args.emplace_back("-zmqpubrawblock=");
+ hidden_args.emplace_back("-zmqpubrawchainlock=");
+ hidden_args.emplace_back("-zmqpubrawchainlocksig=");
+ hidden_args.emplace_back("-zmqpubrawgovernancevote=");
+ hidden_args.emplace_back("-zmqpubrawgovernanceobject=");
+ hidden_args.emplace_back("-zmqpubrawinstantsenddoublespend=");
+ hidden_args.emplace_back("-zmqpubrawrecoveredsig=");
+ hidden_args.emplace_back("-zmqpubrawtx=");
+ hidden_args.emplace_back("-zmqpubrawtxlock=");
+ hidden_args.emplace_back("-zmqpubrawtxlocksig=");
#endif
gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. (default: %u)", defaultChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST);
@@ -598,9 +650,12 @@ void SetupServerArgs()
gArgs.AddArg("-watchquorums=", strprintf("Watch and validate quorum communication (default: %u)", llmq::DEFAULT_WATCH_QUORUMS), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-addrmantest", "Allows to test address relay on localhost", true, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-budgetparams=::", "Override masternode, budget and superblock start heights", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-debug=", strprintf("Output debugging information (default: %u, supplying is optional)", 0) + ". " +
"If is not supplied or if = 1, output all debugging information. can be: " + ListLogCategories() + ".", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-debugexclude=", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories."), false, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-dip3params=:", "Override DIP3 activation and enforcement heights", false, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-dip8params=", "Override DIP8 activation height", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-disablegovernance", strprintf("Disable governance validation (0-1, default: %u)", 0), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-help-debug", "Show all debugging options (usage: --help -help-debug)", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-highsubsidyblocks=", strprintf("The number of blocks with a higher than normal subsidy to mine at the start of a devnet (default: %u)", devnetConsensus.nHighSubsidyBlocks), false, OptionsCategory::DEBUG_TEST);
@@ -622,6 +677,7 @@ void SetupServerArgs()
gArgs.AddArg("-minsporkkeys=", "Overrides minimum spork signers to change spork value. Only useful for regtest and devnet. Using this on mainnet or testnet will ban you.", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-printtoconsole", "Send trace/debug info to console instead of debug.log file", false, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-pushversion", "Protocol version to report to other nodes", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-sporkaddr=", "Override spork address. Only useful for regtest and devnet. Using this on mainnet or testnet will ban you.", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-sporkkey=", "Set the private key to be used for signing spork messages.", false, OptionsCategory::DEBUG_TEST);
@@ -668,6 +724,14 @@ void SetupServerArgs()
gArgs.AddArg("-statsport=", strprintf("Specify statsd port (default: %u)", DEFAULT_STATSD_PORT), false, OptionsCategory::STATSD);
gArgs.AddArg("-statsns=", strprintf("Specify additional namespace prefix (default: %s)", DEFAULT_STATSD_NAMESPACE), false, OptionsCategory::STATSD);
gArgs.AddArg("-statsperiod=", strprintf("Specify the number of seconds between periodic measurements (default: %d)", DEFAULT_STATSD_PERIOD), false, OptionsCategory::STATSD);
+#if HAVE_DECL_DAEMON
+ gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", false, OptionsCategory::OPTIONS);
+#else
+ hidden_args.emplace_back("-daemon");
+#endif
+
+ // Add the hidden options
+ gArgs.AddHiddenArgs(hidden_args);
}
std::string LicenseInfo()
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 99b68d6786af..7279a9a7b02f 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -160,11 +160,11 @@ class NodeImpl : public Node
CoinJoinOptionsImpl m_coinjoin;
#endif
- void parseParameters(int argc, const char* const argv[]) override
+ bool parseParameters(int argc, const char* const argv[], std::string& error) override
{
- gArgs.ParseParameters(argc, argv);
+ return gArgs.ParseParameters(argc, argv, error);
}
- void readConfigFiles() override { gArgs.ReadConfigFiles(); }
+ bool readConfigFiles(std::string& error) override { return gArgs.ReadConfigFiles(error); }
bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); }
bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); }
void selectParams(const std::string& network) override { SelectParams(network); }
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 58223ca66cb1..f2a918be279d 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -93,7 +93,7 @@ class Node
virtual ~Node() {}
//! Set command line arguments.
- virtual void parseParameters(int argc, const char* const argv[]) = 0;
+ virtual bool parseParameters(int argc, const char* const argv[], std::string& error) = 0;
//! Set a command line argument if it doesn't already have a value
virtual bool softSetArg(const std::string& arg, const std::string& value) = 0;
@@ -102,7 +102,7 @@ class Node
virtual bool softSetBoolArg(const std::string& arg, bool value) = 0;
//! Load settings from configuration file.
- virtual void readConfigFiles() = 0;
+ virtual bool readConfigFiles(std::string& error) = 0;
//! Choose network parameters.
virtual void selectParams(const std::string& network) = 0;
diff --git a/src/key.cpp b/src/key.cpp
index a75d56618d84..860f1ded8d76 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -273,7 +273,7 @@ bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
return key.Derive(out.key, out.chaincode, _nChild, chaincode);
}
-void CExtKey::SetMaster(const unsigned char *seed, unsigned int nSeedLen) {
+void CExtKey::SetSeed(const unsigned char *seed, unsigned int nSeedLen) {
static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
std::vector> vout(64);
CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(vout.data());
diff --git a/src/key.h b/src/key.h
index 585363107bd4..92e31652da03 100644
--- a/src/key.h
+++ b/src/key.h
@@ -158,7 +158,7 @@ struct CExtKey {
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
bool Derive(CExtKey& out, unsigned int nChild) const;
CExtPubKey Neuter() const;
- void SetMaster(const unsigned char* seed, unsigned int nSeedLen);
+ void SetSeed(const unsigned char* seed, unsigned int nSeedLen);
template
void Serialize(Stream& s) const
{
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 3a8764d4085a..012013934f4e 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -43,26 +43,26 @@ static const unsigned int DUST_RELAY_TX_FEE = 3000;
* with. However scripts violating these flags may still be present in valid
* blocks and we must accept those blocks.
*/
-static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
- SCRIPT_VERIFY_DERSIG |
- SCRIPT_VERIFY_STRICTENC |
- SCRIPT_VERIFY_MINIMALDATA |
- SCRIPT_VERIFY_NULLDUMMY |
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
- SCRIPT_VERIFY_CLEANSTACK |
- SCRIPT_VERIFY_NULLFAIL |
- SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
- SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
- SCRIPT_VERIFY_LOW_S |
- SCRIPT_ENABLE_DIP0020_OPCODES |
- SCRIPT_VERIFY_CONST_SCRIPTCODE;
+static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
+ SCRIPT_VERIFY_DERSIG |
+ SCRIPT_VERIFY_STRICTENC |
+ SCRIPT_VERIFY_MINIMALDATA |
+ SCRIPT_VERIFY_NULLDUMMY |
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
+ SCRIPT_VERIFY_CLEANSTACK |
+ SCRIPT_VERIFY_NULLFAIL |
+ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
+ SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
+ SCRIPT_VERIFY_LOW_S |
+ SCRIPT_ENABLE_DIP0020_OPCODES |
+ SCRIPT_VERIFY_CONST_SCRIPTCODE;
/** For convenience, standard but not mandatory verify flags. */
-static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
+static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
-static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
- LOCKTIME_MEDIAN_TIME_PAST;
+static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
+ LOCKTIME_MEDIAN_TIME_PAST;
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index a2c8fcd92721..03221d7d8822 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -91,9 +91,9 @@ uint256 CTransaction::ComputeHash() const
}
/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */
-CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nType(TRANSACTION_NORMAL), nLockTime(0), hash() {}
-CTransaction::CTransaction(const CMutableTransaction &tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nType(tx.nType), nLockTime(tx.nLockTime), vExtraPayload(tx.vExtraPayload), hash(ComputeHash()) {}
-CTransaction::CTransaction(CMutableTransaction &&tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nType(tx.nType), nLockTime(tx.nLockTime), vExtraPayload(tx.vExtraPayload), hash(ComputeHash()) {}
+CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nType(TRANSACTION_NORMAL), nLockTime(0), hash{} {}
+CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nType(tx.nType), nLockTime(tx.nLockTime), vExtraPayload(tx.vExtraPayload), hash{ComputeHash()} {}
+CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nType(tx.nType), nLockTime(tx.nLockTime), vExtraPayload(tx.vExtraPayload), hash{ComputeHash()} {}
CAmount CTransaction::GetValueOut() const
{
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 06744ddb7867..091c498a8e85 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -232,9 +232,7 @@ class CTransaction
return vin.empty() && vout.empty();
}
- const uint256& GetHash() const {
- return hash;
- }
+ const uint256& GetHash() const { return hash; }
// Return sum of txouts.
CAmount GetValueOut() const;
@@ -277,7 +275,7 @@ struct CMutableTransaction
std::vector vExtraPayload; // only available for special transaction types
CMutableTransaction();
- CMutableTransaction(const CTransaction& tx);
+ explicit CMutableTransaction(const CTransaction& tx);
SERIALIZE_METHODS(CMutableTransaction, obj)
{
@@ -303,17 +301,6 @@ struct CMutableTransaction
uint256 GetHash() const;
std::string ToString() const;
-
- friend bool operator==(const CMutableTransaction& a, const CMutableTransaction& b)
- {
- return a.GetHash() == b.GetHash();
- }
-
- friend bool operator!=(const CMutableTransaction& a, const CMutableTransaction& b)
- {
- return !(a == b);
- }
-
};
typedef std::shared_ptr CTransactionRef;
diff --git a/src/pubkey.h b/src/pubkey.h
index 875ab76bf6de..cf61c4aabed7 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -33,10 +33,10 @@ class CPubKey
/**
* secp256k1:
*/
- static const unsigned int PUBLIC_KEY_SIZE = 65;
- static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33;
- static const unsigned int SIGNATURE_SIZE = 72;
- static const unsigned int COMPACT_SIGNATURE_SIZE = 65;
+ static constexpr unsigned int PUBLIC_KEY_SIZE = 65;
+ static constexpr unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33;
+ static constexpr unsigned int SIGNATURE_SIZE = 72;
+ static constexpr unsigned int COMPACT_SIGNATURE_SIZE = 65;
/**
* see www.keylength.com
* script supports up to 75 for single byte push
diff --git a/src/qt/README.md b/src/qt/README.md
index cba965b7a750..255d8400b1a9 100644
--- a/src/qt/README.md
+++ b/src/qt/README.md
@@ -4,7 +4,7 @@ The current precise version for Qt 5 is specified in [qt.mk](/depends/packages/q
## Compile and run
-See build instructions ([OSX](/doc/build-osx.md), [Windows](/doc/build-windows.md), [Unix](/doc/build-unix.md), etc).
+See build instructions ([macOS](/doc/build-osx.md), [Windows](/doc/build-windows.md), [Unix](/doc/build-unix.md), etc).
To run:
@@ -65,7 +65,7 @@ Represents the view to a single wallet.
* `guiconstants.h`: UI colors, app name, etc
* `guiutil.h`: several helper functions
* `macdockiconhandler.(h/cpp)`
-* `macdockiconhandler.(h/cpp)`: display notifications in OSX
+* `macdockiconhandler.(h/cpp)`: display notifications in macOS
## Contribute
@@ -81,9 +81,9 @@ the UI layout.
Download and install the community edition of [Qt Creator](https://www.qt.io/download/).
Uncheck everything except Qt Creator during the installation process.
-Instructions for OSX:
+Instructions for macOS:
-1. Make sure you installed everything through Homebrew mentioned in the [OSX build instructions](/doc/build-osx.md)
+1. Make sure you installed everything through Homebrew mentioned in the [macOS build instructions](/doc/build-osx.md)
2. Use `./configure` with the `--enable-debug` flag
3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project
4. Enter "dash-qt" as project name, enter src/qt as location
diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp
index 21efd607afb0..b1fc4c735df1 100644
--- a/src/qt/dash.cpp
+++ b/src/qt/dash.cpp
@@ -580,15 +580,9 @@ int main(int argc, char *argv[])
std::unique_ptr node = interfaces::MakeNode();
- /// 1. Parse command-line options. These take precedence over anything else.
- // Command-line options take precedence:
- node->setupServerArgs();
- SetupUIArgs();
- node->parseParameters(argc, argv);
-
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
- /// 2. Basic Qt initialization (not dependent on parameters or configuration)
+ /// 1. Basic Qt initialization (not dependent on parameters or configuration)
Q_INIT_RESOURCE(dash);
Q_INIT_RESOURCE(dash_locale);
@@ -613,6 +607,17 @@ int main(int argc, char *argv[])
qRegisterMetaType("WalletModel*");
#endif
+ /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
+ // Command-line options take precedence:
+ node->setupServerArgs();
+ SetupUIArgs();
+ std::string error;
+ if (!node->parseParameters(argc, argv, error)) {
+ QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
+ QObject::tr("Error parsing command line arguments: %1.").arg(QString::fromStdString(error)));
+ return EXIT_FAILURE;
+ }
+
/// 3. Application identification
// must be set before OptionsModel is initialized or translations are loaded,
// as it is used to locate QSettings
@@ -654,11 +659,9 @@ int main(int argc, char *argv[])
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
return EXIT_FAILURE;
}
- try {
- node->readConfigFiles();
- } catch (const std::exception& e) {
+ if (!node->readConfigFiles(error)) {
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
- QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what()));
+ QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error)));
return EXIT_FAILURE;
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 05f1477754c4..1365ba236224 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -734,19 +734,17 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
if (coin.IsSpent()) {
throw JSONRPCError(RPC_VERIFY_ERROR, "Input not found or already spent");
}
- const CScript& prevPubKey = coin.out.scriptPubKey;
- const CAmount& amount = coin.out.nValue;
-
SignatureData sigdata;
// ... and merge in other signatures:
for (const CMutableTransaction& txv : txVariants) {
if (txv.vin.size() > i) {
- sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
+ sigdata.MergeSignatureData(DataFromTransaction(txv, i, coin.out));
}
}
+ ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&mergedTx, i, coin.out.nValue, 1), coin.out.scriptPubKey, sigdata);
- UpdateTransaction(mergedTx, i, sigdata);
+ UpdateInput(txin, sigdata);
}
return EncodeHexTx(mergedTx);
@@ -871,14 +869,13 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival
const CScript& prevPubKey = coin.out.scriptPubKey;
const CAmount& amount = coin.out.nValue;
- SignatureData sigdata;
+ SignatureData sigdata = DataFromTransaction(mtx, i, coin.out);
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mtx.vout.size())) {
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
}
- sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(mtx, i));
- UpdateTransaction(mtx, i, sigdata);
+ UpdateInput(txin, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 0f7b9e33034d..5e8a5ca9f862 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1032,7 +1032,7 @@ bool EvalScript(std::vector >& stack, const CScript&
CSHA256()
.Write(vchMessage.data(), vchMessage.size())
.Finalize(vchHash.data());
- fSuccess = checker.VerifySignature(vchSig, CPubKey(vchPubKey), uint256(vchHash));
+ fSuccess = CPubKey(vchPubKey).Verify(uint256(vchHash), vchSig);
}
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) {
@@ -1308,9 +1308,11 @@ namespace {
* Wrapper that serializes like CTransaction, but with the modifications
* required for the signature hash done in-place
*/
-class CTransactionSignatureSerializer {
+template
+class CTransactionSignatureSerializer
+{
private:
- const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized)
+ const T& txTo; //!< reference to the spending transaction (the one being serialized)
const CScript& scriptCode; //!< output script being consumed
const unsigned int nIn; //!< input index of txTo being signed
const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set
@@ -1318,7 +1320,7 @@ class CTransactionSignatureSerializer {
const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE
public:
- CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
+ CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
@@ -1402,7 +1404,9 @@ class CTransactionSignatureSerializer {
}
};
-uint256 GetPrevoutHash(const CTransaction& txTo) {
+template
+uint256 GetPrevoutHash(const T& txTo)
+{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txin : txTo.vin) {
ss << txin.prevout;
@@ -1410,7 +1414,9 @@ uint256 GetPrevoutHash(const CTransaction& txTo) {
return ss.GetHash();
}
-uint256 GetSequenceHash(const CTransaction& txTo) {
+template
+uint256 GetSequenceHash(const T& txTo)
+{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txin : txTo.vin) {
ss << txin.nSequence;
@@ -1418,7 +1424,9 @@ uint256 GetSequenceHash(const CTransaction& txTo) {
return ss.GetHash();
}
-uint256 GetOutputsHash(const CTransaction& txTo) {
+template
+uint256 GetOutputsHash(const T& txTo)
+{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txout : txTo.vout) {
ss << txout;
@@ -1428,14 +1436,20 @@ uint256 GetOutputsHash(const CTransaction& txTo) {
} // namespace
-PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
+template
+PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
{
hashPrevouts = GetPrevoutHash(txTo);
hashSequence = GetSequenceHash(txTo);
hashOutputs = GetOutputsHash(txTo);
}
-uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
+// explicit instantiation
+template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
+template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
+
+template
+uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
assert(nIn < txTo.vin.size());
@@ -1450,7 +1464,7 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
}
// Wrapper to serialize only the necessary parts of the transaction being signed
- CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);
+ CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);
// Serialize and hash
CHashWriter ss(SER_GETHASH, 0);
@@ -1458,12 +1472,14 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
return ss.GetHash();
}
-bool BaseSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const
+template
+bool GenericTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
return pubkey.Verify(sighash, vchSig);
}
-bool TransactionSignatureChecker::CheckSig(const std::vector& vchSigIn, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
+template
+bool GenericTransactionSignatureChecker::CheckSig(const std::vector& vchSigIn, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
@@ -1484,7 +1500,8 @@ bool TransactionSignatureChecker::CheckSig(const std::vector& vch
return true;
}
-bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
+template
+bool GenericTransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
{
// There are two kinds of nLockTime: lock-by-blockheight
// and lock-by-blocktime, distinguished by whether
@@ -1520,7 +1537,8 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
return true;
}
-bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
+template
+bool GenericTransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
{
// Relative lock times are supported by comparing the passed
// in operand to the sequence number of the input.
@@ -1566,6 +1584,10 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con
return true;
}
+// explicit instantiation
+template class GenericTransactionSignatureChecker;
+template class GenericTransactionSignatureChecker;
+
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 631ffc834085..dcd98b9a569e 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -110,7 +110,8 @@ struct PrecomputedTransactionData
{
uint256 hashPrevouts, hashSequence, hashOutputs;
- explicit PrecomputedTransactionData(const CTransaction& tx);
+ template
+ explicit PrecomputedTransactionData(const T& tx);
};
enum class SigVersion
@@ -118,13 +119,12 @@ enum class SigVersion
BASE = 0,
};
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
+template
+uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
class BaseSignatureChecker
{
public:
- virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
-
virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
return false;
@@ -143,33 +143,29 @@ class BaseSignatureChecker
virtual ~BaseSignatureChecker() {}
};
-class TransactionSignatureChecker : public BaseSignatureChecker
+template
+class GenericTransactionSignatureChecker : public BaseSignatureChecker
{
private:
- const CTransaction* txTo;
+ const T* txTo;
unsigned int nIn;
const CAmount amount;
const PrecomputedTransactionData* txdata;
-public:
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
-
- // The overriden functions are now final.
- bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const final;
- bool CheckLockTime(const CScriptNum& nLockTime) const final;
- bool CheckSequence(const CScriptNum& nSequence) const final;
-};
-
-class MutableTransactionSignatureChecker : public TransactionSignatureChecker
-{
-private:
- const CTransaction txTo;
+protected:
+ virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
+ GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
+ GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
+ bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
+ bool CheckLockTime(const CScriptNum& nLockTime) const override;
+ bool CheckSequence(const CScriptNum& nSequence) const override;
};
+using TransactionSignatureChecker = GenericTransactionSignatureChecker;
+using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker;
+
bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = nullptr);
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 90ede11a7c7b..40bb3358c6f6 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -27,6 +27,19 @@ enum class IsMineSigVersion
P2SH = 1, //! P2SH redeemScript
};
+/**
+ * This is an internal representation of isminetype + invalidity.
+ * Its order is significant, as we return the max of all explored
+ * possibilities.
+ */
+enum class IsMineResult
+{
+ NO = 0, //! Not ours
+ WATCH_ONLY = 1, //! Included in watch-only balance
+ SPENDABLE = 2, //! Included in all balances
+ INVALID = 3, //! Not spendable by anyone (P2SH inside P2SH)
+};
+
bool PermitsUncompressed(IsMineSigVersion sigversion)
{
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
@@ -41,15 +54,13 @@ bool HaveKeys(const std::vector& pubkeys, const CKeyStore& keystore)
return true;
}
-isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, IsMineSigVersion sigversion)
+IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
{
+ IsMineResult ret = IsMineResult::NO;
+
std::vector vSolutions;
txnouttype whichType;
- if (!Solver(scriptPubKey, whichType, vSolutions)) {
- if (keystore.HaveWatchOnly(scriptPubKey))
- return ISMINE_WATCH_UNSOLVABLE;
- return ISMINE_NO;
- }
+ Solver(scriptPubKey, whichType, vSolutions);
CKeyID keyID;
switch (whichType)
@@ -60,39 +71,43 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
- isInvalid = true;
- return ISMINE_NO;
+ return IsMineResult::INVALID;
+ }
+ if (keystore.HaveKey(keyID)) {
+ ret = std::max(ret, IsMineResult::SPENDABLE);
}
- if (keystore.HaveKey(keyID))
- return ISMINE_SPENDABLE;
break;
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
if (!PermitsUncompressed(sigversion)) {
CPubKey pubkey;
if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
- isInvalid = true;
- return ISMINE_NO;
+ return IsMineResult::INVALID;
}
}
- if (keystore.HaveKey(keyID))
- return ISMINE_SPENDABLE;
+ if (keystore.HaveKey(keyID)) {
+ ret = std::max(ret, IsMineResult::SPENDABLE);
+ }
break;
case TX_SCRIPTHASH:
{
+ if (sigversion != IsMineSigVersion::TOP) {
+ // P2SH inside P2SH is invalid.
+ return IsMineResult::INVALID;
+ }
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) {
- isminetype ret = IsMineInner(keystore, subscript, isInvalid, IsMineSigVersion::P2SH);
- if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))
- return ret;
+ ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::P2SH));
}
break;
}
case TX_MULTISIG:
{
// Never treat bare multisig outputs as ours (they can still be made watchonly-though)
- if (sigversion == IsMineSigVersion::TOP) break;
+ if (sigversion == IsMineSigVersion::TOP) {
+ break;
+ }
// Only consider transactions "mine" if we own ALL the
// keys involved. Multi-signature transactions that are
@@ -103,36 +118,37 @@ isminetype IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, b
if (!PermitsUncompressed(sigversion)) {
for (size_t i = 0; i < keys.size(); i++) {
if (keys[i].size() != 33) {
- isInvalid = true;
- return ISMINE_NO;
+ return IsMineResult::INVALID;
}
}
}
- if (HaveKeys(keys, keystore))
- return ISMINE_SPENDABLE;
+ if (HaveKeys(keys, keystore)) {
+ ret = std::max(ret, IsMineResult::SPENDABLE);
+ }
break;
}
}
- if (keystore.HaveWatchOnly(scriptPubKey)) {
- // TODO: This could be optimized some by doing some work after the above solver
- SignatureData sigs;
- return ProduceSignature(keystore, DUMMY_SIGNATURE_CREATOR, scriptPubKey, sigs) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE;
+ if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
+ ret = std::max(ret, IsMineResult::WATCH_ONLY);
}
- return ISMINE_NO;
+ return ret;
}
} // namespace
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid)
-{
- return IsMineInner(keystore, scriptPubKey, isInvalid, IsMineSigVersion::TOP);
-}
-
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
{
- bool isInvalid = false;
- return IsMine(keystore, scriptPubKey, isInvalid);
+ switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) {
+ case IsMineResult::INVALID:
+ case IsMineResult::NO:
+ return ISMINE_NO;
+ case IsMineResult::WATCH_ONLY:
+ return ISMINE_WATCH_ONLY;
+ case IsMineResult::SPENDABLE:
+ return ISMINE_SPENDABLE;
+ }
+ assert(false);
}
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest)
diff --git a/src/script/ismine.h b/src/script/ismine.h
index 37f4acae0318..c012cc292e3a 100644
--- a/src/script/ismine.h
+++ b/src/script/ismine.h
@@ -17,23 +17,13 @@ class CScript;
enum isminetype
{
ISMINE_NO = 0,
- //! Indicates that we don't know how to create a scriptSig that would solve this if we were given the appropriate private keys
- ISMINE_WATCH_UNSOLVABLE = 1,
- //! Indicates that we know how to create a scriptSig that would solve this if we were given the appropriate private keys
- ISMINE_WATCH_SOLVABLE = 2,
- ISMINE_WATCH_ONLY = ISMINE_WATCH_SOLVABLE | ISMINE_WATCH_UNSOLVABLE,
- ISMINE_SPENDABLE = 4,
+ ISMINE_WATCH_ONLY = 1,
+ ISMINE_SPENDABLE = 2,
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
};
/** used for bitflags of isminetype */
typedef uint8_t isminefilter;
-/* isInvalid becomes true when the script is found invalid by consensus or policy. This will terminate the recursion
- * and return a ISMINE_NO immediately, as an invalid script should never be considered as "mine". This is needed as
- * different SIGVERSION may have different network rules. Currently there is no use of isInvalid but it could be
- * used in the future. See https://github.com/bitcoin/bitcoin/pull/8499 (segwit policy limits) as an example.
- */
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid);
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
diff --git a/src/script/script.cpp b/src/script/script.cpp
index f83a5c9e27a2..78bc07a6f332 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -145,11 +145,6 @@ const char* GetOpName(opcodetype opcode)
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
- // Note:
- // The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum
- // as kind of implementation hack, they are *NOT* real opcodes. If found in real
- // Script, just let the default: case deal with them.
-
default:
return "OP_UNKNOWN";
}
diff --git a/src/script/script.h b/src/script/script.h
index 4a2a506f56e1..05456538afb0 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -187,12 +187,6 @@ enum opcodetype
OP_CHECKDATASIG = 0xba,
OP_CHECKDATASIGVERIFY = 0xbb,
- // template matching params
- OP_SMALLINTEGER = 0xfa,
- OP_PUBKEYS = 0xfb,
- OP_PUBKEYHASH = 0xfd,
- OP_PUBKEY = 0xfe,
-
OP_INVALIDOPCODE = 0xff,
};
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index a071171a0a82..4231250bd0eb 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -14,9 +14,9 @@
typedef std::vector valtype;
-TransactionSignatureCreator::TransactionSignatureCreator(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
+MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
-bool TransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
+bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
{
CKey key;
if (!provider.GetKey(address, key))
@@ -29,27 +29,48 @@ bool TransactionSignatureCreator::CreateSig(const SigningProvider& provider, std
return true;
}
-static bool Sign1(const SigningProvider& provider, const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion)
+static bool GetCScript(const SigningProvider& provider, const SignatureData& sigdata, const CScriptID& scriptid, CScript& script)
{
- std::vector vchSig;
- if (!creator.CreateSig(provider, vchSig, address, scriptCode, sigversion))
- return false;
- ret.push_back(vchSig);
- return true;
+ if (provider.GetCScript(scriptid, script)) {
+ return true;
+ }
+ // Look for scripts in SignatureData
+ if (CScriptID(sigdata.redeem_script) == scriptid) {
+ script = sigdata.redeem_script;
+ return true;
+ }
+ return false;
}
-static bool SignN(const SigningProvider& provider, const std::vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion)
+static bool GetPubKey(const SigningProvider& provider, const SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey)
{
- int nSigned = 0;
- int nRequired = multisigdata.front()[0];
- for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
- {
- const valtype& pubkey = multisigdata[i];
- CKeyID keyID = CPubKey(pubkey).GetID();
- if (Sign1(provider, keyID, creator, scriptCode, ret, sigversion))
- ++nSigned;
+ if (provider.GetPubKey(address, pubkey)) {
+ return true;
}
- return nSigned==nRequired;
+ // Look for pubkey in all partial sigs
+ const auto it = sigdata.signatures.find(address);
+ if (it != sigdata.signatures.end()) {
+ pubkey = it->second.first;
+ return true;
+ }
+ return false;
+}
+
+static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector& sig_out, const CKeyID& keyid, const CScript& scriptcode, SigVersion sigversion)
+{
+ const auto it = sigdata.signatures.find(keyid);
+ if (it != sigdata.signatures.end()) {
+ sig_out = it->second.second;
+ return true;
+ }
+ if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) {
+ CPubKey pubkey;
+ GetPubKey(provider, sigdata, keyid, pubkey);
+ auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out));
+ assert(i.second);
+ return true;
+ }
+ return false;
}
/**
@@ -59,46 +80,57 @@ static bool SignN(const SigningProvider& provider, const std::vector& m
* Returns false if scriptPubKey could not be completely satisfied.
*/
static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey,
- std::vector& ret, txnouttype& whichTypeRet, SigVersion sigversion)
+ std::vector& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
{
CScript scriptRet;
uint160 h160;
ret.clear();
+ std::vector sig;
std::vector vSolutions;
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
return false;
- CKeyID keyID;
switch (whichTypeRet)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
return false;
case TX_PUBKEY:
- keyID = CPubKey(vSolutions[0]).GetID();
- return Sign1(provider, keyID, creator, scriptPubKey, ret, sigversion);
- case TX_PUBKEYHASH:
- keyID = CKeyID(uint160(vSolutions[0]));
- if (!Sign1(provider, keyID, creator, scriptPubKey, ret, sigversion))
- return false;
- else
- {
- CPubKey vch;
- provider.GetPubKey(keyID, vch);
- ret.push_back(ToByteVector(vch));
- }
+ if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false;
+ ret.push_back(std::move(sig));
return true;
+ case TX_PUBKEYHASH: {
+ CKeyID keyID = CKeyID(uint160(vSolutions[0]));
+ if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false;
+ ret.push_back(std::move(sig));
+ CPubKey pubkey;
+ GetPubKey(provider, sigdata, keyID, pubkey);
+ ret.push_back(ToByteVector(pubkey));
+ return true;
+ }
case TX_SCRIPTHASH:
- if (provider.GetCScript(uint160(vSolutions[0]), scriptRet)) {
+ if (GetCScript(provider, sigdata, uint160(vSolutions[0]), scriptRet)) {
ret.push_back(std::vector(scriptRet.begin(), scriptRet.end()));
return true;
}
return false;
- case TX_MULTISIG:
+ case TX_MULTISIG: {
+ size_t required = vSolutions.front()[0];
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
- return (SignN(provider, vSolutions, creator, scriptPubKey, ret, sigversion));
+ for (size_t i = 1; i < vSolutions.size() - 1; ++i) {
+ CPubKey pubkey = CPubKey(vSolutions[i]);
+ if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) {
+ ret.push_back(std::move(sig));
+ }
+ }
+ bool ok = ret.size() == required + 1;
+ for (size_t i = 0; i + ret.size() < required + 1; ++i) {
+ ret.push_back(valtype());
+ }
+ return ok;
+ }
default:
return false;
@@ -122,9 +154,11 @@ static CScript PushAll(const std::vector& values)
bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata)
{
+ if (sigdata.complete) return true;
+
std::vector result;
txnouttype whichType;
- bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE);
+ bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata);
bool P2SH = false;
CScript subscript;
@@ -134,7 +168,8 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
// the final scriptSig is the signatures from that
// and then the serialized subscript:
subscript = CScript(result[0].begin(), result[0].end());
- solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE) && whichType != TX_SCRIPTHASH;
+ sigdata.redeem_script = subscript;
+ solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TX_SCRIPTHASH;
P2SH = true;
}
@@ -144,104 +179,29 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
sigdata.scriptSig = PushAll(result);
// Test solution
- return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
+ sigdata.complete = solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
+ return sigdata.complete;
}
-SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn)
+class SignatureExtractorChecker final : public BaseSignatureChecker
{
- SignatureData data;
- assert(tx.vin.size() > nIn);
- data.scriptSig = tx.vin[nIn].scriptSig;
- return data;
-}
+private:
+ SignatureData& sigdata;
+ BaseSignatureChecker& checker;
-void UpdateInput(CTxIn& input, const SignatureData& data)
-{
- input.scriptSig = data.scriptSig;
-}
-
-void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data)
-{
- assert(tx.vin.size() > nIn);
- UpdateInput(tx.vin[nIn], data);
-}
-
-bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
-{
- assert(nIn < txTo.vin.size());
-
- CTransaction txToConst(txTo);
- TransactionSignatureCreator creator(&txToConst, nIn, amount, nHashType);
-
- SignatureData sigdata;
- bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata);
- UpdateTransaction(txTo, nIn, sigdata);
- return ret;
-}
-
-bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
-{
- assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
- assert(txin.prevout.n < txFrom.vout.size());
- const CTxOut& txout = txFrom.vout[txin.prevout.n];
-
- return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
-}
+public:
+ SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {}
+ bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
+};
-static std::vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const std::vector& vSolutions,
- const std::vector& sigs1, const std::vector& sigs2, SigVersion sigversion)
+bool SignatureExtractorChecker::CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
- // Combine all the signatures we've got:
- std::set allsigs;
- for (const valtype& v : sigs1)
- {
- if (!v.empty())
- allsigs.insert(v);
- }
- for (const valtype& v : sigs2)
- {
- if (!v.empty())
- allsigs.insert(v);
- }
-
- // Build a map of pubkey -> signature by matching sigs to pubkeys:
- assert(vSolutions.size() > 1);
- unsigned int nSigsRequired = vSolutions.front()[0];
- unsigned int nPubKeys = vSolutions.size()-2;
- std::map sigs;
- for (const valtype& sig : allsigs)
- {
- for (unsigned int i = 0; i < nPubKeys; i++)
- {
- const valtype& pubkey = vSolutions[i+1];
- if (sigs.count(pubkey))
- continue; // Already got a sig for this pubkey
-
- if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion))
- {
- sigs[pubkey] = sig;
- break;
- }
- }
- }
- // Now build a merged CScript:
- unsigned int nSigsHave = 0;
- std::vector result; result.push_back(valtype()); // pop-one-too-many workaround
- for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
- {
- if (sigs.count(vSolutions[i+1]))
- {
- result.push_back(sigs[vSolutions[i+1]]);
- ++nSigsHave;
- }
+ if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) {
+ CPubKey pubkey(vchPubKey);
+ sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig));
+ return true;
}
- // Fill any missing with OP_0:
- for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
- result.push_back(valtype());
-
- return result;
+ return false;
}
namespace
@@ -264,59 +224,98 @@ struct Stacks
};
}
-static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const txnouttype txType, const std::vector& vSolutions,
- Stacks sigs1, Stacks sigs2, SigVersion sigversion)
+// Extracts signatures and scripts from incomplete scriptSigs. Please do not extend this, use PSBT instead
+SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout)
{
- switch (txType)
- {
- case TX_NONSTANDARD:
- case TX_NULL_DATA:
- // Don't know anything about this, assume bigger one is correct:
- if (sigs1.script.size() >= sigs2.script.size())
- return sigs1;
- return sigs2;
- case TX_PUBKEY:
- case TX_PUBKEYHASH:
- // Signatures are bigger than placeholders or empty scripts:
- if (sigs1.script.empty() || sigs1.script[0].empty())
- return sigs2;
- return sigs1;
- case TX_SCRIPTHASH:
- if (sigs1.script.empty() || sigs1.script.back().empty())
- return sigs2;
- else if (sigs2.script.empty() || sigs2.script.back().empty())
- return sigs1;
- else
- {
- // Recur to combine:
- valtype spk = sigs1.script.back();
- CScript pubKey2(spk.begin(), spk.end());
-
- txnouttype txType2;
- std::vector > vSolutions2;
- Solver(pubKey2, txType2, vSolutions2);
- sigs1.script.pop_back();
- sigs2.script.pop_back();
- Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion);
- result.script.push_back(spk);
- return result;
+ SignatureData data;
+ assert(tx.vin.size() > nIn);
+ data.scriptSig = tx.vin[nIn].scriptSig;
+ Stacks stack(data);
+
+ // Get signatures
+ MutableTransactionSignatureChecker tx_checker(&tx, nIn, txout.nValue);
+ SignatureExtractorChecker extractor_checker(data, tx_checker);
+ if (VerifyScript(data.scriptSig, txout.scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, extractor_checker)) {
+ data.complete = true;
+ return data;
+ }
+
+ // Get scripts
+ txnouttype script_type;
+ std::vector> solutions;
+ Solver(txout.scriptPubKey, script_type, solutions);
+ SigVersion sigversion = SigVersion::BASE;
+ CScript next_script = txout.scriptPubKey;
+
+ if (script_type == TX_SCRIPTHASH && !stack.script.empty() && !stack.script.back().empty()) {
+ // Get the redeemScript
+ CScript redeem_script(stack.script.back().begin(), stack.script.back().end());
+ data.redeem_script = redeem_script;
+ next_script = std::move(redeem_script);
+
+ // Get redeemScript type
+ Solver(next_script, script_type, solutions);
+ stack.script.pop_back();
+ }
+
+ if (script_type == TX_MULTISIG && !stack.script.empty()) {
+ // Build a map of pubkey -> signature by matching sigs to pubkeys:
+ assert(solutions.size() > 1);
+ unsigned int num_pubkeys = solutions.size()-2;
+ unsigned int last_success_key = 0;
+ for (const valtype& sig : stack.script) {
+ for (unsigned int i = last_success_key; i < num_pubkeys; ++i) {
+ const valtype& pubkey = solutions[i+1];
+ // We either have a signature for this pubkey, or we have found a signature and it is valid
+ if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckSig(sig, pubkey, next_script, sigversion)) {
+ last_success_key = i + 1;
+ break;
+ }
+ }
}
- case TX_MULTISIG:
- return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion));
- default:
- return Stacks();
}
+
+ return data;
+}
+
+void UpdateInput(CTxIn& input, const SignatureData& data)
+{
+ input.scriptSig = data.scriptSig;
+}
+
+void SignatureData::MergeSignatureData(SignatureData sigdata)
+{
+ if (complete) return;
+ if (sigdata.complete) {
+ *this = std::move(sigdata);
+ return;
+ }
+ if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
+ redeem_script = sigdata.redeem_script;
+ }
+ signatures.insert(std::make_move_iterator(sigdata.signatures.begin()), std::make_move_iterator(sigdata.signatures.end()));
+}
+
+bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType)
+{
+ assert(nIn < txTo.vin.size());
+
+ MutableTransactionSignatureCreator creator(&txTo, nIn, amount, nHashType);
+
+ SignatureData sigdata;
+ bool ret = ProduceSignature(provider, creator, fromPubKey, sigdata);
+ UpdateInput(txTo.vin.at(nIn), sigdata);
+ return ret;
}
-SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const SignatureData& scriptSig1, const SignatureData& scriptSig2)
+bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
- txnouttype txType;
- std::vector > vSolutions;
- Solver(scriptPubKey, txType, vSolutions);
+ assert(nIn < txTo.vin.size());
+ CTxIn& txin = txTo.vin[nIn];
+ assert(txin.prevout.n < txFrom.vout.size());
+ const CTxOut& txout = txFrom.vout[txin.prevout.n];
- return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SigVersion::BASE).Output();
+ return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
}
namespace {
@@ -352,3 +351,18 @@ class DummySignatureCreator final : public BaseSignatureCreator {
}
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator();
+const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
+
+bool IsSolvable(const SigningProvider& provider, const CScript& script)
+{
+ // This check is to make sure that the script we created can actually be solved for and signed by us
+ // if we were to have the private keys. This is just to make sure that the script is valid and that,
+ // if found in a transaction, we would still accept and relay that transaction.
+ SignatureData sigs;
+ if (ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, script, sigs)) {
+ // VerifyScript check is just defensive, and should never fail.
+ assert(VerifyScript(sigs.scriptSig, script, STANDARD_SCRIPT_VERIFY_FLAGS, DUMMY_CHECKER));
+ return true;
+ }
+ return false;
+}
diff --git a/src/script/sign.h b/src/script/sign.h
index 53c25e336dca..fa6c560b7fd0 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -21,11 +21,13 @@ class SigningProvider
{
public:
virtual ~SigningProvider() {}
- virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const =0;
- virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const =0;
- virtual bool GetKey(const CKeyID &address, CKey& key) const =0;
+ virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
+ virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
+ virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
};
+extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
+
/** Interface for signature creators. */
class BaseSignatureCreator {
public:
@@ -37,34 +39,36 @@ class BaseSignatureCreator {
};
/** A signature creator for transactions. */
-class TransactionSignatureCreator : public BaseSignatureCreator {
- const CTransaction* txTo;
+class MutableTransactionSignatureCreator : public BaseSignatureCreator {
+ const CMutableTransaction* txTo;
unsigned int nIn;
int nHashType;
CAmount amount;
- const TransactionSignatureChecker checker;
+ const MutableTransactionSignatureChecker checker;
public:
- TransactionSignatureCreator(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
+ MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn = SIGHASH_ALL);
const BaseSignatureChecker& Checker() const override{ return checker; }
bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
};
-class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
- CTransaction tx;
-
-public:
- MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(&tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
-};
-
/** A signature creator that just produces 72-byte empty signatures. */
extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR;
+typedef std::pair> SigPair;
+
+// This struct contains information from a transaction input and also contains signatures for that input.
+// The information contained here can be used to create a signature and is also filled by ProduceSignature
+// in order to construct final scriptSigs and scriptWitnesses.
struct SignatureData {
- CScript scriptSig;
+ bool complete = false; ///< Stores whether the scriptSig is complete
+ CScript scriptSig; ///< The scriptSig of an input. Contains complete signatures or the traditional partial signatures format
+ CScript redeem_script; ///< The redeemScript (if any) for the input
+ std::map signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig.
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
+ void MergeSignatureData(SignatureData sigdata);
};
/** Produce a script signature using a generic signature creator. */
@@ -74,12 +78,14 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
-/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
-SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2);
-
-/** Extract signature data from a transaction, and insert it. */
-SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
-void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);
+/** Extract signature data from a transaction input, and insert it. */
+SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
void UpdateInput(CTxIn& input, const SignatureData& data);
+/* Check whether we know how to sign for an output like this, assuming we
+ * have all private keys. While this function does not need private keys, the passed
+ * provider is used to look up public keys and redeemscripts by hash.
+ * Solvability is unrelated to whether we consider this output to be ours. */
+bool IsSolvable(const SigningProvider& provider, const CScript& script);
+
#endif // BITCOIN_SCRIPT_SIGN_H
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 07c1a10bb6ae..6a3202d37606 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -32,22 +32,54 @@ const char* GetTxnOutputType(txnouttype t)
return nullptr;
}
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet)
+static bool MatchPayToPubkey(const CScript& script, valtype& pubkey)
{
- // Templates
- static std::multimap mTemplates;
- if (mTemplates.empty())
- {
- // Standard tx, sender provides pubkey, receiver adds signature
- mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
+ if (script.size() == CPubKey::PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::PUBLIC_KEY_SIZE && script.back() == OP_CHECKSIG) {
+ pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::PUBLIC_KEY_SIZE + 1);
+ return CPubKey::ValidSize(pubkey);
+ }
+ if (script.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE && script.back() == OP_CHECKSIG) {
+ pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1);
+ return CPubKey::ValidSize(pubkey);
+ }
+ return false;
+}
- // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
- mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
+static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash)
+{
+ if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
+ pubkeyhash = valtype(script.begin () + 3, script.begin() + 23);
+ return true;
+ }
+ return false;
+}
+
+/** Test for "small positive integer" script opcodes - OP_1 through OP_16. */
+static constexpr bool IsSmallInteger(opcodetype opcode)
+{
+ return opcode >= OP_1 && opcode <= OP_16;
+}
- // Sender provides N pubkeys, receivers provides M signatures
- mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+static bool MatchMultisig(const CScript& script, unsigned int& required, std::vector& pubkeys)
+{
+ opcodetype opcode;
+ valtype data;
+ CScript::const_iterator it = script.begin();
+ if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
+
+ if (!script.GetOp(it, opcode, data) || !IsSmallInteger(opcode)) return false;
+ required = CScript::DecodeOP_N(opcode);
+ while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
+ pubkeys.emplace_back(std::move(data));
}
+ if (!IsSmallInteger(opcode)) return false;
+ unsigned int keys = CScript::DecodeOP_N(opcode);
+ if (pubkeys.size() != keys || keys < required) return false;
+ return (it + 1 == script.end());
+}
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet)
+{
vSolutionsRet.clear();
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
@@ -70,84 +102,27 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& tplate : mTemplates)
- {
- const CScript& script2 = tplate.second;
- vSolutionsRet.clear();
+ std::vector data;
+ if (MatchPayToPubkey(scriptPubKey, data)) {
+ typeRet = TX_PUBKEY;
+ vSolutionsRet.push_back(std::move(data));
+ return true;
+ }
- opcodetype opcode1, opcode2;
- std::vector vch1, vch2;
+ if (MatchPayToPubkeyHash(scriptPubKey, data)) {
+ typeRet = TX_PUBKEYHASH;
+ vSolutionsRet.push_back(std::move(data));
+ return true;
+ }
- // Compare
- CScript::const_iterator pc1 = script1.begin();
- CScript::const_iterator pc2 = script2.begin();
- while (true)
- {
- if (pc1 == script1.end() && pc2 == script2.end())
- {
- // Found a match
- typeRet = tplate.first;
- if (typeRet == TX_MULTISIG)
- {
- // Additional checks for TX_MULTISIG:
- unsigned char m = vSolutionsRet.front()[0];
- unsigned char n = vSolutionsRet.back()[0];
- if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
- return false;
- }
- return true;
- }
- if (!script1.GetOp(pc1, opcode1, vch1))
- break;
- if (!script2.GetOp(pc2, opcode2, vch2))
- break;
-
- // Template matching opcodes:
- if (opcode2 == OP_PUBKEYS)
- {
- while (CPubKey::ValidSize(vch1))
- {
- vSolutionsRet.push_back(vch1);
- if (!script1.GetOp(pc1, opcode1, vch1))
- break;
- }
- if (!script2.GetOp(pc2, opcode2, vch2))
- break;
- // Normal situation is to fall through
- // to other if/else statements
- }
-
- if (opcode2 == OP_PUBKEY)
- {
- if (!CPubKey::ValidSize(vch1))
- break;
- vSolutionsRet.push_back(vch1);
- }
- else if (opcode2 == OP_PUBKEYHASH)
- {
- if (vch1.size() != sizeof(uint160))
- break;
- vSolutionsRet.push_back(vch1);
- }
- else if (opcode2 == OP_SMALLINTEGER)
- { // Single-byte small integer pushed onto vSolutions
- if (opcode1 == OP_0 ||
- (opcode1 >= OP_1 && opcode1 <= OP_16))
- {
- char n = (char)CScript::DecodeOP_N(opcode1);
- vSolutionsRet.push_back(valtype(1, n));
- }
- else
- break;
- }
- else if (opcode1 != opcode2 || vch1 != vch2)
- {
- // Others must match exactly
- break;
- }
- }
+ unsigned int required;
+ std::vector> keys;
+ if (MatchMultisig(scriptPubKey, required, keys)) {
+ typeRet = TX_MULTISIG;
+ vSolutionsRet.push_back({static_cast(required)}); // safe as required is in range 1..16
+ vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
+ vSolutionsRet.push_back({static_cast(keys.size())}); // safe as size is in range 1..16
+ return true;
}
vSolutionsRet.clear();
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index 302181fae08a..621e782fdf5e 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -198,13 +198,6 @@ BOOST_AUTO_TEST_CASE( shifts ) { // "<<" ">>" "<<=" ">>="
BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ -
{
- BOOST_CHECK(!ZeroL);
- BOOST_CHECK(!(!OneL));
- for (unsigned int i = 0; i < 256; ++i)
- BOOST_CHECK(!(!(OneL< seed = ParseHex(test.strHexMaster);
CExtKey key;
CExtPubKey pubkey;
- key.SetMaster(seed.data(), seed.size());
+ key.SetSeed(seed.data(), seed.size());
pubkey = key.Neuter();
for (const TestDerivation &derive : test.vDerive) {
unsigned char data[74];
diff --git a/src/test/bip39_tests.cpp b/src/test/bip39_tests.cpp
index e5ffc6242fe4..cefccc67798f 100644
--- a/src/test/bip39_tests.cpp
+++ b/src/test/bip39_tests.cpp
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(bip39_vectors)
CExtKey key;
CExtPubKey pubkey;
- key.SetMaster(seed.data(), 64);
+ key.SetSeed(seed.data(), 64);
pubkey = key.Neuter();
// printf("CBitcoinExtKey: %s\n", EncodeExtKey(key).c_str());
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 7ded9d4fabf7..2b23a62b96e5 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -312,7 +312,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
if (InsecureRandRange(10) == 0 && coinbase_coins.size()) {
auto utxod = FindRandomFrom(coinbase_coins);
// Reuse the exact same coinbase
- tx = std::get<0>(utxod->second);
+ tx = CMutableTransaction{std::get<0>(utxod->second)};
// shouldn't be available for reconnection if it's been duplicated
disconnected_coins.erase(utxod->first);
@@ -331,7 +331,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// 1/20 times reconnect a previously disconnected tx
if (randiter % 20 == 2 && disconnected_coins.size()) {
auto utxod = FindRandomFrom(disconnected_coins);
- tx = std::get<0>(utxod->second);
+ tx = CMutableTransaction{std::get<0>(utxod->second)};
prevout = tx.vin[0].prevout;
if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) {
disconnected_coins.erase(utxod->first);
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index eec164c50083..ce76a35b624e 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -27,11 +27,21 @@ static void ResetArgs(const std::string& strArg)
for (std::string& s : vecArg)
vecChar.push_back(s.c_str());
- gArgs.ParseParameters(vecChar.size(), vecChar.data());
+ std::string error;
+ gArgs.ParseParameters(vecChar.size(), vecChar.data(), error);
+}
+
+static void SetupArgs(const std::vector& args)
+{
+ gArgs.ClearArgs();
+ for (const std::string& arg : args) {
+ gArgs.AddArg(arg, "", false, OptionsCategory::OPTIONS);
+ }
}
BOOST_AUTO_TEST_CASE(boolarg)
{
+ SetupArgs({"-foo"});
ResetArgs("-foo");
BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
@@ -84,6 +94,7 @@ BOOST_AUTO_TEST_CASE(boolarg)
BOOST_AUTO_TEST_CASE(stringarg)
{
+ SetupArgs({"-foo", "-bar"});
ResetArgs("");
BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "");
BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "eleven");
@@ -108,6 +119,7 @@ BOOST_AUTO_TEST_CASE(stringarg)
BOOST_AUTO_TEST_CASE(intarg)
{
+ SetupArgs({"-foo", "-bar"});
ResetArgs("");
BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 11), 11);
BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 0), 0);
@@ -127,6 +139,7 @@ BOOST_AUTO_TEST_CASE(intarg)
BOOST_AUTO_TEST_CASE(doubledash)
{
+ SetupArgs({"-foo", "-bar"});
ResetArgs("--foo");
BOOST_CHECK_EQUAL(gArgs.GetBoolArg("-foo", false), true);
@@ -137,6 +150,7 @@ BOOST_AUTO_TEST_CASE(doubledash)
BOOST_AUTO_TEST_CASE(boolargno)
{
+ SetupArgs({"-foo", "-bar"});
ResetArgs("-nofoo");
BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index e927de17ae8d..95ef91dfa455 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -588,9 +588,6 @@ inline CTransactionRef make_tx(std::vector&& output_values, std::vector
return MakeTransactionRef(tx);
}
-#define MK_OUTPUTS(amounts...) std::vector{amounts}
-#define MK_INPUTS(txs...) std::vector{txs}
-#define MK_INPUT_IDX(idxes...) std::vector{idxes}
BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
{
@@ -604,8 +601,8 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
//
// [tx1]
//
- CTransactionRef tx1 = make_tx(MK_OUTPUTS(10 * COIN));
- pool.addUnchecked(tx1->GetHash(), entry.Fee(10000LL).FromTx(*tx1));
+ CTransactionRef tx1 = make_tx(/* output_values */ {10 * COIN});
+ pool.addUnchecked(tx1->GetHash(), entry.Fee(10000LL).FromTx(tx1));
// Ancestors / descendants should be 1 / 1 (itself / itself)
pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
@@ -616,8 +613,8 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
//
// [tx1].0 <- [tx2]
//
- CTransactionRef tx2 = make_tx(MK_OUTPUTS(495 * CENT, 5 * COIN), MK_INPUTS(tx1));
- pool.addUnchecked(tx2->GetHash(), entry.Fee(10000LL).FromTx(*tx2));
+ CTransactionRef tx2 = make_tx(/* output_values */ {495 * CENT, 5 * COIN}, /* inputs */ {tx1});
+ pool.addUnchecked(tx2->GetHash(), entry.Fee(10000LL).FromTx(tx2));
// Ancestors / descendants should be:
// transaction ancestors descendants
@@ -635,8 +632,8 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
//
// [tx1].0 <- [tx2].0 <- [tx3]
//
- CTransactionRef tx3 = make_tx(MK_OUTPUTS(290 * CENT, 200 * CENT), MK_INPUTS(tx2));
- pool.addUnchecked(tx3->GetHash(), entry.Fee(10000LL).FromTx(*tx3));
+ CTransactionRef tx3 = make_tx(/* output_values */ {290 * CENT, 200 * CENT}, /* inputs */ {tx2});
+ pool.addUnchecked(tx3->GetHash(), entry.Fee(10000LL).FromTx(tx3));
// Ancestors / descendants should be:
// transaction ancestors descendants
@@ -660,8 +657,8 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
// |
// \---1 <- [tx4]
//
- CTransactionRef tx4 = make_tx(MK_OUTPUTS(290 * CENT, 250 * CENT), MK_INPUTS(tx2), MK_INPUT_IDX(1));
- pool.addUnchecked(tx4->GetHash(), entry.Fee(10000LL).FromTx(*tx4));
+ CTransactionRef tx4 = make_tx(/* output_values */ {290 * CENT, 250 * CENT}, /* inputs */ {tx2}, /* input_indices */ {1});
+ pool.addUnchecked(tx4->GetHash(), entry.Fee(10000LL).FromTx(tx4));
// Ancestors / descendants should be:
// transaction ancestors descendants
@@ -696,15 +693,15 @@ BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
CAmount v = 5 * COIN;
for (uint64_t i = 0; i < 5; i++) {
CTransactionRef& tyi = *ty[i];
- tyi = make_tx(MK_OUTPUTS(v), i > 0 ? MK_INPUTS(*ty[i-1]) : std::vector());
+ tyi = make_tx(/* output_values */ {v}, /* inputs */ i > 0 ? std::vector{*ty[i - 1]} : std::vector{});
v -= 50 * CENT;
- pool.addUnchecked(tyi->GetHash(), entry.Fee(10000LL).FromTx(*tyi));
+ pool.addUnchecked(tyi->GetHash(), entry.Fee(10000LL).FromTx(tyi));
pool.GetTransactionAncestry(tyi->GetHash(), ancestors, descendants);
BOOST_CHECK_EQUAL(ancestors, i+1);
BOOST_CHECK_EQUAL(descendants, i+1);
}
- CTransactionRef ty6 = make_tx(MK_OUTPUTS(5 * COIN), MK_INPUTS(tx3, ty5));
- pool.addUnchecked(ty6->GetHash(), entry.Fee(10000LL).FromTx(*ty6));
+ CTransactionRef ty6 = make_tx(/* output_values */ {5 * COIN}, /* inputs */ {tx3, ty5});
+ pool.addUnchecked(ty6->GetHash(), entry.Fee(10000LL).FromTx(ty6));
// Ancestors / descendants should be:
// transaction ancestors descendants
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 554bb8e1ec97..0a503f391f3c 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -320,143 +320,132 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
CScript scriptPubKey;
isminetype result;
- bool isInvalid;
// P2PK compressed
{
CBasicKeyStore keystore;
- scriptPubKey.clear();
- scriptPubKey << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
// Keystore does not have key
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has key
keystore.AddKey(keys[0]);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- BOOST_CHECK(!isInvalid);
}
// P2PK uncompressed
{
CBasicKeyStore keystore;
- scriptPubKey.clear();
- scriptPubKey << ToByteVector(uncompressedPubkey) << OP_CHECKSIG;
+ scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
// Keystore does not have key
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has key
keystore.AddKey(uncompressedKey);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- BOOST_CHECK(!isInvalid);
}
// P2PKH compressed
{
CBasicKeyStore keystore;
- scriptPubKey.clear();
- scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ scriptPubKey = GetScriptForDestination(pubkeys[0].GetID());
// Keystore does not have key
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has key
keystore.AddKey(keys[0]);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- BOOST_CHECK(!isInvalid);
}
// P2PKH uncompressed
{
CBasicKeyStore keystore;
- scriptPubKey.clear();
- scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(uncompressedPubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ scriptPubKey = GetScriptForDestination(uncompressedPubkey.GetID());
// Keystore does not have key
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has key
keystore.AddKey(uncompressedKey);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- BOOST_CHECK(!isInvalid);
}
// P2SH
{
CBasicKeyStore keystore;
- CScript redeemScript;
- redeemScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
-
- scriptPubKey.clear();
- scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ CScript redeemScript = GetScriptForDestination(pubkeys[0].GetID());
+ scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
// Keystore does not have redeemScript or key
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has redeemScript but no key
keystore.AddCScript(redeemScript);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has redeemScript and key
keystore.AddKey(keys[0]);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- BOOST_CHECK(!isInvalid);
+ }
+
+ // (P2PKH inside) P2SH inside P2SH (invalid)
+ {
+ CBasicKeyStore keystore;
+
+ CScript redeemscript_inner = GetScriptForDestination(pubkeys[0].GetID());
+ CScript redeemscript = GetScriptForDestination(CScriptID(redeemscript_inner));
+ scriptPubKey = GetScriptForDestination(CScriptID(redeemscript));
+
+ keystore.AddCScript(redeemscript);
+ keystore.AddCScript(redeemscript_inner);
+ keystore.AddCScript(scriptPubKey);
+ keystore.AddKey(keys[0]);
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// scriptPubKey multisig
{
CBasicKeyStore keystore;
- scriptPubKey.clear();
- scriptPubKey << OP_2 <<
- ToByteVector(uncompressedPubkey) <<
- ToByteVector(pubkeys[1]) <<
- OP_2 << OP_CHECKMULTISIG;
+ scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
// Keystore does not have any keys
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has 1/2 keys
keystore.AddKey(uncompressedKey);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has 2/2 keys
keystore.AddKey(keys[1]);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has 2/2 keys and the script
keystore.AddCScript(scriptPubKey);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
}
// P2SH multisig
@@ -465,25 +454,17 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
keystore.AddKey(uncompressedKey);
keystore.AddKey(keys[1]);
- CScript redeemScript;
- redeemScript << OP_2 <<
- ToByteVector(uncompressedPubkey) <<
- ToByteVector(pubkeys[1]) <<
- OP_2 << OP_CHECKMULTISIG;
-
- scriptPubKey.clear();
- scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
// Keystore has no redeemScript
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
// Keystore has redeemScript
keystore.AddCScript(redeemScript);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- BOOST_CHECK(!isInvalid);
}
// OP_RETURN
@@ -494,9 +475,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
scriptPubKey.clear();
scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
}
// Nonstandard
@@ -507,9 +487,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
scriptPubKey.clear();
scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
- result = IsMine(keystore, scriptPubKey, isInvalid);
+ result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
- BOOST_CHECK(!isInvalid);
}
}
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 508dbf3770b1..8e03aef8508b 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -133,7 +133,7 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
return txCredit;
}
-CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit)
+CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CTransaction& txCredit)
{
CMutableTransaction txSpend;
txSpend.nVersion = 1;
@@ -155,7 +155,7 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, co
bool expect = (scriptError == SCRIPT_ERR_OK);
bool fEnableDIP0020Opcodes = (SCRIPT_ENABLE_DIP0020_OPCODES & flags) != 0;
ScriptError err;
- CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
+ const CTransaction txCredit{BuildCreditingTransaction(scriptPubKey)};
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit);
CMutableTransaction tx2 = tx;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message);
@@ -1018,7 +1018,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CScript scriptPubKey12;
scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12);
+ const CTransaction txFrom12{BuildCreditingTransaction(scriptPubKey12)};
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
@@ -1049,7 +1049,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
CScript scriptPubKey23;
scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
- CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23);
+ const CTransaction txFrom23{BuildCreditingTransaction(scriptPubKey23)};
CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23);
std::vector keys;
@@ -1106,10 +1106,19 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
}
+/* Wrapper around ProduceSignature to combine two scriptsigs */
+SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction& tx, const SignatureData& scriptSig1, const SignatureData& scriptSig2)
+{
+ SignatureData data;
+ data.MergeSignatureData(scriptSig1);
+ data.MergeSignatureData(scriptSig2);
+ ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&tx, 0, txout.nValue), txout.scriptPubKey, data);
+ return data;
+}
+
BOOST_AUTO_TEST_CASE(script_combineSigs)
{
- // Test the CombineSignatures function
- CAmount amount;
+ // Test the ProduceSignature's ability to combine signatures function
CBasicKeyStore keystore;
std::vector keys;
std::vector pubkeys;
@@ -1125,52 +1134,51 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));
CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom);
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
- CScript& scriptSig = txTo.vin[0].scriptSig;
+ SignatureData scriptSig;
SignatureData empty;
- SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty);
+ SignatureData combined = CombineSignatures(txFrom.vout[0], txTo, empty, empty);
BOOST_CHECK(combined.scriptSig.empty());
// Single signature case:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // changes scriptSig
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
- BOOST_CHECK(combined.scriptSig == scriptSig);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSig);
- CScript scriptSigCopy = scriptSig;
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
+ combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
+ SignatureData scriptSigCopy = scriptSig;
// Signing again will give a different, valid signature:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);
// P2SH, single-signature case:
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
keystore.AddCScript(pkSingle);
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
- BOOST_CHECK(combined.scriptSig == scriptSig);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSig);
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
+ combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
scriptSigCopy = scriptSig;
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
- // dummy scriptSigCopy with placeholder, should always choose non-placeholder:
- scriptSigCopy = CScript() << OP_0 << std::vector(pkSingle.begin(), pkSingle.end());
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSig);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy));
- BOOST_CHECK(combined.scriptSig == scriptSig);
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);
// Hardest case: Multisig 2-of-3
scriptPubKey = GetScriptForMultisig(2, pubkeys);
keystore.AddCScript(scriptPubKey);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
- BOOST_CHECK(combined.scriptSig == scriptSig);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
- BOOST_CHECK(combined.scriptSig == scriptSig);
+ scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
+ combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
+ combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);
+ BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);
// A couple of partially-signed versions:
std::vector sig1;
@@ -1197,22 +1205,28 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CScript complete12 = CScript() << OP_0 << sig1 << sig2;
CScript complete13 = CScript() << OP_0 << sig1 << sig3;
CScript complete23 = CScript() << OP_0 << sig2 << sig3;
-
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b));
+ SignatureData partial1_sigs;
+ partial1_sigs.signatures.emplace(keys[0].GetPubKey().GetID(), SigPair(keys[0].GetPubKey(), sig1));
+ SignatureData partial2_sigs;
+ partial2_sigs.signatures.emplace(keys[1].GetPubKey().GetID(), SigPair(keys[1].GetPubKey(), sig2));
+ SignatureData partial3_sigs;
+ partial3_sigs.signatures.emplace(keys[2].GetPubKey().GetID(), SigPair(keys[2].GetPubKey(), sig3));
+
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial1_sigs);
BOOST_CHECK(combined.scriptSig == partial1a);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial2_sigs);
BOOST_CHECK(combined.scriptSig == complete12);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial2_sigs, partial1_sigs);
BOOST_CHECK(combined.scriptSig == complete12);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial2_sigs);
BOOST_CHECK(combined.scriptSig == complete12);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial1_sigs);
BOOST_CHECK(combined.scriptSig == complete13);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial2_sigs, partial3_sigs);
BOOST_CHECK(combined.scriptSig == complete23);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial2_sigs);
BOOST_CHECK(combined.scriptSig == complete23);
- combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a));
+ combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial3_sigs);
BOOST_CHECK(combined.scriptSig == partial3c);
}
diff --git a/src/test/test_dash.cpp b/src/test/test_dash.cpp
index 9c170ce7d2f0..786dc00ca894 100644
--- a/src/test/test_dash.cpp
+++ b/src/test/test_dash.cpp
@@ -232,7 +232,7 @@ CBlock TestChainSetup::CreateBlock(const std::vector& txns,
if (!CalcCbTxMerkleRootQuorums(block, chainActive.Tip(), cbTx.merkleRootQuorums, state)) {
BOOST_ASSERT(false);
}
- CMutableTransaction tmpTx = *block.vtx[0];
+ CMutableTransaction tmpTx{*block.vtx[0]};
SetTxPayload(tmpTx, cbTx);
block.vtx[0] = MakeTransactionRef(tmpTx);
}
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 6b1f115787ca..f6a435cee176 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -24,7 +24,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
static bool
-ToMemPool(CMutableTransaction& tx)
+ToMemPool(const CMutableTransaction& tx)
{
LOCK(cs_main);
@@ -114,7 +114,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
// should fail.
// Capture this interaction with the upgraded_nop argument: set it when evaluating
// any script flag that is implemented as an upgraded NOP code.
-static void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_flags, bool add_to_cache)
+static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache)
{
PrecomputedTransactionData txdata(tx);
// If we add many more flags, this loop can get too expensive, but we can
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 65eb7f82b355..2b564d851209 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -132,27 +132,37 @@ struct TestArgsManager : public ArgsManager
LOCK(cs_args);
m_config_args.clear();
}
- ReadConfigStream(streamConfig);
+ std::string error;
+ ReadConfigStream(streamConfig, error);
}
void SetNetworkOnlyArg(const std::string arg)
{
LOCK(cs_args);
m_network_only_args.insert(arg);
}
+ void SetupArgs(int argv, const char* args[])
+ {
+ for (int i = 0; i < argv; ++i) {
+ AddArg(args[i], "", false, OptionsCategory::OPTIONS);
+ }
+ }
};
BOOST_AUTO_TEST_CASE(util_ParseParameters)
{
TestArgsManager testArgs;
+ const char* avail_args[] = {"-a", "-b", "-ccc", "-d"};
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
- testArgs.ParseParameters(0, (char**)argv_test);
+ std::string error;
+ testArgs.SetupArgs(4, avail_args);
+ testArgs.ParseParameters(0, (char**)argv_test, error);
BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty());
- testArgs.ParseParameters(1, (char**)argv_test);
+ testArgs.ParseParameters(1, (char**)argv_test, error);
BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty());
- testArgs.ParseParameters(7, (char**)argv_test);
+ testArgs.ParseParameters(7, (char**)argv_test, error);
// expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
@@ -173,9 +183,12 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters)
BOOST_AUTO_TEST_CASE(util_GetBoolArg)
{
TestArgsManager testArgs;
+ const char* avail_args[] = {"-a", "-b", "-c", "-d", "-e", "-f"};
const char *argv_test[] = {
"ignored", "-a", "-nob", "-c=0", "-d=1", "-e=false", "-f=true"};
- testArgs.ParseParameters(7, (char**)argv_test);
+ std::string error;
+ testArgs.SetupArgs(6, avail_args);
+ testArgs.ParseParameters(7, (char**)argv_test, error);
// Each letter should be set.
for (char opt : "abcdef")
@@ -207,8 +220,11 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
TestArgsManager testArgs;
// Params test
+ const char* avail_args[] = {"-foo", "-bar"};
const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"};
- testArgs.ParseParameters(4, (char**)argv_test);
+ testArgs.SetupArgs(2, avail_args);
+ std::string error;
+ testArgs.ParseParameters(4, (char**)argv_test, error);
// This was passed twice, second one overrides the negative setting.
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
@@ -220,7 +236,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
// Config test
const char *conf_test = "nofoo=1\nfoo=1\nnobar=0\n";
- testArgs.ParseParameters(1, (char**)argv_test);
+ testArgs.ParseParameters(1, (char**)argv_test, error);
testArgs.ReadConfigString(conf_test);
// This was passed twice, second one overrides the negative setting,
@@ -235,7 +251,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
// Combined test
const char *combo_test_args[] = {"ignored", "-nofoo", "-bar"};
const char *combo_test_conf = "foo=1\nnobar=1\n";
- testArgs.ParseParameters(3, (char**)combo_test_args);
+ testArgs.ParseParameters(3, (char**)combo_test_args, error);
testArgs.ReadConfigString(combo_test_conf);
// Command line overrides, but doesn't erase old setting
@@ -275,6 +291,8 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
"iii=2\n";
TestArgsManager test_args;
+ const char* avail_args[] = {"-a", "-b", "-ccc", "-d", "-e", "-fff", "-ggg", "-h", "-i", "-iii"};
+ test_args.SetupArgs(10, avail_args);
test_args.ReadConfigString(str_config);
// expectation: a, b, ccc, d, fff, ggg, h, i end up in map
@@ -472,6 +490,8 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_AUTO_TEST_CASE(util_GetChainName)
{
TestArgsManager test_args;
+ const char* avail_args[] = {"-testnet", "-regtest"};
+ test_args.SetupArgs(2, avail_args);
const char* argv_testnet[] = {"cmd", "-testnet"};
const char* argv_regtest[] = {"cmd", "-regtest"};
@@ -481,39 +501,40 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
// equivalent to "-testnet"
// regtest in testnet section is ignored
const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1";
+ std::string error;
- test_args.ParseParameters(0, (char**)argv_testnet);
+ test_args.ParseParameters(0, (char**)argv_testnet, error);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
- test_args.ParseParameters(2, (char**)argv_testnet);
+ test_args.ParseParameters(2, (char**)argv_testnet, error);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_regtest);
+ test_args.ParseParameters(2, (char**)argv_regtest, error);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest");
- test_args.ParseParameters(3, (char**)argv_test_no_reg);
+ test_args.ParseParameters(3, (char**)argv_test_no_reg, error);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(3, (char**)argv_both);
+ test_args.ParseParameters(3, (char**)argv_both, error);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
- test_args.ParseParameters(0, (char**)argv_testnet);
+ test_args.ParseParameters(0, (char**)argv_testnet, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_testnet);
+ test_args.ParseParameters(2, (char**)argv_testnet, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_regtest);
+ test_args.ParseParameters(2, (char**)argv_regtest, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
- test_args.ParseParameters(3, (char**)argv_test_no_reg);
+ test_args.ParseParameters(3, (char**)argv_test_no_reg, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(3, (char**)argv_both);
+ test_args.ParseParameters(3, (char**)argv_both, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
@@ -521,23 +542,23 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
// [test] regtest=1 potentially relevant) doesn't break things
test_args.SelectConfigNetwork("test");
- test_args.ParseParameters(0, (char**)argv_testnet);
+ test_args.ParseParameters(0, (char**)argv_testnet, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_testnet);
+ test_args.ParseParameters(2, (char**)argv_testnet, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(2, (char**)argv_regtest);
+ test_args.ParseParameters(2, (char**)argv_regtest, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
- test_args.ParseParameters(2, (char**)argv_test_no_reg);
+ test_args.ParseParameters(2, (char**)argv_test_no_reg, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
- test_args.ParseParameters(3, (char**)argv_both);
+ test_args.ParseParameters(3, (char**)argv_both, error);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
}
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index c683a5135ab3..4b5ef21abb98 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -1108,18 +1108,18 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
// Check children against mapNextTx
CTxMemPool::setEntries setChildrenCheck;
auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
- int64_t childSizes = 0;
+ uint64_t child_sizes = 0;
for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) {
txiter childit = mapTx.find(iter->second->GetHash());
assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
if (setChildrenCheck.insert(childit).second) {
- childSizes += childit->GetTxSize();
+ child_sizes += childit->GetTxSize();
}
}
assert(setChildrenCheck == GetMemPoolChildren(it));
// Also check to make sure size is greater than sum with immediate children.
// just a sanity check, not definitive that this calc is correct...
- assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
+ assert(it->GetSizeWithDescendants() >= child_sizes + it->GetTxSize());
if (fDependsWait)
waitingOnDependants.push_back(&(*it));
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 75c90f9e97a4..850b26717ae1 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -420,7 +420,7 @@ void ArgsManager::SelectConfigNetwork(const std::string& network)
m_network = network;
}
-void ArgsManager::ParseParameters(int argc, const char* const argv[])
+bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error)
{
LOCK(cs_args);
m_override_args.clear();
@@ -452,6 +452,14 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
} else {
m_override_args[key].push_back(val);
}
+
+ // Check that the arg is known
+ if (!(IsSwitchChar(key[0]) && key.size() == 1)) {
+ if (!IsArgKnown(key, error)) {
+ error = strprintf("Invalid parameter %s", key.c_str());
+ return false;
+ }
+ }
}
// we do not allow -includeconf from command line, so we clear it here
@@ -459,11 +467,28 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
if (it != m_override_args.end()) {
if (it->second.size() > 0) {
for (const auto& ic : it->second) {
- fprintf(stderr, "warning: -includeconf cannot be used from commandline; ignoring -includeconf=%s\n", ic.c_str());
+ error += "-includeconf cannot be used from commandline; -includeconf=" + ic + "\n";
}
- m_override_args.erase(it);
+ return false;
}
}
+ return true;
+}
+
+bool ArgsManager::IsArgKnown(const std::string& key, std::string& error)
+{
+ size_t option_index = key.find('.');
+ std::string arg_no_net;
+ if (option_index == std::string::npos) {
+ arg_no_net = key;
+ } else {
+ arg_no_net = std::string("-") + key.substr(option_index + 1, std::string::npos);
+ }
+
+ for (const auto& arg_map : m_available_args) {
+ if (arg_map.second.count(arg_no_net)) return true;
+ }
+ return false;
}
std::vector ArgsManager::GetArgs(const std::string& strArg) const
@@ -557,62 +582,108 @@ void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strV
void ArgsManager::AddArg(const std::string& name, const std::string& help, const bool debug_only, const OptionsCategory& cat)
{
- std::pair key(cat, name);
- assert(m_available_args.count(key) == 0);
- m_available_args.emplace(key, std::pair(help, debug_only));
+ // Split arg name from its help param
+ size_t eq_index = name.find('=');
+ if (eq_index == std::string::npos) {
+ eq_index = name.size();
+ }
+
+ std::map& arg_map = m_available_args[cat];
+ auto ret = arg_map.emplace(name.substr(0, eq_index), Arg(name.substr(eq_index, name.size() - eq_index), help, debug_only));
+ assert(ret.second); // Make sure an insertion actually happened
+}
+
+void ArgsManager::AddHiddenArgs(const std::vector& names)
+{
+ for (const std::string& name : names) {
+ AddArg(name, "", false, OptionsCategory::HIDDEN);
+ }
}
std::string ArgsManager::GetHelpMessage()
{
const bool show_debug = gArgs.GetBoolArg("-help-debug", false);
- std::string usage = HelpMessageGroup("Options:");
-
- OptionsCategory last_cat = OptionsCategory::OPTIONS;
- for (auto& arg : m_available_args) {
- if (arg.first.first != last_cat) {
- last_cat = arg.first.first;
- if (last_cat == OptionsCategory::CONNECTION)
+ std::string usage = "";
+ for (const auto& arg_map : m_available_args) {
+ switch(arg_map.first) {
+ case OptionsCategory::OPTIONS:
+ usage += HelpMessageGroup("Options:");
+ break;
+ case OptionsCategory::CONNECTION:
usage += HelpMessageGroup("Connection options:");
- else if (last_cat == OptionsCategory::INDEXING)
+ break;
+ case OptionsCategory::INDEXING:
usage += HelpMessageGroup("Indexing options:");
- else if (last_cat == OptionsCategory::MASTERNODE)
+ break;
+ case OptionsCategory::MASTERNODE:
usage += HelpMessageGroup("Masternode options:");
- else if (last_cat == OptionsCategory::STATSD)
+ break;
+ case OptionsCategory::STATSD:
usage += HelpMessageGroup("Statsd options:");
- else if (last_cat == OptionsCategory::ZMQ)
+ break;
+ case OptionsCategory::ZMQ:
usage += HelpMessageGroup("ZeroMQ notification options:");
- else if (last_cat == OptionsCategory::DEBUG_TEST)
+ break;
+ case OptionsCategory::DEBUG_TEST:
usage += HelpMessageGroup("Debugging/Testing options:");
- else if (last_cat == OptionsCategory::NODE_RELAY)
+ break;
+ case OptionsCategory::NODE_RELAY:
usage += HelpMessageGroup("Node relay options:");
- else if (last_cat == OptionsCategory::BLOCK_CREATION)
+ break;
+ case OptionsCategory::BLOCK_CREATION:
usage += HelpMessageGroup("Block creation options:");
- else if (last_cat == OptionsCategory::RPC)
+ break;
+ case OptionsCategory::RPC:
usage += HelpMessageGroup("RPC server options:");
- else if (last_cat == OptionsCategory::WALLET)
+ break;
+ case OptionsCategory::WALLET:
usage += HelpMessageGroup("Wallet options:");
- else if (last_cat == OptionsCategory::WALLET)
+ break;
+ case OptionsCategory::WALLET_FEE:
usage += HelpMessageGroup("Wallet fee options:");
- else if (last_cat == OptionsCategory::WALLET)
+ break;
+ case OptionsCategory::WALLET_HD:
usage += HelpMessageGroup("HD wallet options:");
- else if (last_cat == OptionsCategory::WALLET)
+ break;
+ case OptionsCategory::WALLET_KEEPASS:
usage += HelpMessageGroup("KeePass options:");
- else if (last_cat == OptionsCategory::WALLET)
+ break;
+ case OptionsCategory::WALLET_COINJOIN:
usage += HelpMessageGroup("CoinJoin options:");
- else if (last_cat == OptionsCategory::WALLET_DEBUG_TEST && show_debug)
- usage += HelpMessageGroup("Wallet debugging/testing options:");
- else if (last_cat == OptionsCategory::CHAINPARAMS)
+ break;
+ case OptionsCategory::WALLET_DEBUG_TEST:
+ if (show_debug) usage += HelpMessageGroup("Wallet debugging/testing options:");
+ break;
+ case OptionsCategory::CHAINPARAMS:
usage += HelpMessageGroup("Chain selection options:");
- else if (last_cat == OptionsCategory::GUI)
+ break;
+ case OptionsCategory::GUI:
usage += HelpMessageGroup("UI Options:");
- else if (last_cat == OptionsCategory::COMMANDS)
+ break;
+ case OptionsCategory::COMMANDS:
usage += HelpMessageGroup("Commands:");
- else if (last_cat == OptionsCategory::REGISTER_COMMANDS)
+ break;
+ case OptionsCategory::REGISTER_COMMANDS:
usage += HelpMessageGroup("Register Commands:");
+ break;
+ default:
+ break;
}
- if (show_debug || !arg.second.second) {
- usage += HelpMessageOpt(arg.first.second, arg.second.first);
+
+ // When we get to the hidden options, stop
+ if (arg_map.first == OptionsCategory::HIDDEN) break;
+
+ for (const auto& arg : arg_map.second) {
+ if (show_debug || !arg.second.m_debug_only) {
+ std::string name;
+ if (arg.second.m_help_param.empty()) {
+ name = arg.first;
+ } else {
+ name = arg.first + arg.second.m_help_param;
+ }
+ usage += HelpMessageOpt(name, arg.second.m_help_text);
+ }
}
}
return usage;
@@ -782,7 +853,7 @@ fs::path GetConfigFile(const std::string& confPath)
return AbsPathForConfigVal(fs::path(confPath), false);
}
-void ArgsManager::ReadConfigStream(std::istream& stream)
+bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys)
{
LOCK(cs_args);
@@ -793,15 +864,23 @@ void ArgsManager::ReadConfigStream(std::istream& stream)
{
std::string strKey = std::string("-") + it->string_key;
std::string strValue = it->value[0];
+
if (InterpretNegatedOption(strKey, strValue)) {
m_config_args[strKey].clear();
} else {
m_config_args[strKey].push_back(strValue);
}
+
+ // Check that the arg is known
+ if (!IsArgKnown(strKey, error) && !ignore_invalid_keys) {
+ error = strprintf("Invalid configuration value %s", it->string_key.c_str());
+ return false;
+ }
}
+ return true;
}
-void ArgsManager::ReadConfigFiles()
+bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
{
{
LOCK(cs_args);
@@ -812,41 +891,73 @@ void ArgsManager::ReadConfigFiles()
fsbridge::ifstream stream(GetConfigFile(confPath));
if (stream.good()) {
- ReadConfigStream(stream);
+ if (!ReadConfigStream(stream, error, ignore_invalid_keys)) {
+ return false;
+ }
// if there is an -includeconf in the override args, but it is empty, that means the user
// passed '-noincludeconf' on the command line, in which case we should not include anything
if (m_override_args.count("-includeconf") == 0) {
+ std::string chain_id = GetChainName();
std::vector includeconf(GetArgs("-includeconf"));
{
// We haven't set m_network yet (that happens in SelectParams()), so manually check
// for network.includeconf args.
- std::vector includeconf_net(GetArgs(std::string("-") + GetChainName() + ".includeconf"));
+ std::vector includeconf_net(GetArgs(std::string("-") + chain_id + ".includeconf"));
includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());
}
+ // Remove -includeconf from configuration, so we can warn about recursion
+ // later
+ {
+ LOCK(cs_args);
+ m_config_args.erase("-includeconf");
+ m_config_args.erase(std::string("-") + chain_id + ".includeconf");
+ }
+
for (const std::string& to_include : includeconf) {
fsbridge::ifstream include_config(GetConfigFile(to_include));
if (include_config.good()) {
- ReadConfigStream(include_config);
+ if (!ReadConfigStream(include_config, error, ignore_invalid_keys)) {
+ return false;
+ }
LogPrintf("Included configuration file %s\n", to_include.c_str());
} else {
- fprintf(stderr, "Failed to include configuration file %s\n", to_include.c_str());
+ error = "Failed to include configuration file " + to_include;
+ return false;
+ }
+ }
+
+ // Warn about recursive -includeconf
+ includeconf = GetArgs("-includeconf");
+ {
+ std::vector includeconf_net(GetArgs(std::string("-") + chain_id + ".includeconf"));
+ includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());
+ std::string chain_id_final = GetChainName();
+ if (chain_id_final != chain_id) {
+ // Also warn about recursive includeconf for the chain that was specified in one of the includeconfs
+ includeconf_net = GetArgs(std::string("-") + chain_id_final + ".includeconf");
+ includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());
}
}
+ for (const std::string& to_include : includeconf) {
+ fprintf(stderr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", to_include.c_str());
+ }
}
} else {
// Create an empty dash.conf if it does not exist
FILE* configFile = fopen(GetConfigFile(confPath).string().c_str(), "a");
if (configFile != nullptr)
fclose(configFile);
- return; // Nothing to read, so just return
+ return true; // Nothing to read, so just return
}
// If datadir is changed in .conf file:
ClearDatadirCache();
if (!fs::is_directory(GetDataDir(false))) {
- throw std::runtime_error(strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str()));
+ error = strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str());
+ return false;
}
+ return true;
}
std::string ArgsManager::GetChainName() const
diff --git a/src/util/system.h b/src/util/system.h
index c864c350dad8..f26b70bed16c 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -141,8 +141,7 @@ inline bool IsSwitchChar(char c)
#endif
}
-enum class OptionsCategory
-{
+enum class OptionsCategory {
OPTIONS,
CONNECTION,
INDEXING,
@@ -162,7 +161,9 @@ enum class OptionsCategory
RPC,
GUI,
COMMANDS,
- REGISTER_COMMANDS
+ REGISTER_COMMANDS,
+
+ HIDDEN // Always the last option to avoid printing these in the help
};
class ArgsManager
@@ -170,14 +171,23 @@ class ArgsManager
protected:
friend class ArgsManagerHelper;
+ struct Arg
+ {
+ std::string m_help_param;
+ std::string m_help_text;
+ bool m_debug_only;
+
+ Arg(const std::string& help_param, const std::string& help_text, bool debug_only) : m_help_param(help_param), m_help_text(help_text), m_debug_only(debug_only) {};
+ };
+
mutable CCriticalSection cs_args;
std::map> m_override_args;
std::map> m_config_args;
std::string m_network;
std::set m_network_only_args;
- std::map