From 1780961a6152ccb109f9c51bf54dd7209df9b8f6 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 04:20:20 +0000 Subject: [PATCH 01/19] revert: bitcoin#25464 (Reduce Univalue push_backV peak memory usage in listtransactions) reverts: - 001d7bad0e2497a9a35e41e596965ceec35f66e1. --- src/univalue/include/univalue.h | 10 ---------- src/wallet/rpc/transactions.cpp | 12 ++++++------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 0742f9fcb157..fc5cf402be3c 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -111,8 +111,6 @@ class UniValue { return push_back(tmpVal); } bool push_backV(const std::vector& vec); - template - bool push_backV(It first, It last); void __pushKV(const std::string& key, const UniValue& val); bool pushKV(const std::string& key, const UniValue& val); @@ -182,14 +180,6 @@ class UniValue { friend const UniValue& find_value( const UniValue& obj, const std::string& name); }; -template -bool UniValue::push_backV(It first, It last) -{ - if (typ != VARR) return false; - values.insert(values.end(), first, last); - return true; -} - enum jtokentype { JTOK_ERR = -1, JTOK_NONE = 0, // eof diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index 254498425d55..f68e487e4c2b 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -329,12 +329,11 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) * @param wtx The wallet transaction. * @param nMinDepth The minimum confirmation depth. * @param fLong Whether to include the JSON version of the transaction. - * @param ret The vector into which the result is stored. + * @param ret The UniValue into which the result is stored. * @param filter_ismine The "is mine" filter flags. * @param filter_label Optional label string to filter incoming transactions. */ -template -static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong, Vec& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) +static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { CAmount nFee; std::list listReceived; @@ -521,7 +520,8 @@ RPCHelpMan listtransactions() if (nFrom < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); - std::vector ret; + UniValue ret(UniValue::VARR); + { LOCK(pwallet->cs_wallet); @@ -543,9 +543,9 @@ RPCHelpMan listtransactions() if ((nFrom + nCount) > (int)ret.size()) nCount = ret.size() - nFrom; - auto txs_rev_it{std::make_move_iterator(ret.rend())}; + const std::vector& txs = ret.getValues(); UniValue result{UniValue::VARR}; - result.push_backV(txs_rev_it - nFrom - nCount, txs_rev_it - nFrom); // Return oldest to newest + result.push_backV({ txs.rend() - nFrom - nCount, txs.rend() - nFrom }); // Return oldest to newest return result; }, }; From b1ae6f5f59b7a45d72b4fa14087a07818da8a0f3 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 04:26:26 +0000 Subject: [PATCH 02/19] Squashed 'src/univalue/' changes from 2740c4f712..a44caf65fe a44caf65fe Merge bitcoin-core/univalue-subtree#28: Import fixes for sanitizer reported issues 135254331e Import fixes for sanitizer reported issues d5fb86940e refactor: use c++11 range based for loop in checkObject ff9c379304 refactor: Use nullptr (c++11) instead of NULL 08a99754d5 build: use ax_cxx_compile_stdcxx.m4 to check for C++11 support 66d3713ce7 Merge bitcoin-core/univalue#29: ci: travis -> cirrus 808d487292 ci: travis -> cirrus c390ac375f Merge bitcoin-core/univalue#19: Split sources for easier buildsystem integration 4a5b0a1c65 build: Move source entries out to sources.mk 6c7d94b33c build: cleanup wonky gen usage a222637c6d Merge #23: Merge changes from jgarzik/univalue@1ae6a23 98fadc0909 Merge #24: Push bool into array correctly 5f03f1f39a Push bool into array correctly f77d0f718d Merge commit '1ae6a231a0169938eb3972c1d48dd17cba5947e1' into HEAD 98261b1e7b Merge #22: Clamp JSON object depth to PHP limit 54c4015415 Clamp JSON object depth to PHP limit 5a58a46671 Merge #21: Remove hand-coded UniValue destructor. b4cdfc4f47 Remove hand-coded UniValue destructor. 1ae6a231a0 Merge pull request #57 from MarcoFalke/test_fix 92bdd11f0b univalue_write: remove unneeded sstream.h include ffb621c130 Merge pull request #56 from drodil/remove_sstream_header f33acf9fe8 Merge commit '7890db9~' into HEAD 7fba60b5ad Merge #17: [docs] Update readme 4577454e7e Merge #13: Fix typo 66e0adec4d Remove unnecessary sstream header from univalue.h ac7e73cda8 [docs] Update readme 7890db99d6 Merge #11: Remove deprecated std pair wrappers 88967f6586 Version 1.0.4 40e34852ac Merge #14: Cleaned up namespace imports to reduce symbol collisions 1dc113dbef Merge pull request #50 from luke-jr/pushKV_bool 72392fb227 [tests] test pushKV for boolean values c23132bcf4 Pushing boolean value to univalue correctly 4a4964729b Fix typo 85052a4819 Remove deprecated std::pair wrappers 81faab26a1 Merge pull request #48 from fwolfst/47-UPDATE_MIT_LINK_TO_HTTPS b17634ef24 Update URLs to MIT license. 51d3ab34ba Merge #10: Add pushKV(key, boolean) function (replaces #5) 129bad96d5 [tests] test pushKV for boolean values b3c44c947f Pushing boolean value to univalue correctly 07947ff2da Merge #9: [tests] Fix BOOST_CHECK_THROW macro ec849d9a28 [tests] Fix BOOST_CHECK_THROW macro 88ab64f6b5 Merge pull request #46 from jasonbcox/master 35ed96da31 Merge pull request #44 from MarcoFalke/Mf1709-univalue-cherrypick-explicit 420c226290 Merge pull request #45 from MarcoFalke/Mf1710-univalue-revert-test d208f986dd Cleaned up namespace imports to reduce symbol collisions 31bc9f5a49 Merge #8: Remove unused Homebrew workaround fa042093d1 Remove HomeBrew workaround a523e08ae4 Merge #7: Declare single-argument (non-converting) constructors "explicit" a9e53b38ba Merge #4: Pull upstream fe805ea74f Declare single-argument (non-converting) constructors "explicit" 8a2d6f1e36 Merge pull request #41 from jgarzik/get-obj-map ba341a20d7 Add getObjMap() helper method. Also, constify checkObject(). ceb1194137 Handle .pushKV() and .checkObject() edge cases. 107db98299 Add ::push_back(double) method for feature parity. d415300316 Move one-line implementation of UniValue::read() to header. 52e85b35b8 Move exception-throwing get_* methods into separate implementation module. dac5296759 README.md: update code quotes 3e31dcffbe README.md: close code quote d09b8429da Update README.md f1b86edb4c Convert README to markdown style. 1dfe464eff Import UniValue class unit tests from bitcoin project. 0d3e74dd1e operator[] takes size_t index parameter (versus unsigned int) 640158fa26 Private findKey() method becomes size_t clean, and returns bool on failure. 7099135857 Merge pull request #36 from ryanofsky/pr/end-str a31231b519 Version 1.0.3 4fd5444d18 Reject unterminated strings 81eba332b7 Merge pull request #26 from isle2983/pushBackHelpers 36405413e8 Merge PR #32 from branch 'nul-not-special' of git://github.com/ryanofsky/univalue into merge 89bb07322a Merge pull request #31 from ryanofsky/raw-literals 511008c36d Merge pull request #30 from ryanofsky/test-driver 77974f3a9f Merge pull request #34 from paveljanik/20161116_Wshadow_codepoint a38fcd3556 Do not shadow member variable codepoint. fd32d1ab85 Don't require nul-terminated string inputs 0bb1439d0d Support parsing raw literals in UniValue 28876d0455 Merge pull request #29 from btcdrak/exportspace 839ccd71f3 Add test driver for JSONTestSuite 26ef3fff15 Remove trailing whitespace from JSON export 16a1f7f6e9 Merge #3: Pull upstream 3f03bfd62b Merge pull request #27 from laanwj/2016_09_const_refs 5668ca397b Return const references from getKeys, getValues, get_str cedda1473d Merge pull request #28 from MarcoFalke/patch-1 9f0b997592 [travis] Work around osx libtool issue daf1285af6 Merge pull request #2 from jgarzik/master cfa0384d64 Convenience wrappers for push_back-ing integer types d9e62d3e19 Merge pull request #24 from MarcoFalke/Mf1608-cleanup faf260f2f8 Rem unused vars and prefer prefix operator for non-primitive type 09a2693ff1 Merge pull request #22 from laanwj/2016_04_unicode c74a04c259 Merge pull request #23 from paveljanik/20160527_Wshadow f32df99e96 Merge branch '2016_04_unicode' into bitcoin 280b191cb1 Merge remote-tracking branch 'jgarzik/master' into bitcoin fceb4f8e84 Do not shadow variables c9a716c2b9 Handle UTF-8 bed8dd9258 Version 1.0.2. 5e7985a3f8 Merge pull request #14 from laanwj/2015_11_escape_plan git-subtree-dir: src/univalue git-subtree-split: a44caf65fe55b9dd8ddb08f04c0f70409efd53b3 --- .cirrus.yml | 44 ++ .travis.yml | 52 -- Makefile.am | 88 +-- README | 7 - README.md | 21 + build-aux/m4/ax_cxx_compile_stdcxx.m4 | 962 ++++++++++++++++++++++++++ configure.ac | 9 +- gen/gen.cpp | 6 +- include/univalue.h | 147 ++-- lib/univalue.cpp | 242 ++----- lib/univalue_escapes.h | 442 ++++++------ lib/univalue_get.cpp | 148 ++++ lib/univalue_read.cpp | 132 ++-- lib/univalue_utffilter.h | 119 ++++ lib/univalue_write.cpp | 38 +- sources.mk | 95 +++ test/.gitignore | 4 + test/fail1.json | 2 +- test/fail38.json | 1 + test/fail39.json | 1 + test/fail40.json | 1 + test/fail41.json | 1 + test/fail42.json | Bin 0 -> 37 bytes test/fail44.json | 1 + test/fail45.json | 1 + test/no_nul.cpp | 8 + test/object.cpp | 420 +++++++++++ test/pass4.json | 1 + test/round2.json | 1 + test/round3.json | 1 + test/round4.json | 1 + test/round5.json | 1 + test/round6.json | 1 + test/round7.json | 1 + test/test_json.cpp | 24 + test/unitester.cpp | 59 +- 36 files changed, 2365 insertions(+), 717 deletions(-) create mode 100644 .cirrus.yml delete mode 100644 .travis.yml delete mode 100644 README create mode 100644 README.md create mode 100644 build-aux/m4/ax_cxx_compile_stdcxx.m4 create mode 100644 lib/univalue_get.cpp create mode 100644 lib/univalue_utffilter.h create mode 100644 sources.mk create mode 100644 test/fail38.json create mode 100644 test/fail39.json create mode 100644 test/fail40.json create mode 100644 test/fail41.json create mode 100644 test/fail42.json create mode 100644 test/fail44.json create mode 100644 test/fail45.json create mode 100644 test/no_nul.cpp create mode 100644 test/object.cpp create mode 100644 test/pass4.json create mode 100644 test/round2.json create mode 100644 test/round3.json create mode 100644 test/round4.json create mode 100644 test/round5.json create mode 100644 test/round6.json create mode 100644 test/round7.json create mode 100644 test/test_json.cpp diff --git a/.cirrus.yml b/.cirrus.yml new file mode 100644 index 000000000000..f140fee12bc8 --- /dev/null +++ b/.cirrus.yml @@ -0,0 +1,44 @@ +env: + MAKEJOBS: "-j4" + RUN_TESTS: "true" + BASE_OUTDIR: "$CIRRUS_WORKING_DIR/out_dir_base" + DEBIAN_FRONTEND: "noninteractive" + +task: + container: + image: ubuntu:focal + cpu: 1 + memory: 1G + greedy: true # https://medium.com/cirruslabs/introducing-greedy-container-instances-29aad06dc2b4 + + matrix: + - name: "gcc" + env: + CC: "gcc" + CXX: "g++" + APT_PKGS: "gcc" + - name: "clang" + env: + CC: "clang" + CXX: "clang++" + APT_PKGS: "clang" + - name: "mingw" + env: + CC: "" + CXX: "" + UNIVALUE_CONFIG: "--host=x86_64-w64-mingw32" + APT_PKGS: "g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 binutils-mingw-w64-x86-64" + RUN_TESTS: "false" + + install_script: + - apt update + - apt install -y pkg-config build-essential libtool autotools-dev automake bsdmainutils + - apt install -y $APT_PKGS + autogen_script: + - ./autogen.sh + configure_script: + - ./configure --cache-file=config.cache --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib $UNIVALUE_CONFIG + make_script: + - make $MAKEJOBS V=1 + test_script: + - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d318d9cc8f6b..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,52 +0,0 @@ - -language: cpp - -compiler: - - clang - - gcc - -os: - - linux - - osx - -sudo: false - -env: - global: - - MAKEJOBS=-j3 - - RUN_TESTS=true - - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out - -cache: - apt: true - -addons: - apt: - packages: - - pkg-config - -before_script: - - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi - - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh - -script: - - if [ -n "$UNIVALUE_CONFIG" ]; then unset CC; unset CXX; fi - - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST - - UNIVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" - - ./configure --cache-file=config.cache $UNIVALUE_CONFIG_ALL $UNIVALUE_CONFIG || ( cat config.log && false) - - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false ) - - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi - -matrix: - fast_finish: true - include: - - os: linux - compiler: gcc - env: UNIVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false - addons: - apt: - packages: - - g++-mingw-w64-x86-64 - - gcc-mingw-w64-x86-64 - - binutils-mingw-w64-x86-64 diff --git a/Makefile.am b/Makefile.am index 34fe9e3f13db..476f14b922eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,26 +1,24 @@ +include sources.mk ACLOCAL_AMFLAGS = -I build-aux/m4 -.PHONY: gen +.PHONY: gen FORCE .INTERMEDIATE: $(GENBIN) -include_HEADERS = include/univalue.h -noinst_HEADERS = lib/univalue_escapes.h +include_HEADERS = $(UNIVALUE_DIST_HEADERS_INT) +noinst_HEADERS = $(UNIVALUE_LIB_HEADERS_INT) lib_LTLIBRARIES = libunivalue.la pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = pc/libunivalue.pc -libunivalue_la_SOURCES = \ - lib/univalue.cpp \ - lib/univalue_read.cpp \ - lib/univalue_write.cpp +libunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT) libunivalue_la_LDFLAGS = \ -version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \ -no-undefined libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include -TESTS = test/unitester +TESTS = test/object test/unitester test/no_nul GENBIN = gen/gen$(BUILD_EXEEXT) GEN_SRCS = gen/gen.cpp @@ -29,60 +27,32 @@ $(GENBIN): $(GEN_SRCS) @echo Building $@ $(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $< -gen: lib/univalue_escapes.h $(GENBIN) - @echo Updating $< +gen: $(GENBIN) FORCE + @echo Updating lib/univalue_escapes.h $(AM_V_at)$(GENBIN) > lib/univalue_escapes.h -noinst_PROGRAMS = $(TESTS) +noinst_PROGRAMS = $(TESTS) test/test_json -TEST_DATA_DIR=test - -test_unitester_SOURCES = test/unitester.cpp +test_unitester_SOURCES = $(UNIVALUE_TEST_UNITESTER_INT) test_unitester_LDADD = libunivalue.la -test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\" +test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\" test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) -TEST_FILES = \ - $(TEST_DATA_DIR)/fail10.json \ - $(TEST_DATA_DIR)/fail11.json \ - $(TEST_DATA_DIR)/fail12.json \ - $(TEST_DATA_DIR)/fail13.json \ - $(TEST_DATA_DIR)/fail14.json \ - $(TEST_DATA_DIR)/fail15.json \ - $(TEST_DATA_DIR)/fail16.json \ - $(TEST_DATA_DIR)/fail17.json \ - $(TEST_DATA_DIR)/fail18.json \ - $(TEST_DATA_DIR)/fail19.json \ - $(TEST_DATA_DIR)/fail1.json \ - $(TEST_DATA_DIR)/fail20.json \ - $(TEST_DATA_DIR)/fail21.json \ - $(TEST_DATA_DIR)/fail22.json \ - $(TEST_DATA_DIR)/fail23.json \ - $(TEST_DATA_DIR)/fail24.json \ - $(TEST_DATA_DIR)/fail25.json \ - $(TEST_DATA_DIR)/fail26.json \ - $(TEST_DATA_DIR)/fail27.json \ - $(TEST_DATA_DIR)/fail28.json \ - $(TEST_DATA_DIR)/fail29.json \ - $(TEST_DATA_DIR)/fail2.json \ - $(TEST_DATA_DIR)/fail30.json \ - $(TEST_DATA_DIR)/fail31.json \ - $(TEST_DATA_DIR)/fail32.json \ - $(TEST_DATA_DIR)/fail33.json \ - $(TEST_DATA_DIR)/fail34.json \ - $(TEST_DATA_DIR)/fail35.json \ - $(TEST_DATA_DIR)/fail36.json \ - $(TEST_DATA_DIR)/fail37.json \ - $(TEST_DATA_DIR)/fail3.json \ - $(TEST_DATA_DIR)/fail4.json \ - $(TEST_DATA_DIR)/fail5.json \ - $(TEST_DATA_DIR)/fail6.json \ - $(TEST_DATA_DIR)/fail7.json \ - $(TEST_DATA_DIR)/fail8.json \ - $(TEST_DATA_DIR)/fail9.json \ - $(TEST_DATA_DIR)/pass1.json \ - $(TEST_DATA_DIR)/pass2.json \ - $(TEST_DATA_DIR)/pass3.json \ - $(TEST_DATA_DIR)/round1.json - -EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS) +test_test_json_SOURCES = $(UNIVALUE_TEST_JSON_INT) +test_test_json_LDADD = libunivalue.la +test_test_json_CXXFLAGS = -I$(top_srcdir)/include +test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT) +test_no_nul_LDADD = libunivalue.la +test_no_nul_CXXFLAGS = -I$(top_srcdir)/include +test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT) +test_object_LDADD = libunivalue.la +test_object_CXXFLAGS = -I$(top_srcdir)/include +test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +TEST_FILES = $(UNIVALUE_TEST_FILES_INT) + +EXTRA_DIST=$(UNIVALUE_TEST_FILES_INT) $(GEN_SRCS) diff --git a/README b/README deleted file mode 100644 index 48167b083b0e..000000000000 --- a/README +++ /dev/null @@ -1,7 +0,0 @@ - - UniValue - -A universal value object, with JSON encoding (output) and decoding (input). - -Built as a single dynamic RAII C++ object class, and no templates. - diff --git a/README.md b/README.md new file mode 100644 index 000000000000..7c62c3397053 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ + +# UniValue + +## Summary + +A universal value class, with JSON encoding and decoding. + +UniValue is an abstract data type that may be a null, boolean, string, +number, array container, or a key/value dictionary container, nested to +an arbitrary depth. + +This class is aligned with the JSON standard, [RFC +7159](https://tools.ietf.org/html/rfc7159.html). + +## Library usage + +This is a fork of univalue used by Bitcoin Core. It is not maintained for usage +by other projects. Notably, the API may break in non-backward-compatible ways. + +Other projects looking for a maintained library should use the upstream +univalue at https://github.com/jgarzik/univalue. diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 000000000000..f7e5137003cf --- /dev/null +++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,962 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for no added switch, and then for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# Copyright (c) 2016, 2018 Krzesimir Nowak +# Copyright (c) 2019 Enji Cooper +# Copyright (c) 2020 Jason Merrill +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 12 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + + m4_if([$2], [], [dnl + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi]) + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 +) + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L + +#error "This is not a C++17 compiler" + +#else + +#include +#include +#include + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_structured_bindings + { + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L + +]]) diff --git a/configure.ac b/configure.ac index 0515b632bdf9..495b25a53d8e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ m4_define([libunivalue_major_version], [1]) m4_define([libunivalue_minor_version], [1]) -m4_define([libunivalue_micro_version], [1]) -m4_define([libunivalue_interface_age], [1]) +m4_define([libunivalue_micro_version], [4]) +m4_define([libunivalue_interface_age], [4]) # If you need a modifier for the version number. # Normally empty, but can be used to make "fixup" releases. m4_define([libunivalue_extraversion], []) @@ -14,7 +14,7 @@ m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_inter m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) -AC_INIT([univalue], [1.0.1], +AC_INIT([univalue], [1.0.4], [http://github.com/jgarzik/univalue/]) dnl make the compilation flags quiet unless V=1 is used @@ -45,6 +45,9 @@ AC_SUBST(LIBUNIVALUE_AGE) LT_INIT LT_LANG([C++]) +dnl Require C++11 compiler (no GNU extensions) +AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault]) + case $host in *mingw*) LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" diff --git a/gen/gen.cpp b/gen/gen.cpp index 17f361941d9e..b8a6c73f4ec4 100644 --- a/gen/gen.cpp +++ b/gen/gen.cpp @@ -1,6 +1,6 @@ // Copyright 2014 BitPay Inc. // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://opensource.org/licenses/mit-license.php. // // To re-create univalue_escapes.h: @@ -12,8 +12,6 @@ #include #include "univalue.h" -using namespace std; - static bool initEscapes; static std::string escapes[256]; @@ -47,7 +45,7 @@ static void outputEscape() for (unsigned int i = 0; i < 256; i++) { if (escapes[i].empty()) { - printf("\tNULL,\n"); + printf("\tnullptr,\n"); } else { printf("\t\""); diff --git a/include/univalue.h b/include/univalue.h index 8428b1c683ac..fc5cf402be3c 100644 --- a/include/univalue.h +++ b/include/univalue.h @@ -1,21 +1,19 @@ // Copyright 2014 BitPay Inc. // Copyright 2015 Bitcoin Core Developers // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://opensource.org/licenses/mit-license.php. #ifndef __UNIVALUE_H__ #define __UNIVALUE_H__ #include +#include #include #include #include #include -#include // .get_int64() -#include // std::pair - class UniValue { public: enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; @@ -47,7 +45,6 @@ class UniValue { std::string s(val_); setStr(s); } - ~UniValue() {} void clear(); @@ -56,7 +53,7 @@ class UniValue { bool setNumStr(const std::string& val); bool setInt(uint64_t val); bool setInt(int64_t val); - bool setInt(int val) { return setInt((int64_t)val); } + bool setInt(int val_) { return setInt((int64_t)val_); } bool setFloat(double val); bool setStr(const std::string& val); bool setArray(); @@ -69,10 +66,11 @@ class UniValue { size_t size() const { return values.size(); } bool getBool() const { return isTrue(); } - bool checkObject(const std::map& memberTypes); + void getObjMap(std::map& kv) const; + bool checkObject(const std::map& memberTypes) const; const UniValue& operator[](const std::string& key) const; - const UniValue& operator[](unsigned int index) const; - bool exists(const std::string& key) const { return (findKey(key) >= 0); } + const UniValue& operator[](size_t index) const; + bool exists(const std::string& key) const { size_t i; return findKey(key, i); } bool isNull() const { return (typ == VNULL); } bool isTrue() const { return (typ == VBOOL) && (val == "1"); } @@ -92,31 +90,56 @@ class UniValue { std::string s(val_); return push_back(s); } + bool push_back(uint64_t val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_back(int64_t val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_back(bool val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_back(int val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_back(double val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } bool push_backV(const std::vector& vec); + void __pushKV(const std::string& key, const UniValue& val); bool pushKV(const std::string& key, const UniValue& val); - bool pushKV(const std::string& key, const std::string& val) { - UniValue tmpVal(VSTR, val); + bool pushKV(const std::string& key, const std::string& val_) { + UniValue tmpVal(VSTR, val_); return pushKV(key, tmpVal); } bool pushKV(const std::string& key, const char *val_) { - std::string val(val_); - return pushKV(key, val); + std::string _val(val_); + return pushKV(key, _val); + } + bool pushKV(const std::string& key, int64_t val_) { + UniValue tmpVal(val_); + return pushKV(key, tmpVal); } - bool pushKV(const std::string& key, int64_t val) { - UniValue tmpVal(val); + bool pushKV(const std::string& key, uint64_t val_) { + UniValue tmpVal(val_); return pushKV(key, tmpVal); } - bool pushKV(const std::string& key, uint64_t val) { - UniValue tmpVal(val); + bool pushKV(const std::string& key, bool val_) { + UniValue tmpVal(val_); return pushKV(key, tmpVal); } - bool pushKV(const std::string& key, int val) { - UniValue tmpVal((int64_t)val); + bool pushKV(const std::string& key, int val_) { + UniValue tmpVal((int64_t)val_); return pushKV(key, tmpVal); } - bool pushKV(const std::string& key, double val) { - UniValue tmpVal(val); + bool pushKV(const std::string& key, double val_) { + UniValue tmpVal(val_); return pushKV(key, tmpVal); } bool pushKVs(const UniValue& obj); @@ -124,9 +147,10 @@ class UniValue { std::string write(unsigned int prettyIndent = 0, unsigned int indentLevel = 0) const; - bool read(const char *raw); + bool read(const char *raw, size_t len); + bool read(const char *raw) { return read(raw, strlen(raw)); } bool read(const std::string& rawStr) { - return read(rawStr.c_str()); + return read(rawStr.data(), rawStr.size()); } private: @@ -135,17 +159,17 @@ class UniValue { std::vector keys; std::vector values; - int findKey(const std::string& key) const; + bool findKey(const std::string& key, size_t& retIdx) const; void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; public: // Strict type-specific getters, these throw std::runtime_error if the // value is of unexpected type - std::vector getKeys() const; - std::vector getValues() const; + const std::vector& getKeys() const; + const std::vector& getValues() const; bool get_bool() const; - std::string get_str() const; + const std::string& get_str() const; int get_int() const; int64_t get_int64() const; double get_real() const; @@ -153,76 +177,9 @@ class UniValue { const UniValue& get_array() const; enum VType type() const { return getType(); } - bool push_back(std::pair pear) { - return pushKV(pear.first, pear.second); - } friend const UniValue& find_value( const UniValue& obj, const std::string& name); }; -// -// The following were added for compatibility with json_spirit. -// Most duplicate other methods, and should be removed. -// -static inline std::pair Pair(const char *cKey, const char *cVal) -{ - std::string key(cKey); - UniValue uVal(cVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, std::string strVal) -{ - std::string key(cKey); - UniValue uVal(strVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, uint64_t u64Val) -{ - std::string key(cKey); - UniValue uVal(u64Val); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, int64_t i64Val) -{ - std::string key(cKey); - UniValue uVal(i64Val); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, bool iVal) -{ - std::string key(cKey); - UniValue uVal(iVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, int iVal) -{ - std::string key(cKey); - UniValue uVal(iVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, double dVal) -{ - std::string key(cKey); - UniValue uVal(dVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, const UniValue& uVal) -{ - std::string key(cKey); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(std::string key, const UniValue& uVal) -{ - return std::make_pair(key, uVal); -} - enum jtokentype { JTOK_ERR = -1, JTOK_NONE = 0, // eof @@ -240,7 +197,7 @@ enum jtokentype { }; extern enum jtokentype getJsonToken(std::string& tokenVal, - unsigned int& consumed, const char *raw); + unsigned int& consumed, const char *raw, const char *end); extern const char *uvTypeName(UniValue::VType t); static inline bool jsonTokenIsValue(enum jtokentype jtt) diff --git a/lib/univalue.cpp b/lib/univalue.cpp index 0076d6678ec7..c4e59fae744b 100644 --- a/lib/univalue.cpp +++ b/lib/univalue.cpp @@ -1,80 +1,15 @@ // Copyright 2014 BitPay Inc. // Copyright 2015 Bitcoin Core Developers // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://opensource.org/licenses/mit-license.php. #include -#include #include -#include #include -#include #include -#include #include "univalue.h" -namespace -{ -static bool ParsePrechecks(const std::string& str) -{ - if (str.empty()) // No empty string allowed - return false; - if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed - return false; - if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed - return false; - return true; -} - -bool ParseInt32(const std::string& str, int32_t *out) -{ - if (!ParsePrechecks(str)) - return false; - char *endp = NULL; - errno = 0; // strtol will not set errno if valid - long int n = strtol(str.c_str(), &endp, 10); - if(out) *out = (int32_t)n; - // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow - // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit - // platforms the size of these types may be different. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - -bool ParseInt64(const std::string& str, int64_t *out) -{ - if (!ParsePrechecks(str)) - return false; - char *endp = NULL; - errno = 0; // strtoll will not set errno if valid - long long int n = strtoll(str.c_str(), &endp, 10); - if(out) *out = (int64_t)n; - // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow - // we still have to check that the returned value is within the range of an *int64_t*. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - -bool ParseDouble(const std::string& str, double *out) -{ - if (!ParsePrechecks(str)) - return false; - if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed - return false; - std::istringstream text(str); - text.imbue(std::locale::classic()); - double result; - text >> result; - if(out) *out = result; - return text.eof() && !text.fail(); -} -} - -using namespace std; - const UniValue NullUniValue; void UniValue::clear() @@ -100,15 +35,15 @@ bool UniValue::setBool(bool val_) return true; } -static bool validNumStr(const string& s) +static bool validNumStr(const std::string& s) { - string tokenVal; + std::string tokenVal; unsigned int consumed; - enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str()); + enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size()); return (tt == JTOK_NUMBER); } -bool UniValue::setNumStr(const string& val_) +bool UniValue::setNumStr(const std::string& val_) { if (!validNumStr(val_)) return false; @@ -119,39 +54,36 @@ bool UniValue::setNumStr(const string& val_) return true; } -bool UniValue::setInt(uint64_t val) +bool UniValue::setInt(uint64_t val_) { - string s; - ostringstream oss; + std::ostringstream oss; - oss << val; + oss << val_; return setNumStr(oss.str()); } -bool UniValue::setInt(int64_t val) +bool UniValue::setInt(int64_t val_) { - string s; - ostringstream oss; + std::ostringstream oss; - oss << val; + oss << val_; return setNumStr(oss.str()); } -bool UniValue::setFloat(double val) +bool UniValue::setFloat(double val_) { - string s; - ostringstream oss; + std::ostringstream oss; - oss << std::setprecision(16) << val; + oss << std::setprecision(16) << val_; bool ret = setNumStr(oss.str()); typ = VNUM; return ret; } -bool UniValue::setStr(const string& val_) +bool UniValue::setStr(const std::string& val_) { clear(); typ = VSTR; @@ -173,12 +105,12 @@ bool UniValue::setObject() return true; } -bool UniValue::push_back(const UniValue& val) +bool UniValue::push_back(const UniValue& val_) { if (typ != VARR) return false; - values.push_back(val); + values.push_back(val_); return true; } @@ -192,13 +124,22 @@ bool UniValue::push_backV(const std::vector& vec) return true; } -bool UniValue::pushKV(const std::string& key, const UniValue& val) +void UniValue::__pushKV(const std::string& key, const UniValue& val_) +{ + keys.push_back(key); + values.push_back(val_); +} + +bool UniValue::pushKV(const std::string& key, const UniValue& val_) { if (typ != VOBJ) return false; - keys.push_back(key); - values.push_back(val); + size_t idx; + if (findKey(key, idx)) + values[idx] = val_; + else + __pushKV(key, val_); return true; } @@ -207,34 +148,49 @@ bool UniValue::pushKVs(const UniValue& obj) if (typ != VOBJ || obj.typ != VOBJ) return false; - for (unsigned int i = 0; i < obj.keys.size(); i++) { - keys.push_back(obj.keys[i]); - values.push_back(obj.values.at(i)); - } + for (size_t i = 0; i < obj.keys.size(); i++) + __pushKV(obj.keys[i], obj.values.at(i)); return true; } -int UniValue::findKey(const std::string& key) const +void UniValue::getObjMap(std::map& kv) const +{ + if (typ != VOBJ) + return; + + kv.clear(); + for (size_t i = 0; i < keys.size(); i++) + kv[keys[i]] = values[i]; +} + +bool UniValue::findKey(const std::string& key, size_t& retIdx) const { - for (unsigned int i = 0; i < keys.size(); i++) { - if (keys[i] == key) - return (int) i; + for (size_t i = 0; i < keys.size(); i++) { + if (keys[i] == key) { + retIdx = i; + return true; + } } - return -1; + return false; } -bool UniValue::checkObject(const std::map& t) +bool UniValue::checkObject(const std::map& t) const { - for (std::map::const_iterator it = t.begin(); - it != t.end(); it++) { - int idx = findKey(it->first); - if (idx < 0) + if (typ != VOBJ) { + return false; + } + + for (const auto& object: t) { + size_t idx = 0; + if (!findKey(object.first, idx)) { return false; + } - if (values.at(idx).getType() != it->second) + if (values.at(idx).getType() != object.second) { return false; + } } return true; @@ -245,14 +201,14 @@ const UniValue& UniValue::operator[](const std::string& key) const if (typ != VOBJ) return NullUniValue; - int index = findKey(key); - if (index < 0) + size_t index = 0; + if (!findKey(key, index)) return NullUniValue; return values.at(index); } -const UniValue& UniValue::operator[](unsigned int index) const +const UniValue& UniValue::operator[](size_t index) const { if (typ != VOBJ && typ != VARR) return NullUniValue; @@ -274,7 +230,7 @@ const char *uvTypeName(UniValue::VType t) } // not reached - return NULL; + return nullptr; } const UniValue& find_value(const UniValue& obj, const std::string& name) @@ -286,75 +242,3 @@ const UniValue& find_value(const UniValue& obj, const std::string& name) return NullUniValue; } -std::vector UniValue::getKeys() const -{ - if (typ != VOBJ) - throw std::runtime_error("JSON value is not an object as expected"); - return keys; -} - -std::vector UniValue::getValues() const -{ - if (typ != VOBJ && typ != VARR) - throw std::runtime_error("JSON value is not an object or array as expected"); - return values; -} - -bool UniValue::get_bool() const -{ - if (typ != VBOOL) - throw std::runtime_error("JSON value is not a boolean as expected"); - return getBool(); -} - -std::string UniValue::get_str() const -{ - if (typ != VSTR) - throw std::runtime_error("JSON value is not a string as expected"); - return getValStr(); -} - -int UniValue::get_int() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not an integer as expected"); - int32_t retval; - if (!ParseInt32(getValStr(), &retval)) - throw std::runtime_error("JSON integer out of range"); - return retval; -} - -int64_t UniValue::get_int64() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not an integer as expected"); - int64_t retval; - if (!ParseInt64(getValStr(), &retval)) - throw std::runtime_error("JSON integer out of range"); - return retval; -} - -double UniValue::get_real() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not a number as expected"); - double retval; - if (!ParseDouble(getValStr(), &retval)) - throw std::runtime_error("JSON double out of range"); - return retval; -} - -const UniValue& UniValue::get_obj() const -{ - if (typ != VOBJ) - throw std::runtime_error("JSON value is not an object as expected"); - return *this; -} - -const UniValue& UniValue::get_array() const -{ - if (typ != VARR) - throw std::runtime_error("JSON value is not an array as expected"); - return *this; -} - diff --git a/lib/univalue_escapes.h b/lib/univalue_escapes.h index 74596aab6d2c..3f714f8e5bc4 100644 --- a/lib/univalue_escapes.h +++ b/lib/univalue_escapes.h @@ -34,229 +34,229 @@ static const char *escapes[256] = { "\\u001d", "\\u001e", "\\u001f", - NULL, - NULL, + nullptr, + nullptr, "\\\"", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, "\\\\", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, "\\u007f", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, }; #endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H diff --git a/lib/univalue_get.cpp b/lib/univalue_get.cpp new file mode 100644 index 000000000000..5af89a3561c1 --- /dev/null +++ b/lib/univalue_get.cpp @@ -0,0 +1,148 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "univalue.h" + +namespace +{ +static bool ParsePrechecks(const std::string& str) +{ + if (str.empty()) // No empty string allowed + return false; + if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed + return false; + if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed + return false; + return true; +} + +bool ParseInt32(const std::string& str, int32_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = nullptr; + errno = 0; // strtol will not set errno if valid + long int n = strtol(str.c_str(), &endp, 10); + if(out) *out = (int32_t)n; + // Note that strtol returns a *long int*, so even if strtol doesn't report an over/underflow + // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit + // platforms the size of these types may be different. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseInt64(const std::string& str, int64_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = nullptr; + errno = 0; // strtoll will not set errno if valid + long long int n = strtoll(str.c_str(), &endp, 10); + if(out) *out = (int64_t)n; + // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int64_t*. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseDouble(const std::string& str, double *out) +{ + if (!ParsePrechecks(str)) + return false; + if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed + return false; + std::istringstream text(str); + text.imbue(std::locale::classic()); + double result; + text >> result; + if(out) *out = result; + return text.eof() && !text.fail(); +} +} + +const std::vector& UniValue::getKeys() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return keys; +} + +const std::vector& UniValue::getValues() const +{ + if (typ != VOBJ && typ != VARR) + throw std::runtime_error("JSON value is not an object or array as expected"); + return values; +} + +bool UniValue::get_bool() const +{ + if (typ != VBOOL) + throw std::runtime_error("JSON value is not a boolean as expected"); + return getBool(); +} + +const std::string& UniValue::get_str() const +{ + if (typ != VSTR) + throw std::runtime_error("JSON value is not a string as expected"); + return getValStr(); +} + +int UniValue::get_int() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int32_t retval; + if (!ParseInt32(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +int64_t UniValue::get_int64() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int64_t retval; + if (!ParseInt64(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +double UniValue::get_real() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not a number as expected"); + double retval; + if (!ParseDouble(getValStr(), &retval)) + throw std::runtime_error("JSON double out of range"); + return retval; +} + +const UniValue& UniValue::get_obj() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return *this; +} + +const UniValue& UniValue::get_array() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an array as expected"); + return *this; +} + diff --git a/lib/univalue_read.cpp b/lib/univalue_read.cpp index c7516b962816..be39bfe57a7a 100644 --- a/lib/univalue_read.cpp +++ b/lib/univalue_read.cpp @@ -1,13 +1,20 @@ // Copyright 2014 BitPay Inc. // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://opensource.org/licenses/mit-license.php. #include #include #include #include "univalue.h" +#include "univalue_utffilter.h" -using namespace std; +/* + * According to stackexchange, the original json test suite wanted + * to limit depth to 22. Widely-deployed PHP bails at depth 512, + * so we will follow PHP's lead, which should be more than sufficient + * (further stackexchange comments indicate depth > 32 rarely occurs). + */ +static const size_t MAX_JSON_DEPTH = 512; static bool json_isdigit(int ch) { @@ -41,22 +48,22 @@ static const char *hatoui(const char *first, const char *last, return first; } -enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, - const char *raw) +enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed, + const char *raw, const char *end) { tokenVal.clear(); consumed = 0; const char *rawStart = raw; - while ((*raw) && (json_isspace(*raw))) // skip whitespace + while (raw < end && (json_isspace(*raw))) // skip whitespace raw++; - switch (*raw) { - - case 0: + if (raw >= end) return JTOK_NONE; + switch (*raw) { + case '{': raw++; consumed = (raw - rawStart); @@ -113,7 +120,7 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, case '8': case '9': { // part 1: int - string numStr; + std::string numStr; const char *first = raw; @@ -126,40 +133,40 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, numStr += *raw; // copy first char raw++; - if ((*first == '-') && (!json_isdigit(*raw))) + if ((*first == '-') && (raw < end) && (!json_isdigit(*raw))) return JTOK_ERR; - while ((*raw) && json_isdigit(*raw)) { // copy digits + while (raw < end && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } // part 2: frac - if (*raw == '.') { + if (raw < end && *raw == '.') { numStr += *raw; // copy . raw++; - if (!json_isdigit(*raw)) + if (raw >= end || !json_isdigit(*raw)) return JTOK_ERR; - while ((*raw) && json_isdigit(*raw)) { // copy digits + while (raw < end && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } } // part 3: exp - if (*raw == 'e' || *raw == 'E') { + if (raw < end && (*raw == 'e' || *raw == 'E')) { numStr += *raw; // copy E raw++; - if (*raw == '-' || *raw == '+') { // copy +/- + if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/- numStr += *raw; raw++; } - if (!json_isdigit(*raw)) + if (raw >= end || !json_isdigit(*raw)) return JTOK_ERR; - while ((*raw) && json_isdigit(*raw)) { // copy digits + while (raw < end && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } @@ -173,42 +180,36 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, case '"': { raw++; // skip " - string valStr; + std::string valStr; + JSONUTF8StringFilter writer(valStr); - while (*raw) { - if (*raw < 0x20) + while (true) { + if (raw >= end || (unsigned char)*raw < 0x20) return JTOK_ERR; else if (*raw == '\\') { raw++; // skip backslash + if (raw >= end) + return JTOK_ERR; + switch (*raw) { - case '"': valStr += "\""; break; - case '\\': valStr += "\\"; break; - case '/': valStr += "/"; break; - case 'b': valStr += "\b"; break; - case 'f': valStr += "\f"; break; - case 'n': valStr += "\n"; break; - case 'r': valStr += "\r"; break; - case 't': valStr += "\t"; break; + case '"': writer.push_back('\"'); break; + case '\\': writer.push_back('\\'); break; + case '/': writer.push_back('/'); break; + case 'b': writer.push_back('\b'); break; + case 'f': writer.push_back('\f'); break; + case 'n': writer.push_back('\n'); break; + case 'r': writer.push_back('\r'); break; + case 't': writer.push_back('\t'); break; case 'u': { unsigned int codepoint; - if (hatoui(raw + 1, raw + 1 + 4, codepoint) != + if (raw + 1 + 4 >= end || + hatoui(raw + 1, raw + 1 + 4, codepoint) != raw + 1 + 4) return JTOK_ERR; - - if (codepoint <= 0x7f) - valStr.push_back((char)codepoint); - else if (codepoint <= 0x7FF) { - valStr.push_back((char)(0xC0 | (codepoint >> 6))); - valStr.push_back((char)(0x80 | (codepoint & 0x3F))); - } else if (codepoint <= 0xFFFF) { - valStr.push_back((char)(0xE0 | (codepoint >> 12))); - valStr.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F))); - valStr.push_back((char)(0x80 | (codepoint & 0x3F))); - } - + writer.push_back_u(codepoint); raw += 4; break; } @@ -226,11 +227,13 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, } else { - valStr += *raw; + writer.push_back(static_cast(*raw)); raw++; } } + if (!writer.finalize()) + return JTOK_ERR; tokenVal = valStr; consumed = (raw - rawStart); return JTOK_STRING; @@ -241,7 +244,7 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, } } -enum expect_bits { +enum expect_bits : unsigned { EXP_OBJ_NAME = (1U << 0), EXP_COLON = (1U << 1), EXP_ARR_VALUE = (1U << 2), @@ -253,21 +256,22 @@ enum expect_bits { #define setExpect(bit) (expectMask |= EXP_##bit) #define clearExpect(bit) (expectMask &= ~EXP_##bit) -bool UniValue::read(const char *raw) +bool UniValue::read(const char *raw, size_t size) { clear(); uint32_t expectMask = 0; - vector stack; + std::vector stack; - string tokenVal; + std::string tokenVal; unsigned int consumed; enum jtokentype tok = JTOK_NONE; enum jtokentype last_tok = JTOK_NONE; + const char* end = raw + size; do { last_tok = tok; - tok = getJsonToken(tokenVal, consumed, raw); + tok = getJsonToken(tokenVal, consumed, raw, end); if (tok == JTOK_NONE || tok == JTOK_ERR) return false; raw += consumed; @@ -327,6 +331,9 @@ bool UniValue::read(const char *raw) stack.push_back(newTop); } + if (stack.size() > MAX_JSON_DEPTH) + return false; + if (utyp == VOBJ) setExpect(OBJ_NAME); else @@ -378,9 +385,6 @@ bool UniValue::read(const char *raw) case JTOK_KW_NULL: case JTOK_KW_TRUE: case JTOK_KW_FALSE: { - if (!stack.size()) - return false; - UniValue tmpVal; switch (tok) { case JTOK_KW_NULL: @@ -395,6 +399,11 @@ bool UniValue::read(const char *raw) default: /* impossible */ break; } + if (!stack.size()) { + *this = tmpVal; + break; + } + UniValue *top = stack.back(); top->values.push_back(tmpVal); @@ -403,10 +412,12 @@ bool UniValue::read(const char *raw) } case JTOK_NUMBER: { - if (!stack.size()) - return false; - UniValue tmpVal(VNUM, tokenVal); + if (!stack.size()) { + *this = tmpVal; + break; + } + UniValue *top = stack.back(); top->values.push_back(tmpVal); @@ -415,17 +426,18 @@ bool UniValue::read(const char *raw) } case JTOK_STRING: { - if (!stack.size()) - return false; - - UniValue *top = stack.back(); - if (expect(OBJ_NAME)) { + UniValue *top = stack.back(); top->keys.push_back(tokenVal); clearExpect(OBJ_NAME); setExpect(COLON); } else { UniValue tmpVal(VSTR, tokenVal); + if (!stack.size()) { + *this = tmpVal; + break; + } + UniValue *top = stack.back(); top->values.push_back(tmpVal); } @@ -439,7 +451,7 @@ bool UniValue::read(const char *raw) } while (!stack.empty ()); /* Check that nothing follows the initial construct (parsed above). */ - tok = getJsonToken(tokenVal, consumed, raw); + tok = getJsonToken(tokenVal, consumed, raw, end); if (tok != JTOK_NONE) return false; diff --git a/lib/univalue_utffilter.h b/lib/univalue_utffilter.h new file mode 100644 index 000000000000..c24ac58eaf2b --- /dev/null +++ b/lib/univalue_utffilter.h @@ -0,0 +1,119 @@ +// Copyright 2016 Wladimir J. van der Laan +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. +#ifndef UNIVALUE_UTFFILTER_H +#define UNIVALUE_UTFFILTER_H + +#include + +/** + * Filter that generates and validates UTF-8, as well as collates UTF-16 + * surrogate pairs as specified in RFC4627. + */ +class JSONUTF8StringFilter +{ +public: + explicit JSONUTF8StringFilter(std::string &s): + str(s), is_valid(true), codepoint(0), state(0), surpair(0) + { + } + // Write single 8-bit char (may be part of UTF-8 sequence) + void push_back(unsigned char ch) + { + if (state == 0) { + if (ch < 0x80) // 7-bit ASCII, fast direct pass-through + str.push_back(ch); + else if (ch < 0xc0) // Mid-sequence character, invalid in this state + is_valid = false; + else if (ch < 0xe0) { // Start of 2-byte sequence + codepoint = (ch & 0x1f) << 6; + state = 6; + } else if (ch < 0xf0) { // Start of 3-byte sequence + codepoint = (ch & 0x0f) << 12; + state = 12; + } else if (ch < 0xf8) { // Start of 4-byte sequence + codepoint = (ch & 0x07) << 18; + state = 18; + } else // Reserved, invalid + is_valid = false; + } else { + if ((ch & 0xc0) != 0x80) // Not a continuation, invalid + is_valid = false; + state -= 6; + codepoint |= (ch & 0x3f) << state; + if (state == 0) + push_back_u(codepoint); + } + } + // Write codepoint directly, possibly collating surrogate pairs + void push_back_u(unsigned int codepoint_) + { + if (state) // Only accept full codepoints in open state + is_valid = false; + if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair + if (surpair) // Two subsequent surrogate pair openers - fail + is_valid = false; + else + surpair = codepoint_; + } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair + if (surpair) { // Open surrogate pair, expect second half + // Compute code point from UTF-16 surrogate pair + append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00)); + surpair = 0; + } else // Second half doesn't follow a first half - fail + is_valid = false; + } else { + if (surpair) // First half of surrogate pair not followed by second - fail + is_valid = false; + else + append_codepoint(codepoint_); + } + } + // Check that we're in a state where the string can be ended + // No open sequences, no open surrogate pairs, etc + bool finalize() + { + if (state || surpair) + is_valid = false; + return is_valid; + } +private: + std::string &str; + bool is_valid; + // Current UTF-8 decoding state + unsigned int codepoint; + int state; // Top bit to be filled in for next UTF-8 byte, or 0 + + // Keep track of the following state to handle the following section of + // RFC4627: + // + // To escape an extended character that is not in the Basic Multilingual + // Plane, the character is represented as a twelve-character sequence, + // encoding the UTF-16 surrogate pair. So, for example, a string + // containing only the G clef character (U+1D11E) may be represented as + // "\uD834\uDD1E". + // + // Two subsequent \u.... may have to be replaced with one actual codepoint. + unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0 + + void append_codepoint(unsigned int codepoint_) + { + if (codepoint_ <= 0x7f) + str.push_back((char)codepoint_); + else if (codepoint_ <= 0x7FF) { + str.push_back((char)(0xC0 | (codepoint_ >> 6))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0xFFFF) { + str.push_back((char)(0xE0 | (codepoint_ >> 12))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0x1FFFFF) { + str.push_back((char)(0xF0 | (codepoint_ >> 18))); + str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } + } +}; + +#endif diff --git a/lib/univalue_write.cpp b/lib/univalue_write.cpp index ceb4cc9166cd..3a2c580c7f69 100644 --- a/lib/univalue_write.cpp +++ b/lib/univalue_write.cpp @@ -1,46 +1,34 @@ // Copyright 2014 BitPay Inc. // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://opensource.org/licenses/mit-license.php. #include -#include #include #include "univalue.h" #include "univalue_escapes.h" -// TODO: Using UTF8 - -using namespace std; - -static string json_escape(const string& inS) +static std::string json_escape(const std::string& inS) { - string outS; + std::string outS; outS.reserve(inS.size() * 2); for (unsigned int i = 0; i < inS.size(); i++) { - unsigned char ch = inS[i]; + unsigned char ch = static_cast(inS[i]); const char *escStr = escapes[ch]; if (escStr) outS += escStr; - - else if (ch < 0x80) - outS += ch; - - else { // TODO handle UTF-8 properly - char tmpesc[16]; - sprintf(tmpesc, "\\u%04x", ch); - outS += tmpesc; - } + else + outS += static_cast(ch); } return outS; } -string UniValue::write(unsigned int prettyIndent, - unsigned int indentLevel) const +std::string UniValue::write(unsigned int prettyIndent, + unsigned int indentLevel) const { - string s; + std::string s; s.reserve(1024); unsigned int modIndent = indentLevel; @@ -71,12 +59,12 @@ string UniValue::write(unsigned int prettyIndent, return s; } -static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, string& s) +static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) { s.append(prettyIndent * indentLevel, ' '); } -void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s) const +void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const { s += "["; if (prettyIndent) @@ -88,8 +76,6 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s s += values[i].write(prettyIndent, indentLevel + 1); if (i != (values.size() - 1)) { s += ","; - if (prettyIndent) - s += " "; } if (prettyIndent) s += "\n"; @@ -100,7 +86,7 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s s += "]"; } -void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s) const +void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const { s += "{"; if (prettyIndent) diff --git a/sources.mk b/sources.mk new file mode 100644 index 000000000000..efab6d277f93 --- /dev/null +++ b/sources.mk @@ -0,0 +1,95 @@ +# - All variables are namespaced with UNIVALUE_ to avoid colliding with +# downstream makefiles. +# - All Variables ending in _HEADERS or _SOURCES confuse automake, so the +# _INT postfix is applied. +# - Convenience variables, for example a UNIVALUE_TEST_DIR should not be used +# as they interfere with automatic dependency generation +# - The %reldir% is the relative path from the Makefile.am. This allows +# downstreams to use these variables without having to manually account for +# the path change. + +UNIVALUE_INCLUDE_DIR_INT = %reldir%/include + +UNIVALUE_DIST_HEADERS_INT = +UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue.h + +UNIVALUE_LIB_HEADERS_INT = +UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_utffilter.h +UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_escapes.h + +UNIVALUE_LIB_SOURCES_INT = +UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue.cpp +UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_get.cpp +UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_read.cpp +UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_write.cpp + +UNIVALUE_TEST_DATA_DIR_INT = %reldir%/test + +UNIVALUE_TEST_UNITESTER_INT = +UNIVALUE_TEST_UNITESTER_INT += %reldir%/test/unitester.cpp + +UNIVALUE_TEST_JSON_INT = +UNIVALUE_TEST_JSON_INT += %reldir%/test/test_json.cpp + +UNIVALUE_TEST_NO_NUL_INT = +UNIVALUE_TEST_NO_NUL_INT += %reldir%/test/no_nul.cpp + +UNIVALUE_TEST_OBJECT_INT = +UNIVALUE_TEST_OBJECT_INT += %reldir%/test/object.cpp + +UNIVALUE_TEST_FILES_INT = +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail1.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail2.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail3.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail4.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail5.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail6.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail7.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail8.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail9.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail10.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail11.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail12.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail13.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail14.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail15.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail16.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail17.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail18.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail19.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail20.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail21.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail22.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail23.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail24.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail25.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail26.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail27.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail28.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail29.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail30.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail31.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail32.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail33.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail34.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail35.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail36.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail37.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail38.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail39.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail40.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail41.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail42.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail44.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/fail45.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/pass1.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/pass2.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/pass3.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/pass4.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/round1.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/round2.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/round3.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/round4.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/round5.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/round6.json +UNIVALUE_TEST_FILES_INT += %reldir%/test/round7.json diff --git a/test/.gitignore b/test/.gitignore index 3d9347fe7e52..7b27cf0da290 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,4 +1,8 @@ + +object unitester +test_json +no_nul *.trs *.log diff --git a/test/fail1.json b/test/fail1.json index 6216b865f102..8feb01a6d0db 100644 --- a/test/fail1.json +++ b/test/fail1.json @@ -1 +1 @@ -"A JSON payload should be an object or array, not a string." \ No newline at end of file +"This is a string that never ends, yes it goes on and on, my friends. diff --git a/test/fail38.json b/test/fail38.json new file mode 100644 index 000000000000..b245e2e46cad --- /dev/null +++ b/test/fail38.json @@ -0,0 +1 @@ +["\ud834"] diff --git a/test/fail39.json b/test/fail39.json new file mode 100644 index 000000000000..7c9e263f27de --- /dev/null +++ b/test/fail39.json @@ -0,0 +1 @@ +["\udd61"] diff --git a/test/fail40.json b/test/fail40.json new file mode 100644 index 000000000000..664dc9e245f6 --- /dev/null +++ b/test/fail40.json @@ -0,0 +1 @@ +["…¡"] \ No newline at end of file diff --git a/test/fail41.json b/test/fail41.json new file mode 100644 index 000000000000..0de342a2b5fd --- /dev/null +++ b/test/fail41.json @@ -0,0 +1 @@ +["ð…"] \ No newline at end of file diff --git a/test/fail42.json b/test/fail42.json new file mode 100644 index 0000000000000000000000000000000000000000..9c7565adbddf645df5edfbdcd630c7a0f94aa2eb GIT binary patch literal 37 kcma!6N=i-3FG^L&E6q_zsw_!Wie*qrOe;w(LWpny0Pvs;RsaA1 literal 0 HcmV?d00001 diff --git a/test/fail44.json b/test/fail44.json new file mode 100644 index 000000000000..80edceddf1ef --- /dev/null +++ b/test/fail44.json @@ -0,0 +1 @@ +"This file ends without a newline or close-quote. \ No newline at end of file diff --git a/test/fail45.json b/test/fail45.json new file mode 100644 index 000000000000..03a30d88009a --- /dev/null +++ b/test/fail45.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] diff --git a/test/no_nul.cpp b/test/no_nul.cpp new file mode 100644 index 000000000000..83d292200bf8 --- /dev/null +++ b/test/no_nul.cpp @@ -0,0 +1,8 @@ +#include "univalue.h" + +int main (int argc, char *argv[]) +{ + char buf[] = "___[1,2,3]___"; + UniValue val; + return val.read(buf + 3, 7) ? 0 : 1; +} diff --git a/test/object.cpp b/test/object.cpp new file mode 100644 index 000000000000..c2f52f83ac21 --- /dev/null +++ b/test/object.cpp @@ -0,0 +1,420 @@ +// Copyright (c) 2014 BitPay Inc. +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include + +#define BOOST_FIXTURE_TEST_SUITE(a, b) +#define BOOST_AUTO_TEST_CASE(funcName) void funcName() +#define BOOST_AUTO_TEST_SUITE_END() +#define BOOST_CHECK(expr) assert(expr) +#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2)) +#define BOOST_CHECK_THROW(stmt, excMatch) { \ + try { \ + (stmt); \ + assert(0 && "No exception caught"); \ + } catch (excMatch & e) { \ + } catch (...) { \ + assert(0 && "Wrong exception caught"); \ + } \ + } +#define BOOST_CHECK_NO_THROW(stmt) { \ + try { \ + (stmt); \ + } catch (...) { \ + assert(0); \ + } \ + } + +BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(univalue_constructor) +{ + UniValue v1; + BOOST_CHECK(v1.isNull()); + + UniValue v2(UniValue::VSTR); + BOOST_CHECK(v2.isStr()); + + UniValue v3(UniValue::VSTR, "foo"); + BOOST_CHECK(v3.isStr()); + BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); + + UniValue numTest; + BOOST_CHECK(numTest.setNumStr("82")); + BOOST_CHECK(numTest.isNum()); + BOOST_CHECK_EQUAL(numTest.getValStr(), "82"); + + uint64_t vu64 = 82; + UniValue v4(vu64); + BOOST_CHECK(v4.isNum()); + BOOST_CHECK_EQUAL(v4.getValStr(), "82"); + + int64_t vi64 = -82; + UniValue v5(vi64); + BOOST_CHECK(v5.isNum()); + BOOST_CHECK_EQUAL(v5.getValStr(), "-82"); + + int vi = -688; + UniValue v6(vi); + BOOST_CHECK(v6.isNum()); + BOOST_CHECK_EQUAL(v6.getValStr(), "-688"); + + double vd = -7.21; + UniValue v7(vd); + BOOST_CHECK(v7.isNum()); + BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); + + std::string vs("yawn"); + UniValue v8(vs); + BOOST_CHECK(v8.isStr()); + BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); + + const char *vcs = "zappa"; + UniValue v9(vcs); + BOOST_CHECK(v9.isStr()); + BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); +} + +BOOST_AUTO_TEST_CASE(univalue_typecheck) +{ + UniValue v1; + BOOST_CHECK(v1.setNumStr("1")); + BOOST_CHECK(v1.isNum()); + BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); + + UniValue v2; + BOOST_CHECK(v2.setBool(true)); + BOOST_CHECK_EQUAL(v2.get_bool(), true); + BOOST_CHECK_THROW(v2.get_int(), std::runtime_error); + + UniValue v3; + BOOST_CHECK(v3.setNumStr("32482348723847471234")); + BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error); + BOOST_CHECK(v3.setNumStr("1000")); + BOOST_CHECK_EQUAL(v3.get_int64(), 1000); + + UniValue v4; + BOOST_CHECK(v4.setNumStr("2147483648")); + BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648); + BOOST_CHECK_THROW(v4.get_int(), std::runtime_error); + BOOST_CHECK(v4.setNumStr("1000")); + BOOST_CHECK_EQUAL(v4.get_int(), 1000); + BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); + BOOST_CHECK_EQUAL(v4.get_real(), 1000); + BOOST_CHECK_THROW(v4.get_array(), std::runtime_error); + BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error); + BOOST_CHECK_THROW(v4.getValues(), std::runtime_error); + BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error); + + UniValue v5; + BOOST_CHECK(v5.read("[true, 10]")); + BOOST_CHECK_NO_THROW(v5.get_array()); + std::vector vals = v5.getValues(); + BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error); + BOOST_CHECK_EQUAL(vals[0].get_bool(), true); + + BOOST_CHECK_EQUAL(vals[1].get_int(), 10); + BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(univalue_set) +{ + UniValue v(UniValue::VSTR, "foo"); + v.clear(); + BOOST_CHECK(v.isNull()); + BOOST_CHECK_EQUAL(v.getValStr(), ""); + + BOOST_CHECK(v.setObject()); + BOOST_CHECK(v.isObject()); + BOOST_CHECK_EQUAL(v.size(), 0); + BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); + BOOST_CHECK(v.empty()); + + BOOST_CHECK(v.setArray()); + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 0); + + BOOST_CHECK(v.setStr("zum")); + BOOST_CHECK(v.isStr()); + BOOST_CHECK_EQUAL(v.getValStr(), "zum"); + + BOOST_CHECK(v.setFloat(-1.01)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); + + BOOST_CHECK(v.setInt((int)1023)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setInt((int64_t)-1023LL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1023"); + + BOOST_CHECK(v.setInt((uint64_t)1023ULL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setNumStr("-688")); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-688"); + + BOOST_CHECK(v.setBool(false)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), false); + BOOST_CHECK_EQUAL(v.isFalse(), true); + BOOST_CHECK_EQUAL(v.getBool(), false); + + BOOST_CHECK(v.setBool(true)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), true); + BOOST_CHECK_EQUAL(v.isFalse(), false); + BOOST_CHECK_EQUAL(v.getBool(), true); + + BOOST_CHECK(!v.setNumStr("zombocom")); + + BOOST_CHECK(v.setNull()); + BOOST_CHECK(v.isNull()); +} + +BOOST_AUTO_TEST_CASE(univalue_array) +{ + UniValue arr(UniValue::VARR); + + UniValue v((int64_t)1023LL); + BOOST_CHECK(arr.push_back(v)); + + std::string vStr("zippy"); + BOOST_CHECK(arr.push_back(vStr)); + + const char *s = "pippy"; + BOOST_CHECK(arr.push_back(s)); + + std::vector vec; + v.setStr("boing"); + vec.push_back(v); + + v.setStr("going"); + vec.push_back(v); + + BOOST_CHECK(arr.push_backV(vec)); + + BOOST_CHECK(arr.push_back((uint64_t) 400ULL)); + BOOST_CHECK(arr.push_back((int64_t) -400LL)); + BOOST_CHECK(arr.push_back((int) -401)); + BOOST_CHECK(arr.push_back(-40.1)); + BOOST_CHECK(arr.push_back(true)); + + BOOST_CHECK_EQUAL(arr.empty(), false); + BOOST_CHECK_EQUAL(arr.size(), 10); + + BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); + BOOST_CHECK_EQUAL(arr[0].getType(), UniValue::VNUM); + BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); + BOOST_CHECK_EQUAL(arr[1].getType(), UniValue::VSTR); + BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); + BOOST_CHECK_EQUAL(arr[2].getType(), UniValue::VSTR); + BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); + BOOST_CHECK_EQUAL(arr[3].getType(), UniValue::VSTR); + BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); + BOOST_CHECK_EQUAL(arr[4].getType(), UniValue::VSTR); + BOOST_CHECK_EQUAL(arr[5].getValStr(), "400"); + BOOST_CHECK_EQUAL(arr[5].getType(), UniValue::VNUM); + BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400"); + BOOST_CHECK_EQUAL(arr[6].getType(), UniValue::VNUM); + BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401"); + BOOST_CHECK_EQUAL(arr[7].getType(), UniValue::VNUM); + BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1"); + BOOST_CHECK_EQUAL(arr[8].getType(), UniValue::VNUM); + BOOST_CHECK_EQUAL(arr[9].getValStr(), "1"); + BOOST_CHECK_EQUAL(arr[9].getType(), UniValue::VBOOL); + + BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); + + arr.clear(); + BOOST_CHECK(arr.empty()); + BOOST_CHECK_EQUAL(arr.size(), 0); +} + +BOOST_AUTO_TEST_CASE(univalue_object) +{ + UniValue obj(UniValue::VOBJ); + std::string strKey, strVal; + UniValue v; + + strKey = "age"; + v.setInt(100); + BOOST_CHECK(obj.pushKV(strKey, v)); + + strKey = "first"; + strVal = "John"; + BOOST_CHECK(obj.pushKV(strKey, strVal)); + + strKey = "last"; + const char *cVal = "Smith"; + BOOST_CHECK(obj.pushKV(strKey, cVal)); + + strKey = "distance"; + BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25)); + + strKey = "time"; + BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600)); + + strKey = "calories"; + BOOST_CHECK(obj.pushKV(strKey, (int) 12)); + + strKey = "temperature"; + BOOST_CHECK(obj.pushKV(strKey, (double) 90.012)); + + strKey = "moon"; + BOOST_CHECK(obj.pushKV(strKey, true)); + + strKey = "spoon"; + BOOST_CHECK(obj.pushKV(strKey, false)); + + UniValue obj2(UniValue::VOBJ); + BOOST_CHECK(obj2.pushKV("cat1", 9000)); + BOOST_CHECK(obj2.pushKV("cat2", 12345)); + + BOOST_CHECK(obj.pushKVs(obj2)); + + BOOST_CHECK_EQUAL(obj.empty(), false); + BOOST_CHECK_EQUAL(obj.size(), 11); + + BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100"); + BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John"); + BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith"); + BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25"); + BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600"); + BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12"); + BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012"); + BOOST_CHECK_EQUAL(obj["moon"].getValStr(), "1"); + BOOST_CHECK_EQUAL(obj["spoon"].getValStr(), ""); + BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000"); + BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345"); + + BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), ""); + + BOOST_CHECK(obj.exists("age")); + BOOST_CHECK(obj.exists("first")); + BOOST_CHECK(obj.exists("last")); + BOOST_CHECK(obj.exists("distance")); + BOOST_CHECK(obj.exists("time")); + BOOST_CHECK(obj.exists("calories")); + BOOST_CHECK(obj.exists("temperature")); + BOOST_CHECK(obj.exists("moon")); + BOOST_CHECK(obj.exists("spoon")); + BOOST_CHECK(obj.exists("cat1")); + BOOST_CHECK(obj.exists("cat2")); + + BOOST_CHECK(!obj.exists("nyuknyuknyuk")); + + std::map objTypes; + objTypes["age"] = UniValue::VNUM; + objTypes["first"] = UniValue::VSTR; + objTypes["last"] = UniValue::VSTR; + objTypes["distance"] = UniValue::VNUM; + objTypes["time"] = UniValue::VNUM; + objTypes["calories"] = UniValue::VNUM; + objTypes["temperature"] = UniValue::VNUM; + objTypes["moon"] = UniValue::VBOOL; + objTypes["spoon"] = UniValue::VBOOL; + objTypes["cat1"] = UniValue::VNUM; + objTypes["cat2"] = UniValue::VNUM; + BOOST_CHECK(obj.checkObject(objTypes)); + + objTypes["cat2"] = UniValue::VSTR; + BOOST_CHECK(!obj.checkObject(objTypes)); + + obj.clear(); + BOOST_CHECK(obj.empty()); + BOOST_CHECK_EQUAL(obj.size(), 0); + BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL); + + BOOST_CHECK_EQUAL(obj.setObject(), true); + UniValue uv; + uv.setInt(42); + obj.__pushKV("age", uv); + BOOST_CHECK_EQUAL(obj.size(), 1); + BOOST_CHECK_EQUAL(obj["age"].getValStr(), "42"); + + uv.setInt(43); + obj.pushKV("age", uv); + BOOST_CHECK_EQUAL(obj.size(), 1); + BOOST_CHECK_EQUAL(obj["age"].getValStr(), "43"); + + obj.pushKV("name", "foo bar"); + + std::map kv; + obj.getObjMap(kv); + BOOST_CHECK_EQUAL(kv["age"].getValStr(), "43"); + BOOST_CHECK_EQUAL(kv["name"].getValStr(), "foo bar"); + +} + +static const char *json1 = +"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]"; + +BOOST_AUTO_TEST_CASE(univalue_readwrite) +{ + UniValue v; + BOOST_CHECK(v.read(json1)); + + std::string strJson1(json1); + BOOST_CHECK(v.read(strJson1)); + + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 2); + + BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000"); + + UniValue obj = v[1]; + BOOST_CHECK(obj.isObject()); + BOOST_CHECK_EQUAL(obj.size(), 3); + + BOOST_CHECK(obj["key1"].isStr()); + std::string correctValue("str"); + correctValue.push_back('\0'); + BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue); + BOOST_CHECK(obj["key2"].isNum()); + BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800"); + BOOST_CHECK(obj["key3"].isObject()); + + BOOST_CHECK_EQUAL(strJson1, v.write()); + + /* Check for (correctly reporting) a parsing error if the initial + JSON construct is followed by more stuff. Note that whitespace + is, of course, exempt. */ + + BOOST_CHECK(v.read(" {}\n ")); + BOOST_CHECK(v.isObject()); + BOOST_CHECK(v.read(" []\n ")); + BOOST_CHECK(v.isArray()); + + BOOST_CHECK(!v.read("@{}")); + BOOST_CHECK(!v.read("{} garbage")); + BOOST_CHECK(!v.read("[]{}")); + BOOST_CHECK(!v.read("{}[]")); + BOOST_CHECK(!v.read("{} 42")); +} + +BOOST_AUTO_TEST_SUITE_END() + +int main (int argc, char *argv[]) +{ + univalue_constructor(); + univalue_typecheck(); + univalue_set(); + univalue_array(); + univalue_object(); + univalue_readwrite(); + return 0; +} + diff --git a/test/pass4.json b/test/pass4.json new file mode 100644 index 000000000000..f5a680b31c6f --- /dev/null +++ b/test/pass4.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] diff --git a/test/round2.json b/test/round2.json new file mode 100644 index 000000000000..b766cccc6889 --- /dev/null +++ b/test/round2.json @@ -0,0 +1 @@ +["a§■ðŽ’ð…¡"] diff --git a/test/round3.json b/test/round3.json new file mode 100644 index 000000000000..7182dc2f9b8e --- /dev/null +++ b/test/round3.json @@ -0,0 +1 @@ +"abcdefghijklmnopqrstuvwxyz" diff --git a/test/round4.json b/test/round4.json new file mode 100644 index 000000000000..7f8f011eb73d --- /dev/null +++ b/test/round4.json @@ -0,0 +1 @@ +7 diff --git a/test/round5.json b/test/round5.json new file mode 100644 index 000000000000..27ba77ddaf61 --- /dev/null +++ b/test/round5.json @@ -0,0 +1 @@ +true diff --git a/test/round6.json b/test/round6.json new file mode 100644 index 000000000000..c508d5366f70 --- /dev/null +++ b/test/round6.json @@ -0,0 +1 @@ +false diff --git a/test/round7.json b/test/round7.json new file mode 100644 index 000000000000..19765bd501b6 --- /dev/null +++ b/test/round7.json @@ -0,0 +1 @@ +null diff --git a/test/test_json.cpp b/test/test_json.cpp new file mode 100644 index 000000000000..2943bae2b15e --- /dev/null +++ b/test/test_json.cpp @@ -0,0 +1,24 @@ +// Test program that can be called by the JSON test suite at +// https://github.com/nst/JSONTestSuite. +// +// It reads JSON input from stdin and exits with code 0 if it can be parsed +// successfully. It also pretty prints the parsed JSON value to stdout. + +#include +#include +#include "univalue.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + UniValue val; + if (val.read(string(istreambuf_iterator(cin), + istreambuf_iterator()))) { + cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl; + return 0; + } else { + cerr << "JSON Parse Error." << endl; + return 1; + } +} diff --git a/test/unitester.cpp b/test/unitester.cpp index 5a052fe92c85..02e1a83c6dff 100644 --- a/test/unitester.cpp +++ b/test/unitester.cpp @@ -1,6 +1,6 @@ // Copyright 2014 BitPay Inc. // Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://opensource.org/licenses/mit-license.php. #include #include @@ -17,11 +17,11 @@ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif -using namespace std; -string srcdir(JSON_TEST_SRC); +std::string srcdir(JSON_TEST_SRC); static bool test_failed = false; #define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } } +#define f_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", __func__); } } static std::string rtrim(std::string s) { @@ -29,9 +29,9 @@ static std::string rtrim(std::string s) return s; } -static void runtest(string filename, const string& jdata) +static void runtest(std::string filename, const std::string& jdata) { - string prefix = filename.substr(0, 4); + std::string prefix = filename.substr(0, 4); bool wantPass = (prefix == "pass") || (prefix == "roun"); bool wantFail = (prefix == "fail"); @@ -55,19 +55,19 @@ static void runtest(string filename, const string& jdata) static void runtest_file(const char *filename_) { - string basename(filename_); - string filename = srcdir + "/" + basename; + std::string basename(filename_); + std::string filename = srcdir + "/" + basename; FILE *f = fopen(filename.c_str(), "r"); - assert(f != NULL); + assert(f != nullptr); - string jdata; + std::string jdata; char buf[4096]; while (!feof(f)) { int bread = fread(buf, 1, sizeof(buf), f); assert(!ferror(f)); - string s(buf, bread); + std::string s(buf, bread); jdata += s; } @@ -108,6 +108,13 @@ static const char *filenames[] = { "fail35.json", "fail36.json", "fail37.json", + "fail38.json", // invalid unicode: only first half of surrogate pair + "fail39.json", // invalid unicode: only second half of surrogate pair + "fail40.json", // invalid unicode: broken UTF-8 + "fail41.json", // invalid unicode: unfinished UTF-8 + "fail42.json", // valid json with garbage following a nul byte + "fail44.json", // unterminated string + "fail45.json", // nested beyond max depth "fail3.json", "fail4.json", // extra comma "fail5.json", @@ -118,15 +125,47 @@ static const char *filenames[] = { "pass1.json", "pass2.json", "pass3.json", + "pass4.json", "round1.json", // round-trip test + "round2.json", // unicode + "round3.json", // bare string + "round4.json", // bare number + "round5.json", // bare true + "round6.json", // bare false + "round7.json", // bare null }; +// Test \u handling +void unescape_unicode_test() +{ + UniValue val; + bool testResult; + // Escaped ASCII (quote) + testResult = val.read("[\"\\u0022\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\""); + // Escaped Basic Plane character, two-byte UTF-8 + testResult = val.read("[\"\\u0191\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xc6\x91"); + // Escaped Basic Plane character, three-byte UTF-8 + testResult = val.read("[\"\\u2191\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xe2\x86\x91"); + // Escaped Supplementary Plane character U+1d161 + testResult = val.read("[\"\\ud834\\udd61\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xf0\x9d\x85\xa1"); +} + int main (int argc, char *argv[]) { for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { runtest_file(filenames[fidx]); } + unescape_unicode_test(); + return test_failed ? 1 : 0; } From b07e5506e8bc2dec275e283f50c2661f5ec4d216 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 04:30:09 +0000 Subject: [PATCH 03/19] merge bitcoin#25153: Use getInt over get_int/get_int64 --- src/bitcoin-cli.cpp | 32 +++++++++++----------- src/bitcoin-tx.cpp | 2 +- src/governance/classes.cpp | 4 +-- src/governance/governance.cpp | 4 +-- src/governance/object.cpp | 2 +- src/governance/validators.cpp | 2 +- src/httprpc.cpp | 2 +- src/net_types.cpp | 8 +++--- src/node/interfaces.cpp | 2 +- src/qt/governancelist.cpp | 4 +-- src/qt/rpcconsole.cpp | 2 +- src/rpc/blockchain.cpp | 46 ++++++++++++++++---------------- src/rpc/governance.cpp | 6 ++--- src/rpc/mining.cpp | 12 ++++----- src/rpc/net.cpp | 10 +++---- src/rpc/node.cpp | 18 ++++++------- src/rpc/output_script.cpp | 2 +- src/rpc/quorums.cpp | 6 ++--- src/rpc/rawtransaction.cpp | 6 ++--- src/rpc/rawtransaction_util.cpp | 8 +++--- src/rpc/request.cpp | 2 +- src/rpc/server.cpp | 2 +- src/rpc/util.cpp | 10 +++---- src/test/blockfilter_tests.cpp | 2 +- src/test/rpc_tests.cpp | 30 ++++++++++----------- src/test/sighash_tests.cpp | 4 +-- src/test/transaction_tests.cpp | 4 +-- src/util/settings.h | 2 +- src/util/system.cpp | 2 +- src/wallet/rpc/addresses.cpp | 6 ++--- src/wallet/rpc/backup.cpp | 6 ++--- src/wallet/rpc/coins.cpp | 14 +++++----- src/wallet/rpc/encrypt.cpp | 2 +- src/wallet/rpc/spend.cpp | 4 +-- src/wallet/rpc/transactions.cpp | 12 ++++----- src/wallet/rpc/wallet.cpp | 6 ++--- src/wallet/test/wallet_tests.cpp | 2 +- 37 files changed, 144 insertions(+), 144 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 75f9c69f434d..d55a4083f92e 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -483,7 +483,7 @@ class NetinfoRequestHandler : public BaseRequestHandler if (!batch[ID_NETWORKINFO]["error"].isNull()) return batch[ID_NETWORKINFO]; const UniValue& networkinfo{batch[ID_NETWORKINFO]["result"]}; - if (networkinfo["version"].get_int() < 200000) { + if (networkinfo["version"].getInt() < 200000) { throw std::runtime_error("-netinfo requires dashd server to be running v20.0 and up"); } const int64_t time_now{TicksSinceEpoch(CliClock::now())}; @@ -504,16 +504,16 @@ class NetinfoRequestHandler : public BaseRequestHandler if (conn_type == "manual") ++m_manual_peers_count; if (DetailsRequested()) { // Push data for this peer to the peers vector. - const int peer_id{peer["id"].get_int()}; - const int mapped_as{peer["mapped_as"].isNull() ? 0 : peer["mapped_as"].get_int()}; - const int version{peer["version"].get_int()}; - const int64_t addr_processed{peer["addr_processed"].isNull() ? 0 : peer["addr_processed"].get_int64()}; - const int64_t addr_rate_limited{peer["addr_rate_limited"].isNull() ? 0 : peer["addr_rate_limited"].get_int64()}; - const int64_t conn_time{peer["conntime"].get_int64()}; - const int64_t last_blck{peer["last_block"].get_int64()}; - const int64_t last_recv{peer["lastrecv"].get_int64()}; - const int64_t last_send{peer["lastsend"].get_int64()}; - const int64_t last_trxn{peer["last_transaction"].get_int64()}; + const int peer_id{peer["id"].getInt()}; + const int mapped_as{peer["mapped_as"].isNull() ? 0 : peer["mapped_as"].getInt()}; + const int version{peer["version"].getInt()}; + const int64_t addr_processed{peer["addr_processed"].isNull() ? 0 : peer["addr_processed"].getInt()}; + const int64_t addr_rate_limited{peer["addr_rate_limited"].isNull() ? 0 : peer["addr_rate_limited"].getInt()}; + const int64_t conn_time{peer["conntime"].getInt()}; + const int64_t last_blck{peer["last_block"].getInt()}; + const int64_t last_recv{peer["lastrecv"].getInt()}; + const int64_t last_send{peer["lastsend"].getInt()}; + const int64_t last_trxn{peer["last_transaction"].getInt()}; const double min_ping{peer["minping"].isNull() ? -1 : peer["minping"].get_real()}; const double ping{peer["pingtime"].isNull() ? -1 : peer["pingtime"].get_real()}; const std::string addr{peer["addr"].get_str()}; @@ -534,7 +534,7 @@ class NetinfoRequestHandler : public BaseRequestHandler } // Generate report header. - std::string result{strprintf("%s client %s%s - server %i%s\n\n", PACKAGE_NAME, FormatFullVersion(), ChainToString(), networkinfo["protocolversion"].get_int(), networkinfo["subversion"].get_str())}; + std::string result{strprintf("%s client %s%s - server %i%s\n\n", PACKAGE_NAME, FormatFullVersion(), ChainToString(), networkinfo["protocolversion"].getInt(), networkinfo["subversion"].get_str())}; // Report detailed peer connections list sorted by direction and minimum ping time. if (DetailsRequested() && !m_peers.empty()) { @@ -623,7 +623,7 @@ class NetinfoRequestHandler : public BaseRequestHandler max_addr_size = std::max(addr["address"].get_str().length() + 1, max_addr_size); } for (const UniValue& addr : local_addrs) { - result += strprintf("\n%-*s port %6i score %6i", max_addr_size, addr["address"].get_str(), addr["port"].get_int(), addr["score"].get_int()); + result += strprintf("\n%-*s port %6i score %6i", max_addr_size, addr["address"].get_str(), addr["port"].getInt(), addr["score"].getInt()); } } @@ -877,7 +877,7 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str response = CallRPC(rh, strMethod, args, rpcwallet); if (fWait) { const UniValue& error = find_value(response, "error"); - if (!error.isNull() && error["code"].get_int() == RPC_IN_WARMUP) { + if (!error.isNull() && error["code"].getInt() == RPC_IN_WARMUP) { throw CConnectionFailed("server in warmup"); } } @@ -912,13 +912,13 @@ static void ParseError(const UniValue& error, std::string& strPrint, int& nRet) if (err_msg.isStr()) { strPrint += ("error message:\n" + err_msg.get_str()); } - if (err_code.isNum() && err_code.get_int() == RPC_WALLET_NOT_SPECIFIED) { + if (err_code.isNum() && err_code.getInt() == RPC_WALLET_NOT_SPECIFIED) { strPrint += "\nTry adding \"-rpcwallet=\" option to dash-cli command line."; } } else { strPrint = "error: " + error.write(); } - nRet = abs(error["code"].get_int()); + nRet = abs(error["code"].getInt()); } /** diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 93e70ed89359..e140a55617cf 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -569,7 +569,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')"); } - const int nOut = prevOut["vout"].get_int(); + const int nOut = prevOut["vout"].getInt(); if (nOut < 0) throw std::runtime_error("vout cannot be negative"); diff --git a/src/governance/classes.cpp b/src/governance/classes.cpp index 62be337be3d1..03b3c4d6ceca 100644 --- a/src/governance/classes.cpp +++ b/src/governance/classes.cpp @@ -88,12 +88,12 @@ CSuperblock::CSuperblock(const CGovernanceObject& govObj, uint256& nHash) : UniValue obj = govObj.GetJSONObject(); - if (obj["type"].get_int() != ToUnderlying(GovernanceObject::TRIGGER)) { + if (obj["type"].getInt() != ToUnderlying(GovernanceObject::TRIGGER)) { throw std::runtime_error("CSuperblock: invalid data type"); } // FIRST WE GET THE START HEIGHT, THE BLOCK HEIGHT AT WHICH THE PAYMENT SHALL OCCUR - nBlockHeight = obj["event_block_height"].get_int(); + nBlockHeight = obj["event_block_height"].getInt(); // NEXT WE GET THE PAYMENT INFORMATION AND RECONSTRUCT THE PAYMENT VECTOR std::string strAddresses = obj["payment_addresses"].get_str(); diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index d2ca46cffd74..88804db50912 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -659,8 +659,8 @@ std::optional CGovernanceManager::CreateSuperblockCandidate(i // Skip proposals that are too expensive if (budgetAllocated + payment.nAmount > governanceBudget) continue; - int64_t windowStart = jproposal["start_epoch"].get_int64() - GOVERNANCE_FUDGE_WINDOW; - int64_t windowEnd = jproposal["end_epoch"].get_int64() + GOVERNANCE_FUDGE_WINDOW; + int64_t windowStart = jproposal["start_epoch"].getInt() - GOVERNANCE_FUDGE_WINDOW; + int64_t windowEnd = jproposal["end_epoch"].getInt() + GOVERNANCE_FUDGE_WINDOW; // Skip proposals if the SB isn't within the proposal time window if (SBEpochTime < windowStart) { diff --git a/src/governance/object.cpp b/src/governance/object.cpp index 839d7d118f3c..41268bb8adbf 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -312,7 +312,7 @@ void CGovernanceObject::LoadData() GetData(objResult); LogPrint(BCLog::GOBJECT, "CGovernanceObject::LoadData -- GetDataAsPlainString = %s\n", GetDataAsPlainString()); UniValue obj = GetJSONObject(); - m_obj.type = GovernanceObject(obj["type"].get_int()); + m_obj.type = GovernanceObject(obj["type"].getInt()); } catch (std::exception& e) { fUnparsable = true; LogPrintf("%s\n", strprintf("CGovernanceObject::LoadData -- Error parsing JSON, e.what() = %s", e.what())); diff --git a/src/governance/validators.cpp b/src/governance/validators.cpp index 6b5cc640582d..bbe10d90439d 100644 --- a/src/governance/validators.cpp +++ b/src/governance/validators.cpp @@ -268,7 +268,7 @@ bool CProposalValidator::GetDataValue(const std::string& strKey, int64_t& nValue const UniValue uValue = objJSON[strKey]; switch (uValue.getType()) { case UniValue::VNUM: - nValueRet = uValue.get_int64(); + nValueRet = uValue.getInt(); fOK = true; break; default: diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 42ce94c3190c..8ba570062a55 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -116,7 +116,7 @@ static bool JSONErrorReply(RpcHttpRequest& rpcRequest, const UniValue& objError, { // Send error reply from json-rpc error object int nStatus = HTTP_INTERNAL_SERVER_ERROR; - int code = find_value(objError, "code").get_int(); + int code = find_value(objError, "code").getInt(); if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; diff --git a/src/net_types.cpp b/src/net_types.cpp index cdde5221fc77..9407ff8e68ba 100644 --- a/src/net_types.cpp +++ b/src/net_types.cpp @@ -12,9 +12,9 @@ static const char* BANMAN_JSON_VERSION_KEY{"version"}; CBanEntry::CBanEntry(const UniValue& json) - : nVersion(json[BANMAN_JSON_VERSION_KEY].get_int()), - nCreateTime(json["ban_created"].get_int64()), - nBanUntil(json["banned_until"].get_int64()) + : nVersion(json[BANMAN_JSON_VERSION_KEY].getInt()), + nCreateTime(json["ban_created"].getInt()), + nBanUntil(json["banned_until"].getInt()) { } @@ -58,7 +58,7 @@ UniValue BanMapToJson(const banmap_t& bans) void BanMapFromJson(const UniValue& bans_json, banmap_t& bans) { for (const auto& ban_entry_json : bans_json.getValues()) { - const int version{ban_entry_json[BANMAN_JSON_VERSION_KEY].get_int()}; + const int version{ban_entry_json[BANMAN_JSON_VERSION_KEY].getInt()}; if (version != CBanEntry::CURRENT_VERSION) { LogPrintf("Dropping entry with unknown version (%s) from ban list\n", version); continue; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index b9b96e18082c..493c8606c86c 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -698,7 +698,7 @@ class RpcHandlerImpl : public Handler // try to handle the request. Otherwise, reraise the exception. if (!last_handler) { const UniValue& code = e["code"]; - if (code.isNum() && code.get_int() == RPC_WALLET_NOT_FOUND) { + if (code.isNum() && code.getInt() == RPC_WALLET_NOT_FOUND) { return false; } } diff --git a/src/qt/governancelist.cpp b/src/qt/governancelist.cpp index 157690e24733..2aa54a3ea88f 100644 --- a/src/qt/governancelist.cpp +++ b/src/qt/governancelist.cpp @@ -50,11 +50,11 @@ Proposal::Proposal(ClientModel* _clientModel, const CGovernanceObject& _govObj, } if (UniValue paymentStartValue = find_value(prop_data, "start_epoch"); paymentStartValue.isNum()) { - m_startDate = QDateTime::fromSecsSinceEpoch(paymentStartValue.get_int64()); + m_startDate = QDateTime::fromSecsSinceEpoch(paymentStartValue.getInt()); } if (UniValue paymentEndValue = find_value(prop_data, "end_epoch"); paymentEndValue.isNum()) { - m_endDate = QDateTime::fromSecsSinceEpoch(paymentEndValue.get_int64()); + m_endDate = QDateTime::fromSecsSinceEpoch(paymentEndValue.getInt()); } if (UniValue amountValue = find_value(prop_data, "payment_amount"); amountValue.isNum()) { diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index a44190ff71b1..fe0357c1ab25 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -460,7 +460,7 @@ void RPCExecutor::request(const QString &command, const WalletModel* wallet_mode { try // Nice formatting for standard-format error { - int code = find_value(objError, "code").get_int(); + int code = find_value(objError, "code").getInt(); std::string message = find_value(objError, "message").get_str(); Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index dd08f585103b..d8e0a0802d37 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -108,7 +108,7 @@ static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateMan CChain& active_chain = chainman.ActiveChain(); if (param.isNum()) { - const int height{param.get_int()}; + const int height{param.getInt()}; if (height < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height)); } @@ -326,7 +326,7 @@ static RPCHelpMan waitfornewblock() { int timeout = 0; if (!request.params[0].isNull()) - timeout = request.params[0].get_int(); + timeout = request.params[0].getInt(); CUpdatedBlock block; { @@ -372,7 +372,7 @@ static RPCHelpMan waitforblock() uint256 hash(ParseHashV(request.params[0], "blockhash")); if (!request.params[1].isNull()) - timeout = request.params[1].get_int(); + timeout = request.params[1].getInt(); CUpdatedBlock block; { @@ -416,10 +416,10 @@ static RPCHelpMan waitforblockheight() { int timeout = 0; - int height = request.params[0].get_int(); + int height = request.params[0].getInt(); if (!request.params[1].isNull()) - timeout = request.params[1].get_int(); + timeout = request.params[1].getInt(); CUpdatedBlock block; { @@ -506,7 +506,7 @@ static RPCHelpMan getblockfrompeer() PeerManager& peerman = EnsurePeerman(node); const uint256& block_hash{ParseHashV(request.params[0], "blockhash")}; - const NodeId peer_id{request.params[1].get_int64()}; + const NodeId peer_id{request.params[1].getInt()}; const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash);); @@ -543,8 +543,8 @@ static RPCHelpMan getblockhashes() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - unsigned int high = request.params[0].get_int(); - unsigned int low = request.params[1].get_int(); + unsigned int high = request.params[0].getInt(); + unsigned int low = request.params[1].getInt(); std::vector blockHashes; ChainstateManager& chainman = EnsureAnyChainman(request.context); @@ -581,7 +581,7 @@ static RPCHelpMan getblockhash() LOCK(cs_main); const CChain& active_chain = chainman.ActiveChain(); - int nHeight = request.params[0].get_int(); + int nHeight = request.params[0].getInt(); if (nHeight < 0 || nHeight > active_chain.Height()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); @@ -732,7 +732,7 @@ static RPCHelpMan getblockheaders() int nCount = MAX_HEADERS_UNCOMPRESSED_RESULT; if (!request.params[1].isNull()) - nCount = request.params[1].get_int(); + nCount = request.params[1].getInt(); if (nCount <= 0 || nCount > (int)MAX_HEADERS_UNCOMPRESSED_RESULT) throw JSONRPCError(RPC_INVALID_PARAMETER, "Count is out of range"); @@ -849,7 +849,7 @@ static RPCHelpMan getmerkleblocks() int nCount = MAX_HEADERS_UNCOMPRESSED_RESULT; if (!request.params[2].isNull()) - nCount = request.params[2].get_int(); + nCount = request.params[2].getInt(); if (nCount <= 0 || nCount > (int)MAX_HEADERS_UNCOMPRESSED_RESULT) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Count is out of range"); @@ -988,7 +988,7 @@ static RPCHelpMan getblock() if (request.params[1].isBool()) { verbosity = request.params[1].get_bool() ? 1 : 0; } else { - verbosity = request.params[1].get_int(); + verbosity = request.params[1].getInt(); } } @@ -1055,7 +1055,7 @@ static RPCHelpMan pruneblockchain() CChainState& active_chainstate = chainman.ActiveChainstate(); CChain& active_chain = active_chainstate.m_chain; - int heightParam = request.params[0].get_int(); + int heightParam = request.params[0].getInt(); if (heightParam < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height."); } @@ -1294,7 +1294,7 @@ static RPCHelpMan gettxout() UniValue ret(UniValue::VOBJ); uint256 hash(ParseHashV(request.params[0], "txid")); - int n = request.params[1].get_int(); + int n = request.params[1].getInt(); COutPoint out(hash, n); bool fMempool = true; if (!request.params[2].isNull()) @@ -1351,8 +1351,8 @@ static RPCHelpMan verifychain() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int()}; - const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()}; + const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].getInt()}; + const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].getInt()}; const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -1650,8 +1650,8 @@ static RPCHelpMan getchaintips() // Always report the currently active tip. setTips.insert(active_chain.Tip()); - int nCountMax{request.params[0].isNull() ? INT_MAX : request.params[0].get_int()}; - const int nBranchMin{request.params[1].isNull() ? -1: request.params[1].get_int()}; + int nCountMax{request.params[0].isNull() ? INT_MAX : request.params[0].getInt()}; + const int nBranchMin{request.params[1].isNull() ? -1: request.params[1].getInt()}; /* Construct the output array. */ UniValue res(UniValue::VARR); @@ -1883,7 +1883,7 @@ static RPCHelpMan getchaintxstats() if (request.params[0].isNull()) { blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1)); } else { - blockcount = request.params[0].get_int(); + blockcount = request.params[0].getInt(); if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1"); @@ -2252,26 +2252,26 @@ static RPCHelpMan getspecialtxes() int nTxType = -1; if (!request.params[1].isNull()) { - nTxType = request.params[1].get_int(); + nTxType = request.params[1].getInt(); } int nCount = 10; if (!request.params[2].isNull()) { - nCount = request.params[2].get_int(); + nCount = request.params[2].getInt(); if (nCount < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); } int nSkip = 0; if (!request.params[3].isNull()) { - nSkip = request.params[3].get_int(); + nSkip = request.params[3].getInt(); if (nSkip < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative skip"); } int nVerbosity = 0; if (!request.params[4].isNull()) { - nVerbosity = request.params[4].get_int(); + nVerbosity = request.params[4].getInt(); if (nVerbosity < 0 || nVerbosity > 2) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbosity must be in range 0..2"); } diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index ec2fa75a0f95..27b147c21e77 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -908,7 +908,7 @@ static RPCHelpMan voteraw() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { uint256 hashMnCollateralTx(ParseHashV(request.params[0], "mn collateral tx hash")); - int nMnCollateralTxIndex = request.params[1].get_int(); + int nMnCollateralTxIndex = request.params[1].getInt(); COutPoint outpoint = COutPoint(hashMnCollateralTx, nMnCollateralTxIndex); uint256 hashGovObj(ParseHashV(request.params[2], "Governance hash")); @@ -939,7 +939,7 @@ static RPCHelpMan voteraw() }(); - int64_t nTime = request.params[5].get_int64(); + int64_t nTime = request.params[5].getInt(); std::string strSig = request.params[6].get_str(); auto opt_vchSig = DecodeBase64(strSig); @@ -1042,7 +1042,7 @@ static RPCHelpMan getsuperblockbudget() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - int nBlockHeight = request.params[0].get_int(); + int nBlockHeight = request.params[0].getInt(); if (nBlockHeight < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 5f498d654cb0..bc40a7a99f54 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -120,7 +120,7 @@ static RPCHelpMan getnetworkhashps() ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1, chainman.ActiveChain()); + return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].getInt() : 120, !request.params[1].isNull() ? request.params[1].getInt() : -1, chainman.ActiveChain()); }, }; } @@ -232,8 +232,8 @@ static RPCHelpMan generatetodescriptor() "\nGenerate 11 blocks to mydesc\n" + HelpExampleCli("generatetodescriptor", "11 \"mydesc\"")}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const int num_blocks{request.params[0].get_int()}; - const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()}; + const int num_blocks{request.params[0].getInt()}; + const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].getInt()}; CScript coinbase_script; std::string error; @@ -271,8 +271,8 @@ static RPCHelpMan generatetoaddress() + HelpExampleCli("getnewaddress", "")}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const int num_blocks{request.params[0].get_int()}; - const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()}; + const int num_blocks{request.params[0].getInt()}; + const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].getInt()}; CTxDestination destination = DecodeDestination(request.params[1].get_str()); if (!IsValidDestination(destination)) { @@ -503,7 +503,7 @@ static RPCHelpMan prioritisetransaction() LOCK(cs_main); uint256 hash(ParseHashV(request.params[0].get_str(), "txid")); - CAmount nAmount = request.params[1].get_int64(); + CAmount nAmount = request.params[1].getInt(); EnsureAnyMemPool(request.context).PrioritiseTransaction(hash, nAmount); return true; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 95cdfdf6cb11..b92e2b74c755 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -450,7 +450,7 @@ static RPCHelpMan disconnectnode() success = connman.DisconnectNode(address_arg.get_str()); } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) { /* handle disconnect-by-id */ - NodeId nodeid = (NodeId) id_arg.get_int64(); + NodeId nodeid = (NodeId) id_arg.getInt(); success = connman.DisconnectNode(nodeid); } else { throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided."); @@ -772,7 +772,7 @@ static RPCHelpMan setban() int64_t banTime = 0; //use standard bantime if not specified if (!request.params[2].isNull()) - banTime = request.params[2].get_int64(); + banTime = request.params[2].getInt(); bool absolute = false; if (request.params[3].isTrue()) @@ -957,7 +957,7 @@ static RPCHelpMan getnodeaddresses() const NodeContext& node = EnsureAnyNodeContext(request.context); const CConnman& connman = EnsureConnman(node); - const int count{request.params[0].isNull() ? 1 : request.params[0].get_int()}; + const int count{request.params[0].isNull() ? 1 : request.params[0].getInt()}; if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range"); const std::optional network{request.params[1].isNull() ? std::nullopt : std::optional{ParseNetwork(request.params[1].get_str())}}; @@ -1011,7 +1011,7 @@ static RPCHelpMan addpeeraddress() } const std::string& addr_string{request.params[0].get_str()}; - const uint16_t port = request.params[1].get_int(); + const uint16_t port = request.params[1].getInt(); const bool tried{request.params[2].isTrue()}; UniValue obj(UniValue::VOBJ); @@ -1055,7 +1055,7 @@ static RPCHelpMan sendmsgtopeer() RPCExamples{ HelpExampleCli("sendmsgtopeer", "0 \"addr\" \"ffffff\"") + HelpExampleRpc("sendmsgtopeer", "0 \"addr\" \"ffffff\"")}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const NodeId peer_id{request.params[0].get_int()}; + const NodeId peer_id{request.params[0].getInt()}; const std::string& msg_type{request.params[1].get_str()}; if (msg_type.size() > CMessageHeader::COMMAND_SIZE) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Error: msg_type too long, max length is %i", CMessageHeader::COMMAND_SIZE)); diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index 10d76dc99efb..f8828f11550e 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -224,7 +224,7 @@ static RPCHelpMan sporkupdate() CHECK_NONFATAL(node.sporkman); // SPORK VALUE - int64_t nValue = request.params[1].get_int64(); + int64_t nValue = request.params[1].getInt(); // broadcast new spork if (node.sporkman->UpdateSpork(peerman, nSporkID, nValue)) { @@ -261,7 +261,7 @@ static RPCHelpMan setmocktime() LOCK(cs_main); RPCTypeCheck(request.params, {UniValue::VNUM}); - const int64_t time{request.params[0].get_int64()}; + const int64_t time{request.params[0].getInt()}; if (time < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime cannot be negative: %s.", time)); } @@ -296,7 +296,7 @@ static RPCHelpMan mnauth() if (!Params().MineBlocksOnDemand()) throw std::runtime_error("mnauth for regression testing (-regtest mode) only"); - int64_t nodeId = request.params[0].get_int64(); + int64_t nodeId = request.params[0].getInt(); uint256 proTxHash = ParseHashV(request.params[1], "proTxHash"); if (proTxHash.IsNull()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "proTxHash invalid"); @@ -558,8 +558,8 @@ static RPCHelpMan getaddressdeltas() int end = 0; if (startValue.isNum() && endValue.isNum()) { - start = startValue.get_int(); - end = endValue.get_int(); + start = startValue.getInt(); + end = endValue.getInt(); if (end < start) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "End value is expected to be greater than start"); } @@ -718,8 +718,8 @@ static RPCHelpMan getaddresstxids() UniValue startValue = find_value(request.params[0].get_obj(), "start"); UniValue endValue = find_value(request.params[0].get_obj(), "end"); if (startValue.isNum() && endValue.isNum()) { - start = startValue.get_int(); - end = endValue.get_int(); + start = startValue.getInt(); + end = endValue.getInt(); } } @@ -797,7 +797,7 @@ static RPCHelpMan getspentinfo() } uint256 txid = ParseHashV(txidValue, "txid"); - int outputIndex = indexValue.get_int(); + int outputIndex = indexValue.getInt(); CSpentIndexKey key(txid, outputIndex); CSpentIndexValue value; @@ -835,7 +835,7 @@ static RPCHelpMan mockscheduler() // check params are valid values RPCTypeCheck(request.params, {UniValue::VNUM}); - int64_t delta_seconds = request.params[0].get_int64(); + int64_t delta_seconds = request.params[0].getInt(); if (delta_seconds <= 0 || delta_seconds > 3600) { throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)"); } diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp index f6e87278c59f..2e238ecfbab9 100644 --- a/src/rpc/output_script.cpp +++ b/src/rpc/output_script.cpp @@ -105,7 +105,7 @@ static RPCHelpMan createmultisig() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - int required = request.params[0].get_int(); + int required = request.params[0].getInt(); // Get the public keys const UniValue& keys = request.params[1].get_array(); diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index c8bfd6cd0128..2f512f46ed9a 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -997,7 +997,7 @@ static RPCHelpMan verifychainlock() } nBlockHeight = pIndex->nHeight; } else { - nBlockHeight = request.params[2].get_int(); + nBlockHeight = request.params[2].getInt(); LOCK(cs_main); if (nBlockHeight < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); @@ -1063,7 +1063,7 @@ static RPCHelpMan verifyislock() int maxHeight{-1}; if (!request.params[3].isNull()) { - maxHeight = request.params[3].get_int(); + maxHeight = request.params[3].getInt(); } int signHeight; @@ -1118,7 +1118,7 @@ static RPCHelpMan submitchainlock() { const uint256 nBlockHash(ParseHashV(request.params[0], "blockHash")); - const int nBlockHeight = request.params[2].get_int(); + const int nBlockHeight = request.params[2].getInt(); if (nBlockHeight <= 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid block height"); } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 0ad984c98faa..dfe73acfead3 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -263,7 +263,7 @@ static RPCHelpMan getrawtransaction() // Accept either a bool (true) or a num (>=1) to indicate verbose output. bool fVerbose = false; if (!request.params[1].isNull()) { - fVerbose = request.params[1].isNum() ? (request.params[1].get_int() != 0) : request.params[1].get_bool(); + fVerbose = request.params[1].isNum() ? (request.params[1].getInt() != 0) : request.params[1].get_bool(); } if (!request.params[2].isNull()) { @@ -352,7 +352,7 @@ static RPCHelpMan getrawtransactionmulti() { // Accept either a bool (true) or a num (>=1) to indicate verbose output. bool fVerbose{false}; if (!request.params[1].isNull()) { - fVerbose = request.params[1].isNum() ? (request.params[1].get_int() != 0) : request.params[1].get_bool(); + fVerbose = request.params[1].isNum() ? (request.params[1].getInt() != 0) : request.params[1].get_bool(); } const NodeContext& node{EnsureAnyNodeContext(request.context)}; @@ -627,7 +627,7 @@ static RPCHelpMan getassetunlockstatuses() std::optional nSpecificCoreHeight{std::nullopt}; if (!request.params[1].isNull()) { - nSpecificCoreHeight = request.params[1].get_int(); + nSpecificCoreHeight = request.params[1].getInt(); if (nSpecificCoreHeight.value() < 0 || nSpecificCoreHeight.value() > chainman.ActiveChain().Height()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); } diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 1c8ebf834c31..d7aa72eff0ad 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -39,7 +39,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal CMutableTransaction rawTx; if (!locktime.isNull()) { - int64_t nLockTime = locktime.get_int64(); + int64_t nLockTime = locktime.getInt(); if (nLockTime < 0 || nLockTime > LOCKTIME_MAX) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range"); rawTx.nLockTime = nLockTime; @@ -54,7 +54,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal const UniValue& vout_v = find_value(o, "vout"); if (!vout_v.isNum()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); - int nOutput = vout_v.get_int(); + int nOutput = vout_v.getInt(); if (nOutput < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); @@ -68,7 +68,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal // set the sequence number if passed in the parameters object const UniValue& sequenceObj = find_value(o, "sequence"); if (sequenceObj.isNum()) { - int64_t seqNr64 = sequenceObj.get_int64(); + int64_t seqNr64 = sequenceObj.getInt(); if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range"); else @@ -164,7 +164,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst uint256 txid = ParseHashO(prevOut, "txid"); - int nOut = find_value(prevOut, "vout").get_int(); + int nOut = find_value(prevOut, "vout").getInt(); if (nOut < 0) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative"); } diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index 5cdf43468782..586bd5d1cad7 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -146,7 +146,7 @@ std::vector JSONRPCProcessBatchReply(const UniValue& in) if (!rec.isObject()) { throw std::runtime_error("Batch member must be an object"); } - size_t id = rec["id"].get_int(); + size_t id = rec["id"].getInt(); if (id >= num) { throw std::runtime_error("Batch member id is larger than batch size"); } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 79dc6f9e67ca..cbb8d0f93e46 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -194,7 +194,7 @@ static RPCHelpMan stop() // this reply will get back to the client. StartShutdown(); if (jsonRequest.params[0].isNum()) { - UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].get_int()}); + UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].getInt()}); } return RESULT; }, diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 1c11ba793ab6..07cea61ab6b7 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -148,7 +148,7 @@ bool ParseBoolV(const UniValue& v, const std::string &strName) if (v.isBool()) return v.get_bool(); else if (v.isNum()) - strBool = ToString(v.get_int()); + strBool = ToString(v.getInt()); else if (v.isStr()) strBool = v.get_str(); @@ -322,7 +322,7 @@ UniValue DescribeAddress(const CTxDestination& dest) unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target) { - const int target{value.get_int()}; + const int target{value.getInt()}; const unsigned int unsigned_target{static_cast(target)}; if (target < 1 || unsigned_target > max_target) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u and %u", 1, max_target)); @@ -936,11 +936,11 @@ std::string RPCArg::ToString(const bool oneline) const static std::pair ParseRange(const UniValue& value) { if (value.isNum()) { - return {0, value.get_int64()}; + return {0, value.getInt()}; } if (value.isArray() && value.size() == 2 && value[0].isNum() && value[1].isNum()) { - int64_t low = value[0].get_int64(); - int64_t high = value[1].get_int64(); + int64_t low = value[0].getInt(); + int64_t high = value[1].getInt(); if (low > high) throw JSONRPCError(RPC_INVALID_PARAMETER, "Range specified as [begin,end] must not have begin after end"); return {low, high}; } diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp index f9c4f01090b3..3b16f36058ed 100644 --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test) } unsigned int pos = 0; - /*int block_height =*/ test[pos++].get_int(); + /*int block_height =*/ test[pos++].getInt(); uint256 block_hash; BOOST_CHECK(ParseHashStr(test[pos++].get_str(), block_hash)); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index e0c9ee2dc932..ab660dda171c 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -139,9 +139,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams) BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), std::runtime_error); std::string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx)); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0); + BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").getInt(), 193); + BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").getInt(), 1); + BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").getInt(), 0); BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error); // Only check failure cases for sendrawtransaction, there's no network to send to... @@ -161,7 +161,7 @@ BOOST_AUTO_TEST_CASE(rpc_togglenetwork) BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive false")); r = CallRPC("getnetworkinfo"); - int numConnection = find_value(r.get_obj(), "connections").get_int(); + int numConnection = find_value(r.get_obj(), "connections").getInt(); BOOST_CHECK_EQUAL(numConnection, 0); netState = find_value(r.get_obj(), "networkactive").get_bool(); @@ -335,7 +335,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); - int64_t banned_until{find_value(o1, "banned_until").get_int64()}; + int64_t banned_until{find_value(o1, "banned_until").getInt()}; BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); BOOST_CHECK_EQUAL(banned_until, 9907731200); // absolute time check @@ -350,10 +350,10 @@ BOOST_AUTO_TEST_CASE(rpc_ban) ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); - banned_until = find_value(o1, "banned_until").get_int64(); - const int64_t ban_created{find_value(o1, "ban_created").get_int64()}; - const int64_t ban_duration{find_value(o1, "ban_duration").get_int64()}; - const int64_t time_remaining{find_value(o1, "time_remaining").get_int64()}; + banned_until = find_value(o1, "banned_until").getInt(); + const int64_t ban_created{find_value(o1, "ban_created").getInt()}; + const int64_t ban_duration{find_value(o1, "ban_duration").getInt()}; + const int64_t time_remaining{find_value(o1, "time_remaining").getInt()}; BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); BOOST_CHECK_EQUAL(banned_until, time_remaining_expected + now.count()); BOOST_CHECK_EQUAL(ban_duration, banned_until - ban_created); @@ -409,22 +409,22 @@ BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress) UniValue result; BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", {"101", "yhq7ifNCtTKEpY4Yu5XPCcztQco6Fh6JsZ"})); - BOOST_CHECK_EQUAL(result[0].get_int(), 101); + BOOST_CHECK_EQUAL(result[0].getInt(), 101); BOOST_CHECK_EQUAL(result[1].get_str(), "yhq7ifNCtTKEpY4Yu5XPCcztQco6Fh6JsZ"); BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", {"101", "yTretFTpoi3oQ3maZk5QadGaDWPiKnmDBc"})); - BOOST_CHECK_EQUAL(result[0].get_int(), 101); + BOOST_CHECK_EQUAL(result[0].getInt(), 101); BOOST_CHECK_EQUAL(result[1].get_str(), "yTretFTpoi3oQ3maZk5QadGaDWPiKnmDBc"); BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", {"1", "yNbNZyCiTYSFtDwEXt7jChV7tZVYX862ua", "9"})); - BOOST_CHECK_EQUAL(result[0].get_int(), 1); + BOOST_CHECK_EQUAL(result[0].getInt(), 1); BOOST_CHECK_EQUAL(result[1].get_str(), "yNbNZyCiTYSFtDwEXt7jChV7tZVYX862ua"); - BOOST_CHECK_EQUAL(result[2].get_int(), 9); + BOOST_CHECK_EQUAL(result[2].getInt(), 9); BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", {"1", "yTG8jLL3MvteKXgbEcHyaN7JvTPCejQpSh", "9"})); - BOOST_CHECK_EQUAL(result[0].get_int(), 1); + BOOST_CHECK_EQUAL(result[0].getInt(), 1); BOOST_CHECK_EQUAL(result[1].get_str(), "yTG8jLL3MvteKXgbEcHyaN7JvTPCejQpSh"); - BOOST_CHECK_EQUAL(result[2].get_int(), 9); + BOOST_CHECK_EQUAL(result[2].getInt(), 9); } #endif // ENABLE_MINER diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index c5694e79254e..2a62c16c90d4 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -180,8 +180,8 @@ BOOST_AUTO_TEST_CASE(sighash_from_data) // deserialize test data raw_tx = test[0].get_str(); raw_script = test[1].get_str(); - nIn = test[2].get_int(); - nHashType = test[3].get_int(); + nIn = test[2].getInt(); + nHashType = test[3].getInt(); sigHashHex = test[4].get_str(); CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 5db21f086b54..5a61438d9dd0 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) break; } - mapprevOutScriptPubKeys[COutPoint{uint256S(vinput[0].get_str()), uint32_t(vinput[1].get_int())}] = ParseScript(vinput[2].get_str()); + mapprevOutScriptPubKeys[COutPoint{uint256S(vinput[0].get_str()), uint32_t(vinput[1].getInt())}] = ParseScript(vinput[2].get_str()); } if (!fValid) { @@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) break; } - mapprevOutScriptPubKeys[COutPoint{uint256S(vinput[0].get_str()), uint32_t(vinput[1].get_int())}] = ParseScript(vinput[2].get_str()); + mapprevOutScriptPubKeys[COutPoint{uint256S(vinput[0].get_str()), uint32_t(vinput[1].getInt())}] = ParseScript(vinput[2].get_str()); } if (!fValid) { diff --git a/src/util/settings.h b/src/util/settings.h index ed3634923212..261a0a032f5e 100644 --- a/src/util/settings.h +++ b/src/util/settings.h @@ -20,7 +20,7 @@ namespace util { //! @note UniValue is used here for convenience and because it can be easily //! serialized in a readable format. But any other variant type that can //! be assigned strings, int64_t, and bool values and has get_str(), -//! get_int64(), get_bool(), isNum(), isBool(), isFalse(), isTrue() and +//! getInt(), get_bool(), isNum(), isBool(), isFalse(), isTrue() and //! isNull() methods can be substituted if there's a need to move away //! from UniValue. (An implementation with boost::variant was posted at //! https://github.com/bitcoin/bitcoin/pull/15934/files#r337691812) diff --git a/src/util/system.cpp b/src/util/system.cpp index 7cc212a53d51..5fa6fcc08ca5 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -626,7 +626,7 @@ std::string ArgsManager::GetArg(const std::string& strArg, const std::string& st int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) const { const util::SettingsValue value = GetSetting(strArg); - return value.isNull() ? nDefault : value.isFalse() ? 0 : value.isTrue() ? 1 : value.isNum() ? value.get_int64() : LocaleIndependentAtoi(value.get_str()); + return value.isNull() ? nDefault : value.isFalse() ? 0 : value.isTrue() ? 1 : value.isNum() ? value.getInt() : LocaleIndependentAtoi(value.get_str()); } bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp index ed19e2499500..a23ba9e7c0cc 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -232,7 +232,7 @@ RPCHelpMan addmultisigaddress() if (!request.params[2].isNull()) label = LabelFromValue(request.params[2]); - int required = request.params[0].get_int(); + int required = request.params[0].getInt(); // Get the public keys const UniValue& keys_or_addrs = request.params[1].get_array(); @@ -289,9 +289,9 @@ RPCHelpMan keypoolrefill() // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool unsigned int kpSize = 0; if (!request.params[0].isNull()) { - if (request.params[0].get_int() < 0) + if (request.params[0].getInt() < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size."); - kpSize = (unsigned int)request.params[0].get_int(); + kpSize = (unsigned int)request.params[0].getInt(); } EnsureWalletIsUnlocked(*pwallet); diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 3d6465a89ce1..d72cefaff7d4 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -797,7 +797,7 @@ RPCHelpMan importelectrumwallet() // Whether to perform rescan after import int nStartHeight = 0; if (!request.params[1].isNull()) - nStartHeight = request.params[1].get_int(); + nStartHeight = request.params[1].getInt(); if (tip_height < nStartHeight) nStartHeight = tip_height; @@ -1459,7 +1459,7 @@ static int64_t GetImportTimestamp(const UniValue& data, int64_t now) if (data.exists("timestamp")) { const UniValue& timestamp = data["timestamp"]; if (timestamp.isNum()) { - return timestamp.get_int64(); + return timestamp.getInt(); } else if (timestamp.isStr() && timestamp.get_str() == "now") { return now; } @@ -1700,7 +1700,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c next_index = range_start; if (data.exists("next_index")) { - next_index = data["next_index"].get_int64(); + next_index = data["next_index"].getInt(); // bound checks if (next_index < range_start || next_index >= range_end) { throw JSONRPCError(RPC_INVALID_PARAMETER, "next_index is out of range"); diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index b9132d42b8a1..1b238040b83f 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -39,7 +39,7 @@ static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool b // Minimum confirmations int min_depth = 1; if (!params[1].isNull()) - min_depth = params[1].get_int(); + min_depth = params[1].getInt(); bool fAddLocked = (!params[2].isNull() && params[2].get_bool()); const bool include_immature_coinbase{params[3].isNull() ? false : params[3].get_bool()}; @@ -200,7 +200,7 @@ RPCHelpMan getbalance() int min_depth = 0; if (!request.params[1].isNull()) { - min_depth = request.params[1].get_int(); + min_depth = request.params[1].getInt(); } const UniValue& addlocked = request.params[2]; @@ -329,7 +329,7 @@ RPCHelpMan lockunspent() }); const uint256 txid(ParseHashO(o, "txid")); - const int nOutput = find_value(o, "vout").get_int(); + const int nOutput = find_value(o, "vout").getInt(); if (nOutput < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); } @@ -568,13 +568,13 @@ RPCHelpMan listunspent() int nMinDepth = 1; if (!request.params[0].isNull()) { RPCTypeCheckArgument(request.params[0], UniValue::VNUM); - nMinDepth = request.params[0].get_int(); + nMinDepth = request.params[0].getInt(); } int nMaxDepth = 9999999; if (!request.params[1].isNull()) { RPCTypeCheckArgument(request.params[1], UniValue::VNUM); - nMaxDepth = request.params[1].get_int(); + nMaxDepth = request.params[1].getInt(); } std::set destinations; @@ -633,10 +633,10 @@ RPCHelpMan listunspent() nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]); if (options.exists("maximumCount")) - nMaximumCount = options["maximumCount"].get_int64(); + nMaximumCount = options["maximumCount"].getInt(); if (options.exists("coinType")) { - int64_t nCoinType = options["coinType"].get_int64(); + int64_t nCoinType = options["coinType"].getInt(); if (nCoinType < static_cast(CoinType::MIN_COIN_TYPE) || nCoinType > static_cast(CoinType::MAX_COIN_TYPE)) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid coinType selected. Available range: %d - %d", static_cast(CoinType::MIN_COIN_TYPE), static_cast(CoinType::MAX_COIN_TYPE))); diff --git a/src/wallet/rpc/encrypt.cpp b/src/wallet/rpc/encrypt.cpp index 56969202aeff..13cdef3d3317 100644 --- a/src/wallet/rpc/encrypt.cpp +++ b/src/wallet/rpc/encrypt.cpp @@ -56,7 +56,7 @@ RPCHelpMan walletpassphrase() strWalletPass = request.params[0].get_str().c_str(); // Get the timeout - nSleepTime = request.params[1].get_int64(); + nSleepTime = request.params[1].getInt(); // Timeout cannot be negative, otherwise it will relock immediately if (nSleepTime < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative."); diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index bb182f3aa90d..ef1012689961 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -417,7 +417,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, } if (options.exists("changePosition") || options.exists("change_position")) { - change_position = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).get_int(); + change_position = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).getInt(); } const UniValue include_watching_option = options.exists("include_watching") ? options["include_watching"] : options["includeWatching"]; @@ -510,7 +510,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds"); for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) { - int pos = subtractFeeFromOutputs[idx].get_int(); + int pos = subtractFeeFromOutputs[idx].getInt(); if (setSubtractFeeFromOutputs.count(pos)) throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos)); if (pos < 0) diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index f68e487e4c2b..a34ba38733d5 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -73,7 +73,7 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons // Minimum confirmations int nMinDepth = 1; if (!params[0].isNull()) - nMinDepth = params[0].get_int(); + nMinDepth = params[0].getInt(); bool fAddLocked = false; if (!params[1].isNull()) fAddLocked = params[1].get_bool(); @@ -505,10 +505,10 @@ RPCHelpMan listtransactions() } int nCount = 10; if (!request.params[1].isNull()) - nCount = request.params[1].get_int(); + nCount = request.params[1].getInt(); int nFrom = 0; if (!request.params[2].isNull()) - nFrom = request.params[2].get_int(); + nFrom = request.params[2].getInt(); isminefilter filter = ISMINE_SPENDABLE; if (ParseIncludeWatchonly(request.params[3], *pwallet)) { @@ -632,7 +632,7 @@ RPCHelpMan listsinceblock() } if (!request.params[1].isNull()) { - target_confirms = request.params[1].get_int(); + target_confirms = request.params[1].getInt(); if (target_confirms < 1) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); @@ -885,14 +885,14 @@ RPCHelpMan rescanblockchain() int tip_height = pwallet->GetLastBlockHeight(); if (!request.params[0].isNull()) { - start_height = request.params[0].get_int(); + start_height = request.params[0].getInt(); if (start_height < 0 || start_height > tip_height) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height"); } } if (!request.params[1].isNull()) { - stop_height = request.params[1].get_int(); + stop_height = request.params[1].getInt(); if (*stop_height < 0 || *stop_height > tip_height) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height"); } else if (*stop_height < start_height) { diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 719b4975d829..d90004c01d18 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -107,7 +107,7 @@ static RPCHelpMan setcoinjoinrounds() const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; - int nRounds = request.params[0].get_int(); + int nRounds = request.params[0].getInt(); if (nRounds > MAX_COINJOIN_ROUNDS || nRounds < MIN_COINJOIN_ROUNDS) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid number of rounds"); @@ -138,7 +138,7 @@ static RPCHelpMan setcoinjoinamount() const std::shared_ptr wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; - int nAmount = request.params[0].get_int(); + int nAmount = request.params[0].getInt(); if (nAmount > MAX_COINJOIN_AMOUNT || nAmount < MIN_COINJOIN_AMOUNT) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount of " + CURRENCY_UNIT + " as mixing goal amount"); @@ -885,7 +885,7 @@ static RPCHelpMan upgradewallet() int version = 0; if (!request.params[0].isNull()) { - version = request.params[0].get_int(); + version = request.params[0].getInt(); } bilingual_str error; const int previous_version{pwallet->GetVersion()}; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index bd73767e7405..2e671c33888d 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -959,7 +959,7 @@ BOOST_FIXTURE_TEST_CASE(rpc_getaddressinfo, TestChain100Setup) BOOST_CHECK_EQUAL(find_value(response, "iswatchonly").get_bool(), false); BOOST_CHECK_EQUAL(find_value(response, "isscript").get_bool(), true); BOOST_CHECK_EQUAL(find_value(response, "ischange").get_bool(), false); - BOOST_CHECK_EQUAL(find_value(response, "sigsrequired").get_int(), 2); + BOOST_CHECK_EQUAL(find_value(response, "sigsrequired").getInt(), 2); BOOST_CHECK(find_value(response, "label").isNull()); UniValue labels = find_value(response, "labels").get_array(); From 88f794f4a1e330ad4f10d0c03631ed473646951a Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 04:30:13 +0000 Subject: [PATCH 04/19] Squashed 'src/univalue/' changes from a44caf65fe..6c19d050a9 6c19d050a9 Merge bitcoin-core/univalue-subtree#33: Add getInt() helper 09e4a930fc Add getInt helper 10619e0d9a Merge bitcoin-core/univalue#32: refactor: include-what-you-use 431cdf5d27 refactor: use constexpr where appropriate 64fc881fa4 refactor: cleanup headers for iwyu 9c35bf38eb Merge bitcoin-core/univalue-subtree#30: doc: note that our API has diverged from upstream 09b65facb9 doc: note that our API has diverged from upstream git-subtree-dir: src/univalue git-subtree-split: 6c19d050a9bcb2be216121db0df57c930a9ee12e --- README.md | 2 +- configure.ac | 4 +-- gen/gen.cpp | 8 +++-- include/univalue.h | 29 ++++++++++++----- lib/univalue.cpp | 11 ++++--- lib/univalue_get.cpp | 70 ++++++------------------------------------ lib/univalue_read.cpp | 13 +++++--- lib/univalue_write.cpp | 8 +++-- test/no_nul.cpp | 2 +- test/object.cpp | 12 +++++--- test/test_json.cpp | 4 ++- test/unitester.cpp | 7 ++--- 12 files changed, 74 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index 7c62c3397053..d622f5b1e035 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This class is aligned with the JSON standard, [RFC ## Library usage This is a fork of univalue used by Bitcoin Core. It is not maintained for usage -by other projects. Notably, the API may break in non-backward-compatible ways. +by other projects. Notably, the API is broken in non-backward-compatible ways. Other projects looking for a maintained library should use the upstream univalue at https://github.com/jgarzik/univalue. diff --git a/configure.ac b/configure.ac index 495b25a53d8e..ed9c5f0c5ca6 100644 --- a/configure.ac +++ b/configure.ac @@ -45,8 +45,8 @@ AC_SUBST(LIBUNIVALUE_AGE) LT_INIT LT_LANG([C++]) -dnl Require C++11 compiler (no GNU extensions) -AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault]) +dnl Require C++17 compiler (no GNU extensions) +AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory], [nodefault]) case $host in *mingw*) diff --git a/gen/gen.cpp b/gen/gen.cpp index b8a6c73f4ec4..ca5b470ddcb9 100644 --- a/gen/gen.cpp +++ b/gen/gen.cpp @@ -8,9 +8,11 @@ // $ ./gen > univalue_escapes.h // -#include -#include -#include "univalue.h" +#include + +#include +#include +#include static bool initEscapes; static std::string escapes[256]; diff --git a/include/univalue.h b/include/univalue.h index fc5cf402be3c..35eaa2dd0d6e 100644 --- a/include/univalue.h +++ b/include/univalue.h @@ -6,13 +6,14 @@ #ifndef __UNIVALUE_H__ #define __UNIVALUE_H__ -#include -#include - +#include +#include +#include +#include +#include #include +#include #include -#include -#include class UniValue { public: @@ -168,10 +169,24 @@ class UniValue { // value is of unexpected type const std::vector& getKeys() const; const std::vector& getValues() const; + template + auto getInt() const + { + static_assert(std::is_integral::value); + if (typ != VNUM) { + throw std::runtime_error("JSON value is not an integer as expected"); + } + Int result; + const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result); + if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) { + throw std::runtime_error("JSON integer out of range"); + } + return result; + } bool get_bool() const; const std::string& get_str() const; - int get_int() const; - int64_t get_int64() const; + auto get_int() const { return getInt(); }; + auto get_int64() const { return getInt(); }; double get_real() const; const UniValue& get_obj() const; const UniValue& get_array() const; diff --git a/lib/univalue.cpp b/lib/univalue.cpp index c4e59fae744b..3553995c28f4 100644 --- a/lib/univalue.cpp +++ b/lib/univalue.cpp @@ -3,12 +3,15 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. -#include +#include + #include +#include +#include #include -#include - -#include "univalue.h" +#include +#include +#include const UniValue NullUniValue; diff --git a/lib/univalue_get.cpp b/lib/univalue_get.cpp index 5af89a3561c1..9bbdb1fe69b9 100644 --- a/lib/univalue_get.cpp +++ b/lib/univalue_get.cpp @@ -3,17 +3,18 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include #include -#include +#include #include - -#include "univalue.h" +#include +#include +#include namespace { @@ -28,37 +29,6 @@ static bool ParsePrechecks(const std::string& str) return true; } -bool ParseInt32(const std::string& str, int32_t *out) -{ - if (!ParsePrechecks(str)) - return false; - char *endp = nullptr; - errno = 0; // strtol will not set errno if valid - long int n = strtol(str.c_str(), &endp, 10); - if(out) *out = (int32_t)n; - // Note that strtol returns a *long int*, so even if strtol doesn't report an over/underflow - // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit - // platforms the size of these types may be different. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - -bool ParseInt64(const std::string& str, int64_t *out) -{ - if (!ParsePrechecks(str)) - return false; - char *endp = nullptr; - errno = 0; // strtoll will not set errno if valid - long long int n = strtoll(str.c_str(), &endp, 10); - if(out) *out = (int64_t)n; - // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow - // we still have to check that the returned value is within the range of an *int64_t*. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - bool ParseDouble(const std::string& str, double *out) { if (!ParsePrechecks(str)) @@ -102,26 +72,6 @@ const std::string& UniValue::get_str() const return getValStr(); } -int UniValue::get_int() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not an integer as expected"); - int32_t retval; - if (!ParseInt32(getValStr(), &retval)) - throw std::runtime_error("JSON integer out of range"); - return retval; -} - -int64_t UniValue::get_int64() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not an integer as expected"); - int64_t retval; - if (!ParseInt64(getValStr(), &retval)) - throw std::runtime_error("JSON integer out of range"); - return retval; -} - double UniValue::get_real() const { if (typ != VNUM) diff --git a/lib/univalue_read.cpp b/lib/univalue_read.cpp index be39bfe57a7a..a6ed75e57a7c 100644 --- a/lib/univalue_read.cpp +++ b/lib/univalue_read.cpp @@ -2,19 +2,22 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. -#include -#include -#include -#include "univalue.h" +#include #include "univalue_utffilter.h" +#include +#include +#include +#include +#include + /* * According to stackexchange, the original json test suite wanted * to limit depth to 22. Widely-deployed PHP bails at depth 512, * so we will follow PHP's lead, which should be more than sufficient * (further stackexchange comments indicate depth > 32 rarely occurs). */ -static const size_t MAX_JSON_DEPTH = 512; +static constexpr size_t MAX_JSON_DEPTH = 512; static bool json_isdigit(int ch) { diff --git a/lib/univalue_write.cpp b/lib/univalue_write.cpp index 3a2c580c7f69..18833077b773 100644 --- a/lib/univalue_write.cpp +++ b/lib/univalue_write.cpp @@ -2,11 +2,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. -#include -#include -#include "univalue.h" +#include #include "univalue_escapes.h" +#include +#include +#include + static std::string json_escape(const std::string& inS) { std::string outS; diff --git a/test/no_nul.cpp b/test/no_nul.cpp index 83d292200bf8..3a7a727abbd5 100644 --- a/test/no_nul.cpp +++ b/test/no_nul.cpp @@ -1,4 +1,4 @@ -#include "univalue.h" +#include int main (int argc, char *argv[]) { diff --git a/test/object.cpp b/test/object.cpp index c2f52f83ac21..b9697a8cb7a9 100644 --- a/test/object.cpp +++ b/test/object.cpp @@ -3,13 +3,15 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. -#include -#include -#include -#include +#include + #include +#include +#include +#include #include -#include +#include +#include #define BOOST_FIXTURE_TEST_SUITE(a, b) #define BOOST_AUTO_TEST_CASE(funcName) void funcName() diff --git a/test/test_json.cpp b/test/test_json.cpp index 2943bae2b15e..f8c10238d4db 100644 --- a/test/test_json.cpp +++ b/test/test_json.cpp @@ -4,9 +4,11 @@ // It reads JSON input from stdin and exits with code 0 if it can be parsed // successfully. It also pretty prints the parsed JSON value to stdout. +#include + #include +#include #include -#include "univalue.h" using namespace std; diff --git a/test/unitester.cpp b/test/unitester.cpp index 02e1a83c6dff..81b1c5d3b1a7 100644 --- a/test/unitester.cpp +++ b/test/unitester.cpp @@ -2,12 +2,11 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. -#include -#include -#include +#include + #include +#include #include -#include "univalue.h" #ifndef JSON_TEST_SRC #error JSON_TEST_SRC must point to test source directory From 9db7b12119256e74f422892dee90c89ae87daba9 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 04:31:40 +0000 Subject: [PATCH 05/19] merge bitcoin#25113: Bump univalue subtree Fulfilled by 774a8ffc From b3443eebd49919287453b303270ba2a044537e9e Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 04:33:33 +0000 Subject: [PATCH 06/19] Squashed 'src/univalue/' changes from 6c19d050a9..de4f73ddca de4f73ddca Merge bitcoin-core/univalue-subtree#36: Drop overloaded members 076c051488 Drop overloaded members 06265321de Merge bitcoin-core/univalue-subtree#35: Remove get_int/get_int64 in favor of getInt<> 462c503aa4 Remove get_int/get_int64 in favor of getInt<> 68c8f5532d Merge bitcoin-core/univalue#34: doc: remove TODO 297c53a5ee doc: remove TODO git-subtree-dir: src/univalue git-subtree-split: de4f73ddca40487179e9ed08c6f6aa745d6cbba3 --- TODO | 10 -------- include/univalue.h | 58 ---------------------------------------------- test/object.cpp | 23 +++++++++++------- 3 files changed, 15 insertions(+), 76 deletions(-) delete mode 100644 TODO diff --git a/TODO b/TODO deleted file mode 100644 index 5530048e923e..000000000000 --- a/TODO +++ /dev/null @@ -1,10 +0,0 @@ - -Rearrange tree for easier 'git subtree' style use - -Move towards C++11 etc. - -Namespace support - must come up with useful shorthand, avoiding -long Univalue::Univalue::Univalue usages forced upon library users. - -Improve test suite - diff --git a/include/univalue.h b/include/univalue.h index 35eaa2dd0d6e..f0d4de2035f8 100644 --- a/include/univalue.h +++ b/include/univalue.h @@ -83,66 +83,10 @@ class UniValue { bool isObject() const { return (typ == VOBJ); } bool push_back(const UniValue& val); - bool push_back(const std::string& val_) { - UniValue tmpVal(VSTR, val_); - return push_back(tmpVal); - } - bool push_back(const char *val_) { - std::string s(val_); - return push_back(s); - } - bool push_back(uint64_t val_) { - UniValue tmpVal(val_); - return push_back(tmpVal); - } - bool push_back(int64_t val_) { - UniValue tmpVal(val_); - return push_back(tmpVal); - } - bool push_back(bool val_) { - UniValue tmpVal(val_); - return push_back(tmpVal); - } - bool push_back(int val_) { - UniValue tmpVal(val_); - return push_back(tmpVal); - } - bool push_back(double val_) { - UniValue tmpVal(val_); - return push_back(tmpVal); - } bool push_backV(const std::vector& vec); void __pushKV(const std::string& key, const UniValue& val); bool pushKV(const std::string& key, const UniValue& val); - bool pushKV(const std::string& key, const std::string& val_) { - UniValue tmpVal(VSTR, val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, const char *val_) { - std::string _val(val_); - return pushKV(key, _val); - } - bool pushKV(const std::string& key, int64_t val_) { - UniValue tmpVal(val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, uint64_t val_) { - UniValue tmpVal(val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, bool val_) { - UniValue tmpVal(val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, int val_) { - UniValue tmpVal((int64_t)val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, double val_) { - UniValue tmpVal(val_); - return pushKV(key, tmpVal); - } bool pushKVs(const UniValue& obj); std::string write(unsigned int prettyIndent = 0, @@ -185,8 +129,6 @@ class UniValue { } bool get_bool() const; const std::string& get_str() const; - auto get_int() const { return getInt(); }; - auto get_int64() const { return getInt(); }; double get_real() const; const UniValue& get_obj() const; const UniValue& get_array() const; diff --git a/test/object.cpp b/test/object.cpp index b9697a8cb7a9..8a35bf914daa 100644 --- a/test/object.cpp +++ b/test/object.cpp @@ -92,23 +92,30 @@ BOOST_AUTO_TEST_CASE(univalue_typecheck) BOOST_CHECK(v1.isNum()); BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); + { + UniValue v_negative; + BOOST_CHECK(v_negative.setNumStr("-1")); + BOOST_CHECK_THROW(v_negative.getInt(), std::runtime_error); + BOOST_CHECK_EQUAL(v_negative.getInt(), -1); + } + UniValue v2; BOOST_CHECK(v2.setBool(true)); BOOST_CHECK_EQUAL(v2.get_bool(), true); - BOOST_CHECK_THROW(v2.get_int(), std::runtime_error); + BOOST_CHECK_THROW(v2.getInt(), std::runtime_error); UniValue v3; BOOST_CHECK(v3.setNumStr("32482348723847471234")); - BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error); + BOOST_CHECK_THROW(v3.getInt(), std::runtime_error); BOOST_CHECK(v3.setNumStr("1000")); - BOOST_CHECK_EQUAL(v3.get_int64(), 1000); + BOOST_CHECK_EQUAL(v3.getInt(), 1000); UniValue v4; BOOST_CHECK(v4.setNumStr("2147483648")); - BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648); - BOOST_CHECK_THROW(v4.get_int(), std::runtime_error); + BOOST_CHECK_EQUAL(v4.getInt(), 2147483648); + BOOST_CHECK_THROW(v4.getInt(), std::runtime_error); BOOST_CHECK(v4.setNumStr("1000")); - BOOST_CHECK_EQUAL(v4.get_int(), 1000); + BOOST_CHECK_EQUAL(v4.getInt(), 1000); BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); BOOST_CHECK_EQUAL(v4.get_real(), 1000); BOOST_CHECK_THROW(v4.get_array(), std::runtime_error); @@ -120,10 +127,10 @@ BOOST_AUTO_TEST_CASE(univalue_typecheck) BOOST_CHECK(v5.read("[true, 10]")); BOOST_CHECK_NO_THROW(v5.get_array()); std::vector vals = v5.getValues(); - BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error); + BOOST_CHECK_THROW(vals[0].getInt(), std::runtime_error); BOOST_CHECK_EQUAL(vals[0].get_bool(), true); - BOOST_CHECK_EQUAL(vals[1].get_int(), 10); + BOOST_CHECK_EQUAL(vals[1].getInt(), 10); BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); } From 6b9e682f8cbe5b18e296dc9485c3144434cf9660 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 04:55:53 +0000 Subject: [PATCH 07/19] merge bitcoin#25249: Bump univalue subtree Fulfilled by c0c3af95 --- src/coinjoin/options.cpp | 14 +++++++------- src/masternode/meta.cpp | 14 +++++++------- src/rpc/blockchain.cpp | 2 +- src/rpc/quorums.cpp | 2 +- src/wallet/rpc/coins.cpp | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/coinjoin/options.cpp b/src/coinjoin/options.cpp index 3ac9234baf20..f6e3e133d0e1 100644 --- a/src/coinjoin/options.cpp +++ b/src/coinjoin/options.cpp @@ -78,11 +78,11 @@ void CCoinJoinClientOptions::GetJsonInfo(UniValue& obj) { assert(obj.isObject()); const CCoinJoinClientOptions& options = CCoinJoinClientOptions::Get(); - obj.pushKV("enabled", options.fEnableCoinJoin); - obj.pushKV("multisession", options.fCoinJoinMultiSession); - obj.pushKV("max_sessions", options.nCoinJoinSessions); - obj.pushKV("max_rounds", options.nCoinJoinRounds); - obj.pushKV("max_amount", options.nCoinJoinAmount); - obj.pushKV("denoms_goal", options.nCoinJoinDenomsGoal); - obj.pushKV("denoms_hardcap", options.nCoinJoinDenomsHardCap); + obj.pushKV("enabled", options.fEnableCoinJoin.load()); + obj.pushKV("multisession", options.fCoinJoinMultiSession.load()); + obj.pushKV("max_sessions", options.nCoinJoinSessions.load()); + obj.pushKV("max_rounds", options.nCoinJoinRounds.load()); + obj.pushKV("max_amount", options.nCoinJoinAmount.load()); + obj.pushKV("denoms_goal", options.nCoinJoinDenomsGoal.load()); + obj.pushKV("denoms_hardcap", options.nCoinJoinDenomsHardCap.load()); } diff --git a/src/masternode/meta.cpp b/src/masternode/meta.cpp index 3cc3ffbb5932..3610d0d23db9 100644 --- a/src/masternode/meta.cpp +++ b/src/masternode/meta.cpp @@ -36,13 +36,13 @@ UniValue CMasternodeMetaInfo::ToJson() const int64_t now = GetTime().count(); - ret.pushKV("lastDSQ", nLastDsq); - ret.pushKV("mixingTxCount", nMixingTxCount); - ret.pushKV("outboundAttemptCount", outboundAttemptCount); - ret.pushKV("lastOutboundAttempt", lastOutboundAttempt); - ret.pushKV("lastOutboundAttemptElapsed", now - lastOutboundAttempt); - ret.pushKV("lastOutboundSuccess", lastOutboundSuccess); - ret.pushKV("lastOutboundSuccessElapsed", now - lastOutboundSuccess); + ret.pushKV("lastDSQ", nLastDsq.load()); + ret.pushKV("mixingTxCount", nMixingTxCount.load()); + ret.pushKV("outboundAttemptCount", outboundAttemptCount.load()); + ret.pushKV("lastOutboundAttempt", lastOutboundAttempt.load()); + ret.pushKV("lastOutboundAttemptElapsed", now - lastOutboundAttempt.load()); + ret.pushKV("lastOutboundSuccess", lastOutboundSuccess.load()); + ret.pushKV("lastOutboundSuccessElapsed", now - lastOutboundSuccess.load()); return ret; } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d8e0a0802d37..582b4adb3722 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2461,7 +2461,7 @@ static RPCHelpMan scantxoutset() // no scan in progress return NullUniValue; } - result.pushKV("progress", g_scan_progress); + result.pushKV("progress", g_scan_progress.load()); return result; } else if (request.params[0].get_str() == "abort") { CoinsViewScanReserver reserver; diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index 2f512f46ed9a..6e8c93f86317 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -211,7 +211,7 @@ static UniValue BuildQuorumInfo(const llmq::CQuorumBlockProcessor& quorum_block_ } mo.pushKV("addresses", dmn->pdmnState->netInfo->ToJson()); mo.pushKV("pubKeyOperator", dmn->pdmnState->pubKeyOperator.ToString()); - mo.pushKV("valid", quorum->qc->validMembers[i]); + mo.pushKV("valid", static_cast(quorum->qc->validMembers[i])); if (quorum->qc->validMembers[i]) { if (quorum->params.size == 1) { mo.pushKV("pubKeyShare", dmn->pdmnState->pubKeyOperator.ToString()); diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index 1b238040b83f..3d16cc3df39e 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -329,7 +329,7 @@ RPCHelpMan lockunspent() }); const uint256 txid(ParseHashO(o, "txid")); - const int nOutput = find_value(o, "vout").getInt(); + const int nOutput{find_value(o, "vout").getInt()}; if (nOutput < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); } From 1e023e5995853737be1935247a6d421f3d7da413 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Fri, 10 Jun 2022 15:30:04 +0100 Subject: [PATCH 08/19] merge bitcoin#25369: Unsubtree Univalue --- .gitignore | 2 - Makefile.am | 1 - ci/lint/06_script.sh | 1 - contrib/devtools/copyright_header.py | 1 - doc/developer-notes.md | 4 - src/univalue/.cirrus.yml | 44 - src/univalue/COPYING | 19 - src/univalue/Makefile.am | 58 -- src/univalue/README.md | 21 - src/univalue/autogen.sh | 9 - src/univalue/build-aux/m4/.gitignore | 1 - .../build-aux/m4/ax_cxx_compile_stdcxx.m4 | 962 ------------------ src/univalue/configure.ac | 72 -- src/univalue/gen/gen.cpp | 84 -- src/univalue/include/univalue.h | 6 +- .../{lib => include}/univalue_escapes.h | 7 +- .../{lib => include}/univalue_utffilter.h | 6 +- src/univalue/lib/univalue_read.cpp | 2 +- src/univalue/lib/univalue_write.cpp | 2 +- src/univalue/pc/libunivalue-uninstalled.pc.in | 9 - src/univalue/pc/libunivalue.pc.in | 10 - src/univalue/sources.mk | 6 +- src/univalue/test/unitester.cpp | 34 +- test/lint/README.md | 1 - test/lint/lint-files.py | 2 +- test/lint/lint-format-strings.py | 2 +- test/lint/lint-include-guards.py | 1 - test/lint/lint-includes.py | 1 - test/lint/lint-locale-dependence.py | 1 - test/lint/lint-shell-locale.py | 2 +- test/lint/lint-shell.py | 2 +- test/lint/lint-spelling.py | 2 +- test/lint/lint-whitespace.py | 1 - 33 files changed, 31 insertions(+), 1345 deletions(-) delete mode 100644 src/univalue/.cirrus.yml delete mode 100644 src/univalue/COPYING delete mode 100644 src/univalue/Makefile.am delete mode 100644 src/univalue/README.md delete mode 100755 src/univalue/autogen.sh delete mode 100644 src/univalue/build-aux/m4/.gitignore delete mode 100644 src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4 delete mode 100644 src/univalue/configure.ac delete mode 100644 src/univalue/gen/gen.cpp rename src/univalue/{lib => include}/univalue_escapes.h (93%) rename src/univalue/{lib => include}/univalue_utffilter.h (96%) delete mode 100644 src/univalue/pc/libunivalue-uninstalled.pc.in delete mode 100644 src/univalue/pc/libunivalue.pc.in diff --git a/.gitignore b/.gitignore index dd1a98f8d0de..023edd5f3498 100644 --- a/.gitignore +++ b/.gitignore @@ -49,8 +49,6 @@ src/obj share/setup.nsi share/qt/Info.plist -src/univalue/gen - src/qt/*.moc src/qt/moc_*.cpp src/qt/forms/ui_*.h diff --git a/Makefile.am b/Makefile.am index b059d0c6f7d4..ad1c903f1acb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -169,7 +169,6 @@ LCOV_FILTER_PATTERN = \ -p "src/leveldb/" \ -p "src/crc32c/" \ -p "src/bench/" \ - -p "src/univalue" \ -p "src/crypto/ctaes" \ -p "src/minisketch" \ -p "src/secp256k1" \ diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh index 1493aa45b2fd..2912edd2dd42 100755 --- a/ci/lint/06_script.sh +++ b/ci/lint/06_script.sh @@ -26,7 +26,6 @@ export COMMIT_RANGE test/lint/git-subtree-check.sh src/crypto/ctaes test/lint/git-subtree-check.sh src/secp256k1 test/lint/git-subtree-check.sh src/minisketch -test/lint/git-subtree-check.sh src/univalue test/lint/git-subtree-check.sh src/leveldb test/lint/check-doc.py test/lint/all-lint.py diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py index f46f90e52d45..540e0fd5713c 100755 --- a/contrib/devtools/copyright_header.py +++ b/contrib/devtools/copyright_header.py @@ -45,7 +45,6 @@ "src/leveldb/", "src/minisketch", "src/secp256k1/", - "src/univalue/", ] INCLUDE = ['*.h', '*.cpp', '*.cc', '*.c', '*.mm', '*.py', '*.sh', '*.bash-completion'] diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 91616f46bcee..9824956fe908 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -1155,10 +1155,6 @@ Current subtrees include: - src/crypto/ctaes - Upstream at https://github.com/bitcoin-core/ctaes ; maintained by Core contributors. -- src/univalue - - Subtree at https://github.com/bitcoin-core/univalue-subtree ; maintained by Core contributors. - - Deviates from upstream https://github.com/jgarzik/univalue. - - src/minisketch - Upstream at https://github.com/sipa/minisketch ; maintained by Core contributors. diff --git a/src/univalue/.cirrus.yml b/src/univalue/.cirrus.yml deleted file mode 100644 index f140fee12bc8..000000000000 --- a/src/univalue/.cirrus.yml +++ /dev/null @@ -1,44 +0,0 @@ -env: - MAKEJOBS: "-j4" - RUN_TESTS: "true" - BASE_OUTDIR: "$CIRRUS_WORKING_DIR/out_dir_base" - DEBIAN_FRONTEND: "noninteractive" - -task: - container: - image: ubuntu:focal - cpu: 1 - memory: 1G - greedy: true # https://medium.com/cirruslabs/introducing-greedy-container-instances-29aad06dc2b4 - - matrix: - - name: "gcc" - env: - CC: "gcc" - CXX: "g++" - APT_PKGS: "gcc" - - name: "clang" - env: - CC: "clang" - CXX: "clang++" - APT_PKGS: "clang" - - name: "mingw" - env: - CC: "" - CXX: "" - UNIVALUE_CONFIG: "--host=x86_64-w64-mingw32" - APT_PKGS: "g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 binutils-mingw-w64-x86-64" - RUN_TESTS: "false" - - install_script: - - apt update - - apt install -y pkg-config build-essential libtool autotools-dev automake bsdmainutils - - apt install -y $APT_PKGS - autogen_script: - - ./autogen.sh - configure_script: - - ./configure --cache-file=config.cache --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib $UNIVALUE_CONFIG - make_script: - - make $MAKEJOBS V=1 - test_script: - - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi diff --git a/src/univalue/COPYING b/src/univalue/COPYING deleted file mode 100644 index 1fb429f3569c..000000000000 --- a/src/univalue/COPYING +++ /dev/null @@ -1,19 +0,0 @@ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/src/univalue/Makefile.am b/src/univalue/Makefile.am deleted file mode 100644 index 476f14b922eb..000000000000 --- a/src/univalue/Makefile.am +++ /dev/null @@ -1,58 +0,0 @@ -include sources.mk -ACLOCAL_AMFLAGS = -I build-aux/m4 -.PHONY: gen FORCE -.INTERMEDIATE: $(GENBIN) - -include_HEADERS = $(UNIVALUE_DIST_HEADERS_INT) -noinst_HEADERS = $(UNIVALUE_LIB_HEADERS_INT) - -lib_LTLIBRARIES = libunivalue.la - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = pc/libunivalue.pc - -libunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT) - -libunivalue_la_LDFLAGS = \ - -version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \ - -no-undefined -libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include - -TESTS = test/object test/unitester test/no_nul - -GENBIN = gen/gen$(BUILD_EXEEXT) -GEN_SRCS = gen/gen.cpp - -$(GENBIN): $(GEN_SRCS) - @echo Building $@ - $(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $< - -gen: $(GENBIN) FORCE - @echo Updating lib/univalue_escapes.h - $(AM_V_at)$(GENBIN) > lib/univalue_escapes.h - -noinst_PROGRAMS = $(TESTS) test/test_json - -test_unitester_SOURCES = $(UNIVALUE_TEST_UNITESTER_INT) -test_unitester_LDADD = libunivalue.la -test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\" -test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -test_test_json_SOURCES = $(UNIVALUE_TEST_JSON_INT) -test_test_json_LDADD = libunivalue.la -test_test_json_CXXFLAGS = -I$(top_srcdir)/include -test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -test_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT) -test_no_nul_LDADD = libunivalue.la -test_no_nul_CXXFLAGS = -I$(top_srcdir)/include -test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -test_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT) -test_object_LDADD = libunivalue.la -test_object_CXXFLAGS = -I$(top_srcdir)/include -test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -TEST_FILES = $(UNIVALUE_TEST_FILES_INT) - -EXTRA_DIST=$(UNIVALUE_TEST_FILES_INT) $(GEN_SRCS) diff --git a/src/univalue/README.md b/src/univalue/README.md deleted file mode 100644 index d622f5b1e035..000000000000 --- a/src/univalue/README.md +++ /dev/null @@ -1,21 +0,0 @@ - -# UniValue - -## Summary - -A universal value class, with JSON encoding and decoding. - -UniValue is an abstract data type that may be a null, boolean, string, -number, array container, or a key/value dictionary container, nested to -an arbitrary depth. - -This class is aligned with the JSON standard, [RFC -7159](https://tools.ietf.org/html/rfc7159.html). - -## Library usage - -This is a fork of univalue used by Bitcoin Core. It is not maintained for usage -by other projects. Notably, the API is broken in non-backward-compatible ways. - -Other projects looking for a maintained library should use the upstream -univalue at https://github.com/jgarzik/univalue. diff --git a/src/univalue/autogen.sh b/src/univalue/autogen.sh deleted file mode 100755 index 4b38721faad0..000000000000 --- a/src/univalue/autogen.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -set -e -srcdir="$(dirname $0)" -cd "$srcdir" -if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then - LIBTOOLIZE="${GLIBTOOLIZE}" - export LIBTOOLIZE -fi -autoreconf --install --force diff --git a/src/univalue/build-aux/m4/.gitignore b/src/univalue/build-aux/m4/.gitignore deleted file mode 100644 index f063686524ea..000000000000 --- a/src/univalue/build-aux/m4/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/*.m4 diff --git a/src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4 deleted file mode 100644 index f7e5137003cf..000000000000 --- a/src/univalue/build-aux/m4/ax_cxx_compile_stdcxx.m4 +++ /dev/null @@ -1,962 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) -# -# DESCRIPTION -# -# Check for baseline language coverage in the compiler for the specified -# version of the C++ standard. If necessary, add switches to CXX and -# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) -# or '14' (for the C++14 standard). -# -# The second argument, if specified, indicates whether you insist on an -# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -# -std=c++11). If neither is specified, you get whatever works, with -# preference for no added switch, and then for an extended mode. -# -# The third argument, if specified 'mandatory' or if left unspecified, -# indicates that baseline support for the specified C++ standard is -# required and that the macro should error out if no mode with that -# support is found. If specified 'optional', then configuration proceeds -# regardless, after defining HAVE_CXX${VERSION} if and only if a -# supporting mode is found. -# -# LICENSE -# -# Copyright (c) 2008 Benjamin Kosnik -# Copyright (c) 2012 Zack Weinberg -# Copyright (c) 2013 Roy Stogner -# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov -# Copyright (c) 2015 Paul Norman -# Copyright (c) 2015 Moritz Klammler -# Copyright (c) 2016, 2018 Krzesimir Nowak -# Copyright (c) 2019 Enji Cooper -# Copyright (c) 2020 Jason Merrill -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 12 - -dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro -dnl (serial version number 13). - -AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl - m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], - [$1], [14], [ax_cxx_compile_alternatives="14 1y"], - [$1], [17], [ax_cxx_compile_alternatives="17 1z"], - [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl - m4_if([$2], [], [], - [$2], [ext], [], - [$2], [noext], [], - [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl - m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], - [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], - [$3], [optional], [ax_cxx_compile_cxx$1_required=false], - [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) - AC_LANG_PUSH([C++])dnl - ac_success=no - - m4_if([$2], [], [dnl - AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, - ax_cv_cxx_compile_cxx$1, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [ax_cv_cxx_compile_cxx$1=yes], - [ax_cv_cxx_compile_cxx$1=no])]) - if test x$ax_cv_cxx_compile_cxx$1 = xyes; then - ac_success=yes - fi]) - - m4_if([$2], [noext], [], [dnl - if test x$ac_success = xno; then - for alternative in ${ax_cxx_compile_alternatives}; do - switch="-std=gnu++${alternative}" - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXX="$CXX" - CXX="$CXX $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXX="$ac_save_CXX"]) - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - fi]) - - m4_if([$2], [ext], [], [dnl - if test x$ac_success = xno; then - dnl HP's aCC needs +std=c++11 according to: - dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf - dnl Cray's crayCC needs "-h std=c++11" - for alternative in ${ax_cxx_compile_alternatives}; do - for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXX="$CXX" - CXX="$CXX $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXX="$ac_save_CXX"]) - if eval test x\$$cachevar = xyes; then - CXX="$CXX $switch" - if test -n "$CXXCPP" ; then - CXXCPP="$CXXCPP $switch" - fi - ac_success=yes - break - fi - done - if test x$ac_success = xyes; then - break - fi - done - fi]) - AC_LANG_POP([C++]) - if test x$ax_cxx_compile_cxx$1_required = xtrue; then - if test x$ac_success = xno; then - AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) - fi - fi - if test x$ac_success = xno; then - HAVE_CXX$1=0 - AC_MSG_NOTICE([No compiler with C++$1 support was found]) - else - HAVE_CXX$1=1 - AC_DEFINE(HAVE_CXX$1,1, - [define if the compiler supports basic C++$1 syntax]) - fi - AC_SUBST(HAVE_CXX$1) -]) - - -dnl Test body for checking C++11 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 -) - - -dnl Test body for checking C++14 support - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 -) - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 -) - -dnl Tests for new features in C++11 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ - -// If the compiler admits that it is not ready for C++11, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201103L - -#error "This is not a C++11 compiler" - -#else - -namespace cxx11 -{ - - namespace test_static_assert - { - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - } - - namespace test_final_override - { - - struct Base - { - virtual ~Base() {} - virtual void f() {} - }; - - struct Derived : public Base - { - virtual ~Derived() override {} - virtual void f() override {} - }; - - } - - namespace test_double_right_angle_brackets - { - - template < typename T > - struct check {}; - - typedef check single_type; - typedef check> double_type; - typedef check>> triple_type; - typedef check>>> quadruple_type; - - } - - namespace test_decltype - { - - int - f() - { - int a = 1; - decltype(a) b = 2; - return a + b; - } - - } - - namespace test_type_deduction - { - - template < typename T1, typename T2 > - struct is_same - { - static const bool value = false; - }; - - template < typename T > - struct is_same - { - static const bool value = true; - }; - - template < typename T1, typename T2 > - auto - add(T1 a1, T2 a2) -> decltype(a1 + a2) - { - return a1 + a2; - } - - int - test(const int c, volatile int v) - { - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == false, ""); - auto ac = c; - auto av = v; - auto sumi = ac + av + 'x'; - auto sumf = ac + av + 1.0; - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == true, ""); - return (sumf > 0.0) ? sumi : add(c, v); - } - - } - - namespace test_noexcept - { - - int f() { return 0; } - int g() noexcept { return 0; } - - static_assert(noexcept(f()) == false, ""); - static_assert(noexcept(g()) == true, ""); - - } - - namespace test_constexpr - { - - template < typename CharT > - unsigned long constexpr - strlen_c_r(const CharT *const s, const unsigned long acc) noexcept - { - return *s ? strlen_c_r(s + 1, acc + 1) : acc; - } - - template < typename CharT > - unsigned long constexpr - strlen_c(const CharT *const s) noexcept - { - return strlen_c_r(s, 0UL); - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("1") == 1UL, ""); - static_assert(strlen_c("example") == 7UL, ""); - static_assert(strlen_c("another\0example") == 7UL, ""); - - } - - namespace test_rvalue_references - { - - template < int N > - struct answer - { - static constexpr int value = N; - }; - - answer<1> f(int&) { return answer<1>(); } - answer<2> f(const int&) { return answer<2>(); } - answer<3> f(int&&) { return answer<3>(); } - - void - test() - { - int i = 0; - const int c = 0; - static_assert(decltype(f(i))::value == 1, ""); - static_assert(decltype(f(c))::value == 2, ""); - static_assert(decltype(f(0))::value == 3, ""); - } - - } - - namespace test_uniform_initialization - { - - struct test - { - static const int zero {}; - static const int one {1}; - }; - - static_assert(test::zero == 0, ""); - static_assert(test::one == 1, ""); - - } - - namespace test_lambdas - { - - void - test1() - { - auto lambda1 = [](){}; - auto lambda2 = lambda1; - lambda1(); - lambda2(); - } - - int - test2() - { - auto a = [](int i, int j){ return i + j; }(1, 2); - auto b = []() -> int { return '0'; }(); - auto c = [=](){ return a + b; }(); - auto d = [&](){ return c; }(); - auto e = [a, &b](int x) mutable { - const auto identity = [](int y){ return y; }; - for (auto i = 0; i < a; ++i) - a += b--; - return x + identity(a + b); - }(0); - return a + b + c + d + e; - } - - int - test3() - { - const auto nullary = [](){ return 0; }; - const auto unary = [](int x){ return x; }; - using nullary_t = decltype(nullary); - using unary_t = decltype(unary); - const auto higher1st = [](nullary_t f){ return f(); }; - const auto higher2nd = [unary](nullary_t f1){ - return [unary, f1](unary_t f2){ return f2(unary(f1())); }; - }; - return higher1st(nullary) + higher2nd(nullary)(unary); - } - - } - - namespace test_variadic_templates - { - - template - struct sum; - - template - struct sum - { - static constexpr auto value = N0 + sum::value; - }; - - template <> - struct sum<> - { - static constexpr auto value = 0; - }; - - static_assert(sum<>::value == 0, ""); - static_assert(sum<1>::value == 1, ""); - static_assert(sum<23>::value == 23, ""); - static_assert(sum<1, 2>::value == 3, ""); - static_assert(sum<5, 5, 11>::value == 21, ""); - static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - - } - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function - // because of this. - namespace test_template_alias_sfinae - { - - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { func(0); } - - } - -} // namespace cxx11 - -#endif // __cplusplus >= 201103L - -]]) - - -dnl Tests for new features in C++14 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ - -// If the compiler admits that it is not ready for C++14, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201402L - -#error "This is not a C++14 compiler" - -#else - -namespace cxx14 -{ - - namespace test_polymorphic_lambdas - { - - int - test() - { - const auto lambda = [](auto&&... args){ - const auto istiny = [](auto x){ - return (sizeof(x) == 1UL) ? 1 : 0; - }; - const int aretiny[] = { istiny(args)... }; - return aretiny[0]; - }; - return lambda(1, 1L, 1.0f, '1'); - } - - } - - namespace test_binary_literals - { - - constexpr auto ivii = 0b0000000000101010; - static_assert(ivii == 42, "wrong value"); - - } - - namespace test_generalized_constexpr - { - - template < typename CharT > - constexpr unsigned long - strlen_c(const CharT *const s) noexcept - { - auto length = 0UL; - for (auto p = s; *p; ++p) - ++length; - return length; - } - - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("x") == 1UL, ""); - static_assert(strlen_c("test") == 4UL, ""); - static_assert(strlen_c("another\0test") == 7UL, ""); - - } - - namespace test_lambda_init_capture - { - - int - test() - { - auto x = 0; - const auto lambda1 = [a = x](int b){ return a + b; }; - const auto lambda2 = [a = lambda1(x)](){ return a; }; - return lambda2(); - } - - } - - namespace test_digit_separators - { - - constexpr auto ten_million = 100'000'000; - static_assert(ten_million == 100000000, ""); - - } - - namespace test_return_type_deduction - { - - auto f(int& x) { return x; } - decltype(auto) g(int& x) { return x; } - - template < typename T1, typename T2 > - struct is_same - { - static constexpr auto value = false; - }; - - template < typename T > - struct is_same - { - static constexpr auto value = true; - }; - - int - test() - { - auto x = 0; - static_assert(is_same::value, ""); - static_assert(is_same::value, ""); - return x; - } - - } - -} // namespace cxx14 - -#endif // __cplusplus >= 201402L - -]]) - - -dnl Tests for new features in C++17 - -m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ - -// If the compiler admits that it is not ready for C++17, why torture it? -// Hopefully, this will speed up the test. - -#ifndef __cplusplus - -#error "This is not a C++ compiler" - -#elif __cplusplus < 201703L - -#error "This is not a C++17 compiler" - -#else - -#include -#include -#include - -namespace cxx17 -{ - - namespace test_constexpr_lambdas - { - - constexpr int foo = [](){return 42;}(); - - } - - namespace test::nested_namespace::definitions - { - - } - - namespace test_fold_expression - { - - template - int multiply(Args... args) - { - return (args * ... * 1); - } - - template - bool all(Args... args) - { - return (args && ...); - } - - } - - namespace test_extended_static_assert - { - - static_assert (true); - - } - - namespace test_auto_brace_init_list - { - - auto foo = {5}; - auto bar {5}; - - static_assert(std::is_same, decltype(foo)>::value); - static_assert(std::is_same::value); - } - - namespace test_typename_in_template_template_parameter - { - - template typename X> struct D; - - } - - namespace test_fallthrough_nodiscard_maybe_unused_attributes - { - - int f1() - { - return 42; - } - - [[nodiscard]] int f2() - { - [[maybe_unused]] auto unused = f1(); - - switch (f1()) - { - case 17: - f1(); - [[fallthrough]]; - case 42: - f1(); - } - return f1(); - } - - } - - namespace test_extended_aggregate_initialization - { - - struct base1 - { - int b1, b2 = 42; - }; - - struct base2 - { - base2() { - b3 = 42; - } - int b3; - }; - - struct derived : base1, base2 - { - int d; - }; - - derived d1 {{1, 2}, {}, 4}; // full initialization - derived d2 {{}, {}, 4}; // value-initialized bases - - } - - namespace test_general_range_based_for_loop - { - - struct iter - { - int i; - - int& operator* () - { - return i; - } - - const int& operator* () const - { - return i; - } - - iter& operator++() - { - ++i; - return *this; - } - }; - - struct sentinel - { - int i; - }; - - bool operator== (const iter& i, const sentinel& s) - { - return i.i == s.i; - } - - bool operator!= (const iter& i, const sentinel& s) - { - return !(i == s); - } - - struct range - { - iter begin() const - { - return {0}; - } - - sentinel end() const - { - return {5}; - } - }; - - void f() - { - range r {}; - - for (auto i : r) - { - [[maybe_unused]] auto v = i; - } - } - - } - - namespace test_lambda_capture_asterisk_this_by_value - { - - struct t - { - int i; - int foo() - { - return [*this]() - { - return i; - }(); - } - }; - - } - - namespace test_enum_class_construction - { - - enum class byte : unsigned char - {}; - - byte foo {42}; - - } - - namespace test_constexpr_if - { - - template - int f () - { - if constexpr(cond) - { - return 13; - } - else - { - return 42; - } - } - - } - - namespace test_selection_statement_with_initializer - { - - int f() - { - return 13; - } - - int f2() - { - if (auto i = f(); i > 0) - { - return 3; - } - - switch (auto i = f(); i + 4) - { - case 17: - return 2; - - default: - return 1; - } - } - - } - - namespace test_template_argument_deduction_for_class_templates - { - - template - struct pair - { - pair (T1 p1, T2 p2) - : m1 {p1}, - m2 {p2} - {} - - T1 m1; - T2 m2; - }; - - void f() - { - [[maybe_unused]] auto p = pair{13, 42u}; - } - - } - - namespace test_non_type_auto_template_parameters - { - - template - struct B - {}; - - B<5> b1; - B<'a'> b2; - - } - - namespace test_structured_bindings - { - - int arr[2] = { 1, 2 }; - std::pair pr = { 1, 2 }; - - auto f1() -> int(&)[2] - { - return arr; - } - - auto f2() -> std::pair& - { - return pr; - } - - struct S - { - int x1 : 2; - volatile double y1; - }; - - S f3() - { - return {}; - } - - auto [ x1, y1 ] = f1(); - auto& [ xr1, yr1 ] = f1(); - auto [ x2, y2 ] = f2(); - auto& [ xr2, yr2 ] = f2(); - const auto [ x3, y3 ] = f3(); - - } - - namespace test_exception_spec_type_system - { - - struct Good {}; - struct Bad {}; - - void g1() noexcept; - void g2(); - - template - Bad - f(T*, T*); - - template - Good - f(T1*, T2*); - - static_assert (std::is_same_v); - - } - - namespace test_inline_variables - { - - template void f(T) - {} - - template inline T g(T) - { - return T{}; - } - - template<> inline void f<>(int) - {} - - template<> int g<>(int) - { - return 5; - } - - } - -} // namespace cxx17 - -#endif // __cplusplus < 201703L - -]]) diff --git a/src/univalue/configure.ac b/src/univalue/configure.ac deleted file mode 100644 index ed9c5f0c5ca6..000000000000 --- a/src/univalue/configure.ac +++ /dev/null @@ -1,72 +0,0 @@ -m4_define([libunivalue_major_version], [1]) -m4_define([libunivalue_minor_version], [1]) -m4_define([libunivalue_micro_version], [4]) -m4_define([libunivalue_interface_age], [4]) -# If you need a modifier for the version number. -# Normally empty, but can be used to make "fixup" releases. -m4_define([libunivalue_extraversion], []) - -dnl libtool versioning from libunivalue -m4_define([libunivalue_current], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version - libunivalue_interface_age)]) -m4_define([libunivalue_binary_age], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version)]) -m4_define([libunivalue_revision], [libunivalue_interface_age]) -m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_interface_age)]) -m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) - - -AC_INIT([univalue], [1.0.4], - [http://github.com/jgarzik/univalue/]) - -dnl make the compilation flags quiet unless V=1 is used -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -AC_PREREQ(2.60) -AC_CONFIG_SRCDIR([lib/univalue.cpp]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([build-aux/m4]) -AC_CONFIG_HEADERS([univalue-config.h]) -AM_INIT_AUTOMAKE([subdir-objects foreign]) - -LIBUNIVALUE_MAJOR_VERSION=libunivalue_major_version -LIBUNIVALUE_MINOR_VERSION=libunivalue_minor_version -LIBUNIVALUE_MICRO_VERSION=libunivalue_micro_version -LIBUNIVALUE_INTERFACE_AGE=libunivalue_interface_age - -# ABI version -# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html -LIBUNIVALUE_CURRENT=libunivalue_current -LIBUNIVALUE_REVISION=libunivalue_revision -LIBUNIVALUE_AGE=libunivalue_age - -AC_SUBST(LIBUNIVALUE_CURRENT) -AC_SUBST(LIBUNIVALUE_REVISION) -AC_SUBST(LIBUNIVALUE_AGE) - -LT_INIT -LT_LANG([C++]) - -dnl Require C++17 compiler (no GNU extensions) -AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory], [nodefault]) - -case $host in - *mingw*) - LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" - ;; -esac - -BUILD_EXEEXT= -case $build in - *mingw*) - BUILD_EXEEXT=".exe" - ;; -esac - -AC_CONFIG_FILES([ - Makefile - pc/libunivalue.pc - pc/libunivalue-uninstalled.pc]) - -AC_SUBST(LIBTOOL_APP_LDFLAGS) -AC_SUBST(BUILD_EXEEXT) -AC_OUTPUT - diff --git a/src/univalue/gen/gen.cpp b/src/univalue/gen/gen.cpp deleted file mode 100644 index ca5b470ddcb9..000000000000 --- a/src/univalue/gen/gen.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT software license, see the accompanying -// file COPYING or https://opensource.org/licenses/mit-license.php. - -// -// To re-create univalue_escapes.h: -// $ g++ -o gen gen.cpp -// $ ./gen > univalue_escapes.h -// - -#include - -#include -#include -#include - -static bool initEscapes; -static std::string escapes[256]; - -static void initJsonEscape() -{ - // Escape all lower control characters (some get overridden with smaller sequences below) - for (int ch=0x00; ch<0x20; ++ch) { - char tmpbuf[20]; - snprintf(tmpbuf, sizeof(tmpbuf), "\\u%04x", ch); - escapes[ch] = std::string(tmpbuf); - } - - escapes[(int)'"'] = "\\\""; - escapes[(int)'\\'] = "\\\\"; - escapes[(int)'\b'] = "\\b"; - escapes[(int)'\f'] = "\\f"; - escapes[(int)'\n'] = "\\n"; - escapes[(int)'\r'] = "\\r"; - escapes[(int)'\t'] = "\\t"; - escapes[(int)'\x7f'] = "\\u007f"; // U+007F DELETE - - initEscapes = true; -} - -static void outputEscape() -{ - printf( "// Automatically generated file. Do not modify.\n" - "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" - "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" - "static const char *escapes[256] = {\n"); - - for (unsigned int i = 0; i < 256; i++) { - if (escapes[i].empty()) { - printf("\tnullptr,\n"); - } else { - printf("\t\""); - - unsigned int si; - for (si = 0; si < escapes[i].size(); si++) { - char ch = escapes[i][si]; - switch (ch) { - case '"': - printf("\\\""); - break; - case '\\': - printf("\\\\"); - break; - default: - printf("%c", escapes[i][si]); - break; - } - } - - printf("\",\n"); - } - } - - printf( "};\n" - "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); -} - -int main (int argc, char *argv[]) -{ - initJsonEscape(); - outputEscape(); - return 0; -} - diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index f0d4de2035f8..22be0311e835 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -3,8 +3,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. -#ifndef __UNIVALUE_H__ -#define __UNIVALUE_H__ +#ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H +#define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H #include #include @@ -194,4 +194,4 @@ extern const UniValue NullUniValue; const UniValue& find_value( const UniValue& obj, const std::string& name); -#endif // __UNIVALUE_H__ +#endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H diff --git a/src/univalue/lib/univalue_escapes.h b/src/univalue/include/univalue_escapes.h similarity index 93% rename from src/univalue/lib/univalue_escapes.h rename to src/univalue/include/univalue_escapes.h index 3f714f8e5bc4..83767e8ac5d8 100644 --- a/src/univalue/lib/univalue_escapes.h +++ b/src/univalue/include/univalue_escapes.h @@ -1,6 +1,5 @@ -// Automatically generated file. Do not modify. -#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H -#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H +#ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_ESCAPES_H +#define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_ESCAPES_H static const char *escapes[256] = { "\\u0000", "\\u0001", @@ -259,4 +258,4 @@ static const char *escapes[256] = { nullptr, nullptr, }; -#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H +#endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_ESCAPES_H diff --git a/src/univalue/lib/univalue_utffilter.h b/src/univalue/include/univalue_utffilter.h similarity index 96% rename from src/univalue/lib/univalue_utffilter.h rename to src/univalue/include/univalue_utffilter.h index c24ac58eaf2b..f688eaaa30f9 100644 --- a/src/univalue/lib/univalue_utffilter.h +++ b/src/univalue/include/univalue_utffilter.h @@ -1,8 +1,8 @@ // Copyright 2016 Wladimir J. van der Laan // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/licenses/mit-license.php. -#ifndef UNIVALUE_UTFFILTER_H -#define UNIVALUE_UTFFILTER_H +#ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_UTFFILTER_H +#define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_UTFFILTER_H #include @@ -116,4 +116,4 @@ class JSONUTF8StringFilter } }; -#endif +#endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_UTFFILTER_H diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp index a6ed75e57a7c..2f2385383c14 100644 --- a/src/univalue/lib/univalue_read.cpp +++ b/src/univalue/lib/univalue_read.cpp @@ -3,7 +3,7 @@ // file COPYING or https://opensource.org/licenses/mit-license.php. #include -#include "univalue_utffilter.h" +#include #include #include diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp index 18833077b773..4a3cbba20fda 100644 --- a/src/univalue/lib/univalue_write.cpp +++ b/src/univalue/lib/univalue_write.cpp @@ -3,7 +3,7 @@ // file COPYING or https://opensource.org/licenses/mit-license.php. #include -#include "univalue_escapes.h" +#include #include #include diff --git a/src/univalue/pc/libunivalue-uninstalled.pc.in b/src/univalue/pc/libunivalue-uninstalled.pc.in deleted file mode 100644 index b7f53e875e6e..000000000000 --- a/src/univalue/pc/libunivalue-uninstalled.pc.in +++ /dev/null @@ -1,9 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libunivalue -Description: libunivalue, C++ universal value object and JSON library -Version: @VERSION@ -Libs: ${pc_top_builddir}/${pcfiledir}/libunivalue.la diff --git a/src/univalue/pc/libunivalue.pc.in b/src/univalue/pc/libunivalue.pc.in deleted file mode 100644 index 358a2d5f7321..000000000000 --- a/src/univalue/pc/libunivalue.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libunivalue -Description: libunivalue, C++ universal value object and JSON library -Version: @VERSION@ -Libs: -L${libdir} -lunivalue -Cflags: -I${includedir} diff --git a/src/univalue/sources.mk b/src/univalue/sources.mk index efab6d277f93..e156216378b1 100644 --- a/src/univalue/sources.mk +++ b/src/univalue/sources.mk @@ -12,10 +12,8 @@ UNIVALUE_INCLUDE_DIR_INT = %reldir%/include UNIVALUE_DIST_HEADERS_INT = UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue.h - -UNIVALUE_LIB_HEADERS_INT = -UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_utffilter.h -UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_escapes.h +UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue_utffilter.h +UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue_escapes.h UNIVALUE_LIB_SOURCES_INT = UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue.cpp diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp index 81b1c5d3b1a7..94c149b39fd7 100644 --- a/src/univalue/test/unitester.cpp +++ b/src/univalue/test/unitester.cpp @@ -12,15 +12,7 @@ #error JSON_TEST_SRC must point to test source directory #endif -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#endif - std::string srcdir(JSON_TEST_SRC); -static bool test_failed = false; - -#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } } -#define f_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", __func__); } } static std::string rtrim(std::string s) { @@ -41,9 +33,9 @@ static void runtest(std::string filename, const std::string& jdata) bool testResult = val.read(jdata); if (wantPass) { - d_assert(testResult == true); + assert(testResult == true); } else { - d_assert(testResult == false); + assert(testResult == false); } if (wantRoundTrip) { @@ -141,30 +133,30 @@ void unescape_unicode_test() bool testResult; // Escaped ASCII (quote) testResult = val.read("[\"\\u0022\"]"); - f_assert(testResult); - f_assert(val[0].get_str() == "\""); + assert(testResult); + assert(val[0].get_str() == "\""); // Escaped Basic Plane character, two-byte UTF-8 testResult = val.read("[\"\\u0191\"]"); - f_assert(testResult); - f_assert(val[0].get_str() == "\xc6\x91"); + assert(testResult); + assert(val[0].get_str() == "\xc6\x91"); // Escaped Basic Plane character, three-byte UTF-8 testResult = val.read("[\"\\u2191\"]"); - f_assert(testResult); - f_assert(val[0].get_str() == "\xe2\x86\x91"); + assert(testResult); + assert(val[0].get_str() == "\xe2\x86\x91"); // Escaped Supplementary Plane character U+1d161 testResult = val.read("[\"\\ud834\\udd61\"]"); - f_assert(testResult); - f_assert(val[0].get_str() == "\xf0\x9d\x85\xa1"); + assert(testResult); + assert(val[0].get_str() == "\xf0\x9d\x85\xa1"); } int main (int argc, char *argv[]) { - for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { - runtest_file(filenames[fidx]); + for (const auto& f: filenames) { + runtest_file(f); } unescape_unicode_test(); - return test_failed ? 1 : 0; + return 0; } diff --git a/test/lint/README.md b/test/lint/README.md index 38e7e102c63d..704922d7abe3 100644 --- a/test/lint/README.md +++ b/test/lint/README.md @@ -46,7 +46,6 @@ To do a full check with `-r`, make sure that you have fetched the upstream repos maintained: * for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master) * for `src/leveldb`: https://github.com/bitcoin-core/leveldb-subtree.git (branch bitcoin-fork) -* for `src/univalue`: https://github.com/bitcoin-core/univalue-subtree.git (branch master) * for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master) * for `src/crc32c`: https://github.com/bitcoin-core/crc32c-subtree.git (branch bitcoin-fork) * for `src/minisketch`: https://github.com/sipa/minisketch.git (branch master) diff --git a/test/lint/lint-files.py b/test/lint/lint-files.py index 4a537501a281..ee09cea93235 100755 --- a/test/lint/lint-files.py +++ b/test/lint/lint-files.py @@ -21,7 +21,7 @@ ALLOWED_FILENAME_REGEXP = "^[a-zA-Z0-9/_.@][a-zA-Z0-9/_.@-]*$" ALLOWED_SOURCE_FILENAME_REGEXP = "^[a-z0-9_./-]+$" ALLOWED_SOURCE_FILENAME_EXCEPTION_REGEXP = ( - "^src/(dashbls/|immer/|secp256k1/|minisketch/|univalue/|test/fuzz/FuzzedDataProvider.h)" + "^src/(dashbls/|immer/|secp256k1/|minisketch/|test/fuzz/FuzzedDataProvider.h)" ) ALLOWED_PERMISSION_NON_EXECUTABLES = 0o644 ALLOWED_PERMISSION_EXECUTABLES = 0o755 diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py index 333327e519a1..a1bd91407e48 100755 --- a/test/lint/lint-format-strings.py +++ b/test/lint/lint-format-strings.py @@ -77,7 +77,7 @@ def main(): matching_files_filtered = [] for matching_file in matching_files: - if not re.search('^src/(dashbls|leveldb|secp256k1|minisketch|tinyformat|univalue|test/fuzz/strprintf.cpp)', matching_file): + if not re.search('^src/(dashbls|leveldb|secp256k1|minisketch|tinyformat|test/fuzz/strprintf.cpp)', matching_file): matching_files_filtered.append(matching_file) matching_files_filtered.sort() diff --git a/test/lint/lint-include-guards.py b/test/lint/lint-include-guards.py index 8fd4c7d63682..e8a287cf2a15 100755 --- a/test/lint/lint-include-guards.py +++ b/test/lint/lint-include-guards.py @@ -22,7 +22,6 @@ 'src/crc32c', 'src/secp256k1', 'src/minisketch', - 'src/univalue', 'src/tinyformat.h', 'src/bench/nanobench.h', 'src/test/fuzz/FuzzedDataProvider.h', diff --git a/test/lint/lint-includes.py b/test/lint/lint-includes.py index ee897c7ed165..4a2ef0a88fad 100755 --- a/test/lint/lint-includes.py +++ b/test/lint/lint-includes.py @@ -19,7 +19,6 @@ "src/crc32c/", "src/secp256k1/", "src/minisketch/", - "src/univalue/", "src/dashbls/", "src/immer/", "src/crypto/x11/"] diff --git a/test/lint/lint-locale-dependence.py b/test/lint/lint-locale-dependence.py index ec27b620bb3b..405c346e6971 100755 --- a/test/lint/lint-locale-dependence.py +++ b/test/lint/lint-locale-dependence.py @@ -62,7 +62,6 @@ "src/secp256k1/", "src/minisketch/", "src/tinyformat.h", - "src/univalue/", "src/dashbls/", "src/immer/" ] diff --git a/test/lint/lint-shell-locale.py b/test/lint/lint-shell-locale.py index 52928041cb0b..77f6d79f3529 100755 --- a/test/lint/lint-shell-locale.py +++ b/test/lint/lint-shell-locale.py @@ -41,7 +41,7 @@ def main(): exit_code = 0 shell_files = get_shell_files_list() for file_path in shell_files: - if re.search('src/(dashbls|secp256k1|minisketch|univalue)/', file_path): + if re.search('src/(dashbls|secp256k1|minisketch)/', file_path): continue with open(file_path, 'r', encoding='utf-8') as file_obj: diff --git a/test/lint/lint-shell.py b/test/lint/lint-shell.py index 569276cb0d58..c1acd618c120 100755 --- a/test/lint/lint-shell.py +++ b/test/lint/lint-shell.py @@ -68,7 +68,7 @@ def main(): ] files = get_files(files_cmd) # remove everything that doesn't match this regex - reg = re.compile(r'src/[dashbls,immer,leveldb,secp256k1,minisketch,univalue]') + reg = re.compile(r'src/[dashbls,immer,leveldb,secp256k1,minisketch]') files[:] = [file for file in files if not reg.match(file)] # build the `shellcheck` command diff --git a/test/lint/lint-spelling.py b/test/lint/lint-spelling.py index e462d9c59d70..533bf8d63122 100755 --- a/test/lint/lint-spelling.py +++ b/test/lint/lint-spelling.py @@ -12,7 +12,7 @@ from subprocess import check_output, STDOUT, CalledProcessError IGNORE_WORDS_FILE = 'test/lint/spelling.ignore-words.txt' -FILES_ARGS = ['git', 'ls-files', '--', ":(exclude)build-aux/m4/", ":(exclude)contrib/seeds/*.txt", ":(exclude)depends/", ":(exclude)doc/release-notes/", ":(exclude)src/bip39_english.h", ":(exclude)src/dashbls/", ":(exclude)src/crc32c/", ":(exclude)src/crypto/", ":(exclude)src/ctpl_stl.h", ":(exclude)src/cxxtimer.hpp", ":(exclude)src/util/expected.h", ":(exclude)src/immer/", ":(exclude)src/leveldb/", ":(exclude)src/qt/locale/", ":(exclude)src/qt/*.qrc", ":(exclude)src/secp256k1/", ":(exclude)src/minisketch/", ":(exclude)src/univalue/", ":(exclude)contrib/builder-keys/", ":(exclude)contrib/guix/patches"] +FILES_ARGS = ['git', 'ls-files', '--', ":(exclude)build-aux/m4/", ":(exclude)contrib/seeds/*.txt", ":(exclude)depends/", ":(exclude)doc/release-notes/", ":(exclude)src/bip39_english.h", ":(exclude)src/dashbls/", ":(exclude)src/crc32c/", ":(exclude)src/crypto/", ":(exclude)src/ctpl_stl.h", ":(exclude)src/cxxtimer.hpp", ":(exclude)src/util/expected.h", ":(exclude)src/immer/", ":(exclude)src/leveldb/", ":(exclude)src/qt/locale/", ":(exclude)src/qt/*.qrc", ":(exclude)src/secp256k1/", ":(exclude)src/minisketch/", ":(exclude)contrib/builder-keys/", ":(exclude)contrib/guix/patches"] def check_codespell_install(): diff --git a/test/lint/lint-whitespace.py b/test/lint/lint-whitespace.py index a674ef514408..a0e1f0636a2b 100755 --- a/test/lint/lint-whitespace.py +++ b/test/lint/lint-whitespace.py @@ -22,7 +22,6 @@ "src/crc32c/", "src/secp256k1/", "src/minisketch/", - "src/univalue/", "src/dashbls/", "src/immer/", "src/util/expected.h", From d980870301f3d060cf040825e8f76a53a090f039 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 05:00:13 +0000 Subject: [PATCH 09/19] revert: revert bitcoin#25464 (Reduce Univalue push_backV peak memory usage in listtransactions) reverts: - 780961a6152ccb109f9c51bf54dd7209df9b8f6. --- src/univalue/include/univalue.h | 10 ++++++++++ src/wallet/rpc/transactions.cpp | 12 ++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 22be0311e835..7f9a6aaffd98 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -84,6 +84,8 @@ class UniValue { bool push_back(const UniValue& val); bool push_backV(const std::vector& vec); + template + bool push_backV(It first, It last); void __pushKV(const std::string& key, const UniValue& val); bool pushKV(const std::string& key, const UniValue& val); @@ -137,6 +139,14 @@ class UniValue { friend const UniValue& find_value( const UniValue& obj, const std::string& name); }; +template +bool UniValue::push_backV(It first, It last) +{ + if (typ != VARR) return false; + values.insert(values.end(), first, last); + return true; +} + enum jtokentype { JTOK_ERR = -1, JTOK_NONE = 0, // eof diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index a34ba38733d5..75588ecf8c00 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -329,11 +329,12 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) * @param wtx The wallet transaction. * @param nMinDepth The minimum confirmation depth. * @param fLong Whether to include the JSON version of the transaction. - * @param ret The UniValue into which the result is stored. + * @param ret The vector into which the result is stored. * @param filter_ismine The "is mine" filter flags. * @param filter_label Optional label string to filter incoming transactions. */ -static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) +template +static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong, Vec& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { CAmount nFee; std::list listReceived; @@ -520,8 +521,7 @@ RPCHelpMan listtransactions() if (nFrom < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); - UniValue ret(UniValue::VARR); - + std::vector ret; { LOCK(pwallet->cs_wallet); @@ -543,9 +543,9 @@ RPCHelpMan listtransactions() if ((nFrom + nCount) > (int)ret.size()) nCount = ret.size() - nFrom; - const std::vector& txs = ret.getValues(); + auto txs_rev_it{std::make_move_iterator(ret.rend())}; UniValue result{UniValue::VARR}; - result.push_backV({ txs.rend() - nFrom - nCount, txs.rend() - nFrom }); // Return oldest to newest + result.push_backV(txs_rev_it - nFrom - nCount, txs_rev_it - nFrom); // Return oldest to newest return result; }, }; From 94bbbf1b4fc323d833ad1aeb511c2f71996ec675 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 6 Jul 2022 11:46:41 +0200 Subject: [PATCH 10/19] partial bitcoin#25551: Throw exception on invalid Univalue pushes over silent ignore excludes: - ccccc17b91 (impacts code that is SegWit-specific) --- src/univalue/include/univalue.h | 15 +++++---- src/univalue/lib/univalue.cpp | 28 ++++++----------- src/univalue/test/object.cpp | 54 +++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 48 deletions(-) diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 7f9a6aaffd98..5cb8268472ff 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -82,14 +82,14 @@ class UniValue { bool isArray() const { return (typ == VARR); } bool isObject() const { return (typ == VOBJ); } - bool push_back(const UniValue& val); - bool push_backV(const std::vector& vec); + void push_back(const UniValue& val); + void push_backV(const std::vector& vec); template - bool push_backV(It first, It last); + void push_backV(It first, It last); void __pushKV(const std::string& key, const UniValue& val); - bool pushKV(const std::string& key, const UniValue& val); - bool pushKVs(const UniValue& obj); + void pushKV(const std::string& key, const UniValue& val); + void pushKVs(const UniValue& obj); std::string write(unsigned int prettyIndent = 0, unsigned int indentLevel = 0) const; @@ -140,11 +140,10 @@ class UniValue { }; template -bool UniValue::push_backV(It first, It last) +void UniValue::push_backV(It first, It last) { - if (typ != VARR) return false; + if (typ != VARR) throw std::runtime_error{"JSON value is not an array as expected"}; values.insert(values.end(), first, last); - return true; } enum jtokentype { diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index 3553995c28f4..ac6f31a5a979 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -108,53 +108,45 @@ bool UniValue::setObject() return true; } -bool UniValue::push_back(const UniValue& val_) +void UniValue::push_back(const UniValue& val_) { - if (typ != VARR) - return false; + if (typ != VARR) throw std::runtime_error{"JSON value is not an array as expected"}; values.push_back(val_); - return true; } -bool UniValue::push_backV(const std::vector& vec) +void UniValue::push_backV(const std::vector& vec) { - if (typ != VARR) - return false; + if (typ != VARR) throw std::runtime_error{"JSON value is not an array as expected"}; values.insert(values.end(), vec.begin(), vec.end()); - - return true; } void UniValue::__pushKV(const std::string& key, const UniValue& val_) { + if (typ != VOBJ) throw std::runtime_error{"JSON value is not an object as expected"}; + keys.push_back(key); values.push_back(val_); } -bool UniValue::pushKV(const std::string& key, const UniValue& val_) +void UniValue::pushKV(const std::string& key, const UniValue& val_) { - if (typ != VOBJ) - return false; + if (typ != VOBJ) throw std::runtime_error{"JSON value is not an object as expected"}; size_t idx; if (findKey(key, idx)) values[idx] = val_; else __pushKV(key, val_); - return true; } -bool UniValue::pushKVs(const UniValue& obj) +void UniValue::pushKVs(const UniValue& obj) { - if (typ != VOBJ || obj.typ != VOBJ) - return false; + if (typ != VOBJ || obj.typ != VOBJ) throw std::runtime_error{"JSON value is not an object as expected"}; for (size_t i = 0; i < obj.keys.size(); i++) __pushKV(obj.keys[i], obj.values.at(i)); - - return true; } void UniValue::getObjMap(std::map& kv) const diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index 8a35bf914daa..196b53616423 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -85,6 +85,16 @@ BOOST_AUTO_TEST_CASE(univalue_constructor) BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); } +BOOST_AUTO_TEST_CASE(univalue_push_throw) +{ + UniValue j; + BOOST_CHECK_THROW(j.push_back(1), std::runtime_error); + BOOST_CHECK_THROW(j.push_backV({1}), std::runtime_error); + BOOST_CHECK_THROW(j.__pushKV("k", 1), std::runtime_error); + BOOST_CHECK_THROW(j.pushKV("k", 1), std::runtime_error); + BOOST_CHECK_THROW(j.pushKVs({}), std::runtime_error); +} + BOOST_AUTO_TEST_CASE(univalue_typecheck) { UniValue v1; @@ -198,13 +208,13 @@ BOOST_AUTO_TEST_CASE(univalue_array) UniValue arr(UniValue::VARR); UniValue v((int64_t)1023LL); - BOOST_CHECK(arr.push_back(v)); + arr.push_back(v); std::string vStr("zippy"); - BOOST_CHECK(arr.push_back(vStr)); + arr.push_back(vStr); const char *s = "pippy"; - BOOST_CHECK(arr.push_back(s)); + arr.push_back(s); std::vector vec; v.setStr("boing"); @@ -213,13 +223,13 @@ BOOST_AUTO_TEST_CASE(univalue_array) v.setStr("going"); vec.push_back(v); - BOOST_CHECK(arr.push_backV(vec)); + arr.push_backV(vec); - BOOST_CHECK(arr.push_back((uint64_t) 400ULL)); - BOOST_CHECK(arr.push_back((int64_t) -400LL)); - BOOST_CHECK(arr.push_back((int) -401)); - BOOST_CHECK(arr.push_back(-40.1)); - BOOST_CHECK(arr.push_back(true)); + arr.push_back(uint64_t{400ULL}); + arr.push_back(int64_t{-400LL}); + arr.push_back(int{-401}); + arr.push_back(-40.1); + arr.push_back(true); BOOST_CHECK_EQUAL(arr.empty(), false); BOOST_CHECK_EQUAL(arr.size(), 10); @@ -260,39 +270,39 @@ BOOST_AUTO_TEST_CASE(univalue_object) strKey = "age"; v.setInt(100); - BOOST_CHECK(obj.pushKV(strKey, v)); + obj.pushKV(strKey, v); strKey = "first"; strVal = "John"; - BOOST_CHECK(obj.pushKV(strKey, strVal)); + obj.pushKV(strKey, strVal); strKey = "last"; - const char *cVal = "Smith"; - BOOST_CHECK(obj.pushKV(strKey, cVal)); + const char* cVal = "Smith"; + obj.pushKV(strKey, cVal); strKey = "distance"; - BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25)); + obj.pushKV(strKey, int64_t{25}); strKey = "time"; - BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600)); + obj.pushKV(strKey, uint64_t{3600}); strKey = "calories"; - BOOST_CHECK(obj.pushKV(strKey, (int) 12)); + obj.pushKV(strKey, int{12}); strKey = "temperature"; - BOOST_CHECK(obj.pushKV(strKey, (double) 90.012)); + obj.pushKV(strKey, double{90.012}); strKey = "moon"; - BOOST_CHECK(obj.pushKV(strKey, true)); + obj.pushKV(strKey, true); strKey = "spoon"; - BOOST_CHECK(obj.pushKV(strKey, false)); + obj.pushKV(strKey, false); UniValue obj2(UniValue::VOBJ); - BOOST_CHECK(obj2.pushKV("cat1", 9000)); - BOOST_CHECK(obj2.pushKV("cat2", 12345)); + obj2.pushKV("cat1", 9000); + obj2.pushKV("cat2", 12345); - BOOST_CHECK(obj.pushKVs(obj2)); + obj.pushKVs(obj2); BOOST_CHECK_EQUAL(obj.empty(), false); BOOST_CHECK_EQUAL(obj.size(), 11); From 7802752bd5a0fe028aedc43455318a95b7d3e912 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Thu, 14 Jul 2022 16:40:40 +0100 Subject: [PATCH 11/19] merge bitcoin#25617: univalue test cleanups --- ci/test/wrap-wine.sh | 2 +- src/Makefile.test.include | 7 +------ src/univalue/sources.mk | 9 +-------- src/univalue/test/.gitignore | 1 - src/univalue/test/no_nul.cpp | 8 -------- src/univalue/test/object.cpp | 22 ++++++++-------------- src/univalue/test/unitester.cpp | 8 ++++++++ 7 files changed, 19 insertions(+), 38 deletions(-) delete mode 100644 src/univalue/test/no_nul.cpp diff --git a/ci/test/wrap-wine.sh b/ci/test/wrap-wine.sh index 525db9eded56..1662f8f6a335 100755 --- a/ci/test/wrap-wine.sh +++ b/ci/test/wrap-wine.sh @@ -6,7 +6,7 @@ export LC_ALL=C.UTF-8 -for b_name in {"${BASE_OUTDIR}/bin"/*,src/secp256k1/*tests,src/minisketch/test{,-verify},src/univalue/{no_nul,test_json,unitester,object}}.exe; do +for b_name in {"${BASE_OUTDIR}/bin"/*,src/secp256k1/*tests,src/minisketch/test{,-verify},src/univalue/{test_json,unitester,object}}.exe; do # shellcheck disable=SC2044 for b in $(find "${BASE_ROOT_DIR}" -executable -type f -name "$(basename "$b_name")"); do if (file "$b" | grep "Windows"); then diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 8375969549ae..0dbd466722ee 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -405,7 +405,7 @@ endif $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if ENABLE_TESTS -UNIVALUE_TESTS = univalue/test/object univalue/test/unitester univalue/test/no_nul +UNIVALUE_TESTS = univalue/test/object univalue/test/unitester noinst_PROGRAMS += $(UNIVALUE_TESTS) TESTS += $(UNIVALUE_TESTS) @@ -414,11 +414,6 @@ univalue_test_unitester_LDADD = $(LIBUNIVALUE) univalue_test_unitester_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) -DJSON_TEST_SRC=\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\" univalue_test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) -univalue_test_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT) -univalue_test_no_nul_LDADD = $(LIBUNIVALUE) -univalue_test_no_nul_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) -univalue_test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - univalue_test_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT) univalue_test_object_LDADD = $(LIBUNIVALUE) univalue_test_object_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) diff --git a/src/univalue/sources.mk b/src/univalue/sources.mk index e156216378b1..5e4d9c383199 100644 --- a/src/univalue/sources.mk +++ b/src/univalue/sources.mk @@ -1,12 +1,8 @@ -# - All variables are namespaced with UNIVALUE_ to avoid colliding with -# downstream makefiles. # - All Variables ending in _HEADERS or _SOURCES confuse automake, so the # _INT postfix is applied. # - Convenience variables, for example a UNIVALUE_TEST_DIR should not be used # as they interfere with automatic dependency generation -# - The %reldir% is the relative path from the Makefile.am. This allows -# downstreams to use these variables without having to manually account for -# the path change. +# - The %reldir% is the relative path from the Makefile.am. UNIVALUE_INCLUDE_DIR_INT = %reldir%/include @@ -29,9 +25,6 @@ UNIVALUE_TEST_UNITESTER_INT += %reldir%/test/unitester.cpp UNIVALUE_TEST_JSON_INT = UNIVALUE_TEST_JSON_INT += %reldir%/test/test_json.cpp -UNIVALUE_TEST_NO_NUL_INT = -UNIVALUE_TEST_NO_NUL_INT += %reldir%/test/no_nul.cpp - UNIVALUE_TEST_OBJECT_INT = UNIVALUE_TEST_OBJECT_INT += %reldir%/test/object.cpp diff --git a/src/univalue/test/.gitignore b/src/univalue/test/.gitignore index 7b27cf0da290..5812c96b1434 100644 --- a/src/univalue/test/.gitignore +++ b/src/univalue/test/.gitignore @@ -2,7 +2,6 @@ object unitester test_json -no_nul *.trs *.log diff --git a/src/univalue/test/no_nul.cpp b/src/univalue/test/no_nul.cpp deleted file mode 100644 index 3a7a727abbd5..000000000000 --- a/src/univalue/test/no_nul.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int main (int argc, char *argv[]) -{ - char buf[] = "___[1,2,3]___"; - UniValue val; - return val.read(buf + 3, 7) ? 0 : 1; -} diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index 196b53616423..cf8c29ec6750 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -13,9 +13,6 @@ #include #include -#define BOOST_FIXTURE_TEST_SUITE(a, b) -#define BOOST_AUTO_TEST_CASE(funcName) void funcName() -#define BOOST_AUTO_TEST_SUITE_END() #define BOOST_CHECK(expr) assert(expr) #define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2)) #define BOOST_CHECK_THROW(stmt, excMatch) { \ @@ -35,9 +32,7 @@ } \ } -BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(univalue_constructor) +void univalue_constructor() { UniValue v1; BOOST_CHECK(v1.isNull()); @@ -85,7 +80,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor) BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); } -BOOST_AUTO_TEST_CASE(univalue_push_throw) +void univalue_push_throw() { UniValue j; BOOST_CHECK_THROW(j.push_back(1), std::runtime_error); @@ -95,7 +90,7 @@ BOOST_AUTO_TEST_CASE(univalue_push_throw) BOOST_CHECK_THROW(j.pushKVs({}), std::runtime_error); } -BOOST_AUTO_TEST_CASE(univalue_typecheck) +void univalue_typecheck() { UniValue v1; BOOST_CHECK(v1.setNumStr("1")); @@ -144,7 +139,7 @@ BOOST_AUTO_TEST_CASE(univalue_typecheck) BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); } -BOOST_AUTO_TEST_CASE(univalue_set) +void univalue_set() { UniValue v(UniValue::VSTR, "foo"); v.clear(); @@ -203,7 +198,7 @@ BOOST_AUTO_TEST_CASE(univalue_set) BOOST_CHECK(v.isNull()); } -BOOST_AUTO_TEST_CASE(univalue_array) +void univalue_array() { UniValue arr(UniValue::VARR); @@ -262,7 +257,7 @@ BOOST_AUTO_TEST_CASE(univalue_array) BOOST_CHECK_EQUAL(arr.size(), 0); } -BOOST_AUTO_TEST_CASE(univalue_object) +void univalue_object() { UniValue obj(UniValue::VOBJ); std::string strKey, strVal; @@ -381,7 +376,7 @@ BOOST_AUTO_TEST_CASE(univalue_object) static const char *json1 = "[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]"; -BOOST_AUTO_TEST_CASE(univalue_readwrite) +void univalue_readwrite() { UniValue v; BOOST_CHECK(v.read(json1)); @@ -424,11 +419,10 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite) BOOST_CHECK(!v.read("{} 42")); } -BOOST_AUTO_TEST_SUITE_END() - int main (int argc, char *argv[]) { univalue_constructor(); + univalue_push_throw(); univalue_typecheck(); univalue_set(); univalue_array(); diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp index 94c149b39fd7..6344a5a0ab8a 100644 --- a/src/univalue/test/unitester.cpp +++ b/src/univalue/test/unitester.cpp @@ -149,6 +149,13 @@ void unescape_unicode_test() assert(val[0].get_str() == "\xf0\x9d\x85\xa1"); } +void no_nul_test() +{ + char buf[] = "___[1,2,3]___"; + UniValue val; + assert(val.read(buf + 3, 7)); +} + int main (int argc, char *argv[]) { for (const auto& f: filenames) { @@ -156,6 +163,7 @@ int main (int argc, char *argv[]) } unescape_unicode_test(); + no_nul_test(); return 0; } From 32958daf50306db2de4fcbe9624398a3c20aaadf Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Thu, 14 Jul 2022 11:20:31 +0200 Subject: [PATCH 12/19] merge bitcoin#25611: Avoid brittle, narrowing and verbose integral type confusions --- src/rpc/net.cpp | 14 ++++++------ src/univalue/include/univalue.h | 40 ++++++++++++++++----------------- src/wallet/rpc/wallet.cpp | 2 +- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index b92e2b74c755..6cb93c9c534d 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -66,7 +66,7 @@ static RPCHelpMan getconnectioncount() const NodeContext& node = EnsureAnyNodeContext(request.context); const CConnman& connman = EnsureConnman(node); - return (int)connman.GetNodeCount(ConnectionDirection::Both); + return connman.GetNodeCount(ConnectionDirection::Both); }, }; } @@ -684,12 +684,12 @@ static RPCHelpMan getnetworkinfo() obj.pushKV("timeoffset", GetTimeOffset()); if (node.connman) { obj.pushKV("networkactive", node.connman->GetNetworkActive()); - obj.pushKV("connections", (int)node.connman->GetNodeCount(ConnectionDirection::Both)); - obj.pushKV("connections_in", (int)node.connman->GetNodeCount(ConnectionDirection::In)); - obj.pushKV("connections_out", (int)node.connman->GetNodeCount(ConnectionDirection::Out)); - obj.pushKV("connections_mn", (int)node.connman->GetNodeCount(ConnectionDirection::Verified)); - obj.pushKV("connections_mn_in", (int)node.connman->GetNodeCount(ConnectionDirection::VerifiedIn)); - obj.pushKV("connections_mn_out", (int)node.connman->GetNodeCount(ConnectionDirection::VerifiedOut)); + obj.pushKV("connections", node.connman->GetNodeCount(ConnectionDirection::Both)); + obj.pushKV("connections_in", node.connman->GetNodeCount(ConnectionDirection::In)); + obj.pushKV("connections_out", node.connman->GetNodeCount(ConnectionDirection::Out)); + obj.pushKV("connections_mn", node.connman->GetNodeCount(ConnectionDirection::Verified)); + obj.pushKV("connections_mn_in", node.connman->GetNodeCount(ConnectionDirection::VerifiedIn)); + obj.pushKV("connections_mn_out", node.connman->GetNodeCount(ConnectionDirection::VerifiedOut)); std::string_view sem_str = SEMToString(node.connman->GetSocketEventsMode()); CHECK_NONFATAL(sem_str != "unknown"); obj.pushKV("socketevents", std::string(sem_str)); diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 5cb8268472ff..7b5843602ce5 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -24,27 +24,25 @@ class UniValue { typ = initialType; val = initialStr; } - UniValue(uint64_t val_) { - setInt(val_); - } - UniValue(int64_t val_) { - setInt(val_); - } - UniValue(bool val_) { - setBool(val_); - } - UniValue(int val_) { - setInt(val_); - } - UniValue(double val_) { - setFloat(val_); - } - UniValue(const std::string& val_) { - setStr(val_); - } - UniValue(const char *val_) { - std::string s(val_); - setStr(s); + template >, + std::enable_if_t || // setFloat + std::is_same_v || // setBool + std::is_signed_v || std::is_unsigned_v || // setInt + std::is_constructible_v, // setStr + bool> = true> + UniValue(Ref&& val) + { + if constexpr (std::is_floating_point_v) { + setFloat(val); + } else if constexpr (std::is_same_v) { + setBool(val); + } else if constexpr (std::is_signed_v) { + setInt(int64_t{val}); + } else if constexpr (std::is_unsigned_v) { + setInt(uint64_t{val}); + } else { + setStr(std::string{std::forward(val)}); + } } void clear(); diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index d90004c01d18..a5a2ec7cb2f9 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -858,7 +858,7 @@ static RPCHelpMan upgradewallet() "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n" "New keys may be generated and a new wallet backup will need to be made.", { - {"version", RPCArg::Type::NUM, RPCArg::Default{FEATURE_LATEST}, "The version number to upgrade to. Default is the latest wallet version."} + {"version", RPCArg::Type::NUM, RPCArg::Default{int{FEATURE_LATEST}}, "The version number to upgrade to. Default is the latest wallet version."} }, RPCResult{ RPCResult::Type::OBJ, "", "", From 27cffb13e8da95be316bf519a4594646d1803f6b Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 05:36:09 +0000 Subject: [PATCH 13/19] refactor: shed avoidable casts in Dash-specific UniValue-ret functions --- src/core_write.cpp | 4 ++-- src/evo/core_write.cpp | 26 ++++++++++++++------------ src/evo/deterministicmns.cpp | 2 +- src/governance/governance.cpp | 6 +++--- src/llmq/commitment.h | 2 +- src/rpc/governance.cpp | 2 +- src/rpc/masternode.cpp | 2 +- src/rpc/mempool.cpp | 4 ++-- src/rpc/node.cpp | 10 +++++----- src/rpc/quorums.cpp | 4 ++-- src/wallet/rpc/backup.cpp | 4 ++-- src/wallet/rpc/wallet.cpp | 19 ++++++++++--------- 12 files changed, 44 insertions(+), 41 deletions(-) diff --git a/src/core_write.cpp b/src/core_write.cpp index f57f28f5aca9..575c8c143945 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -270,7 +270,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry if (it != ptxSpentInfo->mSpentInfo.end()) { auto spentInfo = it->second; out.pushKV("spentTxId", spentInfo.m_tx_hash.GetHex()); - out.pushKV("spentIndex", (int)spentInfo.m_tx_index); + out.pushKV("spentIndex", spentInfo.m_tx_index); out.pushKV("spentHeight", spentInfo.m_block_height); } } @@ -283,7 +283,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry entry.pushKV("vout", vout); if (!tx.vExtraPayload.empty()) { - entry.pushKV("extraPayloadSize", (int)tx.vExtraPayload.size()); + entry.pushKV("extraPayloadSize", tx.vExtraPayload.size()); entry.pushKV("extraPayload", HexStr(tx.vExtraPayload)); } diff --git a/src/evo/core_write.cpp b/src/evo/core_write.cpp index 828b7938881d..e61c82d8bdc0 100644 --- a/src/evo/core_write.cpp +++ b/src/evo/core_write.cpp @@ -3,6 +3,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include + #include #include #include @@ -28,7 +30,7 @@ } UniValue ret(UniValue::VOBJ); - ret.pushKV("version", int(nVersion)); + ret.pushKV("version", nVersion); ret.pushKV("creditOutputs", outputs); return ret; } @@ -36,10 +38,10 @@ [[nodiscard]] UniValue CAssetUnlockPayload::ToJson() const { UniValue ret(UniValue::VOBJ); - ret.pushKV("version", int(nVersion)); - ret.pushKV("index", int(index)); - ret.pushKV("fee", int(fee)); - ret.pushKV("requestedHeight", int(requestedHeight)); + ret.pushKV("version", nVersion); + ret.pushKV("index", index); + ret.pushKV("fee", fee); + ret.pushKV("requestedHeight", requestedHeight); ret.pushKV("quorumHash", quorumHash.ToString()); ret.pushKV("quorumSig", quorumSig.ToString()); return ret; @@ -48,13 +50,13 @@ [[nodiscard]] UniValue CCbTx::ToJson() const { UniValue ret(UniValue::VOBJ); - ret.pushKV("version", (int)nVersion); + ret.pushKV("version", ToUnderlying(nVersion)); ret.pushKV("height", nHeight); ret.pushKV("merkleRootMNList", merkleRootMNList.ToString()); if (nVersion >= CCbTx::Version::MERKLE_ROOT_QUORUMS) { ret.pushKV("merkleRootQuorums", merkleRootQuorums.ToString()); if (nVersion >= CCbTx::Version::CLSIG_AND_BALANCE) { - ret.pushKV("bestCLHeightDiff", static_cast(bestCLHeightDiff)); + ret.pushKV("bestCLHeightDiff", bestCLHeightDiff); ret.pushKV("bestCLSignature", bestCLSignature.ToString()); ret.pushKV("creditPoolBalance", ValueFromAmount(creditPoolBalance)); } @@ -68,7 +70,7 @@ ret.pushKV("version", nVersion); ret.pushKV("type", ToUnderlying(nType)); ret.pushKV("collateralHash", collateralOutpoint.hash.ToString()); - ret.pushKV("collateralIndex", (int)collateralOutpoint.n); + ret.pushKV("collateralIndex", collateralOutpoint.n); if (IsServiceDeprecatedRPCEnabled()) { ret.pushKV("service", netInfo->GetPrimary().ToStringAddrPort()); } @@ -108,7 +110,7 @@ UniValue ret(UniValue::VOBJ); ret.pushKV("version", nVersion); ret.pushKV("proTxHash", proTxHash.ToString()); - ret.pushKV("reason", (int)nReason); + ret.pushKV("reason", nReason); ret.pushKV("inputsHash", inputsHash.ToString()); return ret; } @@ -138,7 +140,7 @@ [[nodiscard]] UniValue MNHFTxPayload::ToJson() const { UniValue ret(UniValue::VOBJ); - ret.pushKV("version", (int)nVersion); + ret.pushKV("version", nVersion); ret.pushKV("signal", signal.ToJson()); return ret; } @@ -146,8 +148,8 @@ [[nodiscard]] UniValue llmq::CFinalCommitmentTxPayload::ToJson() const { UniValue ret(UniValue::VOBJ); - ret.pushKV("version", int{nVersion}); - ret.pushKV("height", int(nHeight)); + ret.pushKV("version", nVersion); + ret.pushKV("height", nHeight); ret.pushKV("commitment", commitment.ToJson()); return ret; } diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 4554944b41ba..1983b34ea2cf 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -56,7 +56,7 @@ UniValue CDeterministicMN::ToJson() const obj.pushKV("type", std::string(GetMnType(nType).description)); obj.pushKV("proTxHash", proTxHash.ToString()); obj.pushKV("collateralHash", collateralOutpoint.hash.ToString()); - obj.pushKV("collateralIndex", (int)collateralOutpoint.n); + obj.pushKV("collateralIndex", collateralOutpoint.n); if (g_txindex) { CTransactionRef collateralTx; diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 88804db50912..91adfe6a9255 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -1504,12 +1504,12 @@ UniValue CGovernanceManager::ToJson() const } UniValue jsonObj(UniValue::VOBJ); - jsonObj.pushKV("objects_total", (int)mapObjects.size()); + jsonObj.pushKV("objects_total", mapObjects.size()); jsonObj.pushKV("proposals", nProposalCount); jsonObj.pushKV("triggers", nTriggerCount); jsonObj.pushKV("other", nOtherCount); - jsonObj.pushKV("erased", (int)mapErasedGovernanceObjects.size()); - jsonObj.pushKV("votes", (int)cmapVoteToObject.GetSize()); + jsonObj.pushKV("erased", mapErasedGovernanceObjects.size()); + jsonObj.pushKV("votes", cmapVoteToObject.GetSize()); return jsonObj; } diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index ca55131c9665..1569e59694fc 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -122,7 +122,7 @@ class CFinalCommitment [[nodiscard]] UniValue ToJson() const { UniValue obj(UniValue::VOBJ); - obj.pushKV("version", int{nVersion}); + obj.pushKV("version", nVersion); obj.pushKV("llmqType", ToUnderlying(llmqType)); obj.pushKV("quorumHash", quorumHash.ToString()); obj.pushKV("quorumIndex", quorumIndex); diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index 27b147c21e77..0ab365dd9e3d 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -1018,7 +1018,7 @@ static RPCHelpMan getgovernanceinfo() obj.pushKV("superblockmaturitywindow", Params().GetConsensus().nSuperblockMaturityWindow); obj.pushKV("lastsuperblock", nLastSuperblock); obj.pushKV("nextsuperblock", nNextSuperblock); - obj.pushKV("fundingthreshold", int(CHECK_NONFATAL(node.dmnman)->GetListAtChainTip().GetValidWeightedMNsCount() / 10)); + obj.pushKV("fundingthreshold", CHECK_NONFATAL(node.dmnman)->GetListAtChainTip().GetValidWeightedMNsCount() / 10); obj.pushKV("governancebudget", ValueFromAmount(CSuperblock::GetPaymentsLimit(chainman.ActiveChain(), nNextSuperblock))); return obj; diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 266845d3e90d..46131ea785a0 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -180,7 +180,7 @@ static RPCHelpMan masternode_status() mnObj.pushKV("proTxHash", dmn->proTxHash.ToString()); mnObj.pushKV("type", std::string(GetMnType(dmn->nType).description)); mnObj.pushKV("collateralHash", dmn->collateralOutpoint.hash.ToString()); - mnObj.pushKV("collateralIndex", (int)dmn->collateralOutpoint.n); + mnObj.pushKV("collateralIndex", dmn->collateralOutpoint.n); mnObj.pushKV("dmnState", dmn->pdmnState->ToJson(dmn->nType)); } mnObj.pushKV("state", node.mn_activeman->GetStateString()); diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 1e3d67c3ea70..ab527f39f824 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -395,8 +395,8 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool, const llmq::CInstantSendManag ret.pushKV("maxmempool", maxmempool); ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK())); ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())); - ret.pushKV("instantsendlocks", (int64_t)isman.GetInstantSendLockCount()); - ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()}); + ret.pushKV("instantsendlocks", isman.GetInstantSendLockCount()); + ret.pushKV("unbroadcastcount", pool.GetUnbroadcastTxs().size()); return ret; } diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index f8828f11550e..7a062af65531 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -435,12 +435,12 @@ static RPCHelpMan getaddressmempool() UniValue delta(UniValue::VOBJ); delta.pushKV("address", address); delta.pushKV("txid", mempoolAddressKey.m_tx_hash.GetHex()); - delta.pushKV("index", (int)mempoolAddressKey.m_tx_index); + delta.pushKV("index", mempoolAddressKey.m_tx_index); delta.pushKV("satoshis", mempoolAddressDelta.m_amount); delta.pushKV("timestamp", count_seconds(mempoolAddressDelta.m_time)); if (mempoolAddressDelta.m_amount < 0) { delta.pushKV("prevtxid", mempoolAddressDelta.m_prev_hash.GetHex()); - delta.pushKV("prevout", (int)mempoolAddressDelta.m_prev_out); + delta.pushKV("prevout", mempoolAddressDelta.m_prev_out); } result.push_back(delta); } @@ -509,7 +509,7 @@ static RPCHelpMan getaddressutxos() output.pushKV("address", address); output.pushKV("txid", unspentKey.m_tx_hash.GetHex()); - output.pushKV("outputIndex", (int)unspentKey.m_tx_index); + output.pushKV("outputIndex", unspentKey.m_tx_index); output.pushKV("script", HexStr(unspentValue.m_tx_script)); output.pushKV("satoshis", unspentValue.m_amount); output.pushKV("height", unspentValue.m_block_height); @@ -596,8 +596,8 @@ static RPCHelpMan getaddressdeltas() UniValue delta(UniValue::VOBJ); delta.pushKV("satoshis", indexDelta); delta.pushKV("txid", indexKey.m_tx_hash.GetHex()); - delta.pushKV("index", (int)indexKey.m_tx_index); - delta.pushKV("blockindex", (int)indexKey.m_block_tx_pos); + delta.pushKV("index", indexKey.m_tx_index); + delta.pushKV("blockindex", indexKey.m_block_tx_pos); delta.pushKV("height", indexKey.m_block_height); delta.pushKV("address", address); result.push_back(delta); diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index 6e8c93f86317..05fc271ef3de 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -164,7 +164,7 @@ static RPCHelpMan quorum_list_extended() } j.pushKV("creationHeight", q->m_quorum_base_block_index->nHeight); j.pushKV("minedBlockHash", q->minedBlockHash.ToString()); - j.pushKV("numValidMembers", (int32_t)num_valid_members); + j.pushKV("numValidMembers", num_valid_members); j.pushKV("healthRatio", ss.str()); obj.pushKV(q->qc->quorumHash.ToString(),j); } @@ -916,7 +916,7 @@ static RPCHelpMan quorum_dkginfo() llmq::CDKGDebugStatus status; llmq_ctx.dkg_debugman->GetLocalDebugStatus(status); UniValue ret(UniValue::VOBJ); - ret.pushKV("active_dkgs", int(status.sessions.size())); + ret.pushKV("active_dkgs", status.sessions.size()); const int nTipHeight{WITH_LOCK(cs_main, return chainman.ActiveChain().Height())}; auto minNextDKG = [](const Consensus::Params& consensusParams, int nTipHeight) { diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index d72cefaff7d4..af293c83b3d7 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -1043,7 +1043,7 @@ RPCHelpMan dumpwallet() file << "# WARNING: ACCOUNT " << i << " IS MISSING!" << "\n\n"; } } - obj.pushKV("hdaccounts", int(hdChainCurrent.CountAccounts())); + obj.pushKV("hdaccounts", hdChainCurrent.CountAccounts()); } for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { @@ -1087,7 +1087,7 @@ RPCHelpMan dumpwallet() file.close(); std::string strWarning = strprintf(_("%s file contains all private keys from this wallet. Do not share it with anyone!").translated, request.params[0].get_str()); - obj.pushKV("keys", int(vKeyBirth.size())); + obj.pushKV("keys", vKeyBirth.size()); obj.pushKV("filename", filepath.utf8string()); obj.pushKV("warning", strWarning); diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index a5a2ec7cb2f9..38597ef270d3 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -232,24 +232,25 @@ static RPCHelpMan getwalletinfo() obj.pushKV("keypoololdest", kp_oldest.value()); } size_t kpExternalSize = pwallet->KeypoolCountExternalKeys(); - obj.pushKV("keypoolsize", (int64_t)kpExternalSize); - obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize)); - obj.pushKV("keys_left", pwallet->nKeysLeftSinceAutoBackup); - if (pwallet->IsCrypted()) + obj.pushKV("keypoolsize", kpExternalSize); + obj.pushKV("keypoolsize_hd_internal", pwallet->GetKeyPoolSize() - kpExternalSize); + obj.pushKV("keys_left", pwallet->nKeysLeftSinceAutoBackup); + if (pwallet->IsCrypted()) { obj.pushKV("unlocked_until", pwallet->nRelockTime); - obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK())); + } + obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK())); if (fHDEnabled) { obj.pushKV("hdchainid", hdChainCurrent.GetID().GetHex()); - obj.pushKV("hdaccountcount", (int64_t)hdChainCurrent.CountAccounts()); + obj.pushKV("hdaccountcount", hdChainCurrent.CountAccounts()); UniValue accounts(UniValue::VARR); for (size_t i = 0; i < hdChainCurrent.CountAccounts(); ++i) { CHDAccount acc; UniValue account(UniValue::VOBJ); - account.pushKV("hdaccountindex", (int64_t)i); + account.pushKV("hdaccountindex", i); if(hdChainCurrent.GetAccount(i, acc)) { - account.pushKV("hdexternalkeyindex", (int64_t)acc.nExternalChainCounter); - account.pushKV("hdinternalkeyindex", (int64_t)acc.nInternalChainCounter); + account.pushKV("hdexternalkeyindex", acc.nExternalChainCounter); + account.pushKV("hdinternalkeyindex", acc.nInternalChainCounter); } else { account.pushKV("error", strprintf("account %d is missing", i)); } From 6f03a13e577b42b8a411b79baa31b6929c17a996 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:23:04 +0200 Subject: [PATCH 14/19] merge bitcoin#25736: Remove unused and confusing set*() return value --- src/test/rpc_tests.cpp | 4 +-- src/univalue/include/univalue.h | 20 +++++++-------- src/univalue/lib/univalue.cpp | 33 ++++++++++-------------- src/univalue/test/object.cpp | 45 ++++++++++++++++----------------- 4 files changed, 47 insertions(+), 55 deletions(-) diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index ab660dda171c..daaac3de546a 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -252,10 +252,10 @@ BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) BOOST_CHECK_EQUAL(ValueFromAmount(std::numeric_limits::min()).write(), "-92233720368.54775808"); } -static UniValue ValueFromString(const std::string &str) +static UniValue ValueFromString(const std::string& str) noexcept { UniValue value; - BOOST_CHECK(value.setNumStr(str)); + value.setNumStr(str); return value; } diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 7b5843602ce5..241c55e02958 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -47,16 +47,16 @@ class UniValue { void clear(); - bool setNull(); - bool setBool(bool val); - bool setNumStr(const std::string& val); - bool setInt(uint64_t val); - bool setInt(int64_t val); - bool setInt(int val_) { return setInt((int64_t)val_); } - bool setFloat(double val); - bool setStr(const std::string& val); - bool setArray(); - bool setObject(); + void setNull(); + void setBool(bool val); + void setNumStr(const std::string& val); + void setInt(uint64_t val); + void setInt(int64_t val); + void setInt(int val_) { return setInt(int64_t{val_}); } + void setFloat(double val); + void setStr(const std::string& val); + void setArray(); + void setObject(); enum VType getType() const { return typ; } const std::string& getValStr() const { return val; } diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index ac6f31a5a979..9062e4853908 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -23,19 +23,17 @@ void UniValue::clear() values.clear(); } -bool UniValue::setNull() +void UniValue::setNull() { clear(); - return true; } -bool UniValue::setBool(bool val_) +void UniValue::setBool(bool val_) { clear(); typ = VBOOL; if (val_) val = "1"; - return true; } static bool validNumStr(const std::string& s) @@ -46,18 +44,18 @@ static bool validNumStr(const std::string& s) return (tt == JTOK_NUMBER); } -bool UniValue::setNumStr(const std::string& val_) +void UniValue::setNumStr(const std::string& val_) { - if (!validNumStr(val_)) - return false; + if (!validNumStr(val_)) { + throw std::runtime_error{"The string '" + val_ + "' is not a valid JSON number"}; + } clear(); typ = VNUM; val = val_; - return true; } -bool UniValue::setInt(uint64_t val_) +void UniValue::setInt(uint64_t val_) { std::ostringstream oss; @@ -66,7 +64,7 @@ bool UniValue::setInt(uint64_t val_) return setNumStr(oss.str()); } -bool UniValue::setInt(int64_t val_) +void UniValue::setInt(int64_t val_) { std::ostringstream oss; @@ -75,37 +73,32 @@ bool UniValue::setInt(int64_t val_) return setNumStr(oss.str()); } -bool UniValue::setFloat(double val_) +void UniValue::setFloat(double val_) { std::ostringstream oss; oss << std::setprecision(16) << val_; - bool ret = setNumStr(oss.str()); - typ = VNUM; - return ret; + return setNumStr(oss.str()); } -bool UniValue::setStr(const std::string& val_) +void UniValue::setStr(const std::string& val_) { clear(); typ = VSTR; val = val_; - return true; } -bool UniValue::setArray() +void UniValue::setArray() { clear(); typ = VARR; - return true; } -bool UniValue::setObject() +void UniValue::setObject() { clear(); typ = VOBJ; - return true; } void UniValue::push_back(const UniValue& val_) diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index cf8c29ec6750..94d7343ff35c 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -45,7 +45,7 @@ void univalue_constructor() BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); UniValue numTest; - BOOST_CHECK(numTest.setNumStr("82")); + numTest.setNumStr("82"); BOOST_CHECK(numTest.isNum()); BOOST_CHECK_EQUAL(numTest.getValStr(), "82"); @@ -93,33 +93,33 @@ void univalue_push_throw() void univalue_typecheck() { UniValue v1; - BOOST_CHECK(v1.setNumStr("1")); + v1.setNumStr("1"); BOOST_CHECK(v1.isNum()); BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); { UniValue v_negative; - BOOST_CHECK(v_negative.setNumStr("-1")); + v_negative.setNumStr("-1"); BOOST_CHECK_THROW(v_negative.getInt(), std::runtime_error); BOOST_CHECK_EQUAL(v_negative.getInt(), -1); } UniValue v2; - BOOST_CHECK(v2.setBool(true)); + v2.setBool(true); BOOST_CHECK_EQUAL(v2.get_bool(), true); BOOST_CHECK_THROW(v2.getInt(), std::runtime_error); UniValue v3; - BOOST_CHECK(v3.setNumStr("32482348723847471234")); + v3.setNumStr("32482348723847471234"); BOOST_CHECK_THROW(v3.getInt(), std::runtime_error); - BOOST_CHECK(v3.setNumStr("1000")); + v3.setNumStr("1000"); BOOST_CHECK_EQUAL(v3.getInt(), 1000); UniValue v4; - BOOST_CHECK(v4.setNumStr("2147483648")); + v4.setNumStr("2147483648"); BOOST_CHECK_EQUAL(v4.getInt(), 2147483648); BOOST_CHECK_THROW(v4.getInt(), std::runtime_error); - BOOST_CHECK(v4.setNumStr("1000")); + v4.setNumStr("1000"); BOOST_CHECK_EQUAL(v4.getInt(), 1000); BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); BOOST_CHECK_EQUAL(v4.get_real(), 1000); @@ -146,55 +146,55 @@ void univalue_set() BOOST_CHECK(v.isNull()); BOOST_CHECK_EQUAL(v.getValStr(), ""); - BOOST_CHECK(v.setObject()); + v.setObject(); BOOST_CHECK(v.isObject()); BOOST_CHECK_EQUAL(v.size(), 0); BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); BOOST_CHECK(v.empty()); - BOOST_CHECK(v.setArray()); + v.setArray(); BOOST_CHECK(v.isArray()); BOOST_CHECK_EQUAL(v.size(), 0); - BOOST_CHECK(v.setStr("zum")); + v.setStr("zum"); BOOST_CHECK(v.isStr()); BOOST_CHECK_EQUAL(v.getValStr(), "zum"); - BOOST_CHECK(v.setFloat(-1.01)); + v.setFloat(-1.01); BOOST_CHECK(v.isNum()); BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); - BOOST_CHECK(v.setInt((int)1023)); + v.setInt(int{1023}); BOOST_CHECK(v.isNum()); BOOST_CHECK_EQUAL(v.getValStr(), "1023"); - BOOST_CHECK(v.setInt((int64_t)-1023LL)); + v.setInt(int64_t{-1023LL}); BOOST_CHECK(v.isNum()); BOOST_CHECK_EQUAL(v.getValStr(), "-1023"); - BOOST_CHECK(v.setInt((uint64_t)1023ULL)); + v.setInt(uint64_t{1023ULL}); BOOST_CHECK(v.isNum()); BOOST_CHECK_EQUAL(v.getValStr(), "1023"); - BOOST_CHECK(v.setNumStr("-688")); + v.setNumStr("-688"); BOOST_CHECK(v.isNum()); BOOST_CHECK_EQUAL(v.getValStr(), "-688"); - BOOST_CHECK(v.setBool(false)); + v.setBool(false); BOOST_CHECK_EQUAL(v.isBool(), true); BOOST_CHECK_EQUAL(v.isTrue(), false); BOOST_CHECK_EQUAL(v.isFalse(), true); BOOST_CHECK_EQUAL(v.getBool(), false); - BOOST_CHECK(v.setBool(true)); + v.setBool(true); BOOST_CHECK_EQUAL(v.isBool(), true); BOOST_CHECK_EQUAL(v.isTrue(), true); BOOST_CHECK_EQUAL(v.isFalse(), false); BOOST_CHECK_EQUAL(v.getBool(), true); - BOOST_CHECK(!v.setNumStr("zombocom")); + BOOST_CHECK_THROW(v.setNumStr("zombocom"), std::runtime_error); - BOOST_CHECK(v.setNull()); + v.setNull(); BOOST_CHECK(v.isNull()); } @@ -352,7 +352,7 @@ void univalue_object() BOOST_CHECK_EQUAL(obj.size(), 0); BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL); - BOOST_CHECK_EQUAL(obj.setObject(), true); + obj.setObject(); UniValue uv; uv.setInt(42); obj.__pushKV("age", uv); @@ -419,7 +419,7 @@ void univalue_readwrite() BOOST_CHECK(!v.read("{} 42")); } -int main (int argc, char *argv[]) +int main(int argc, char* argv[]) { univalue_constructor(); univalue_push_throw(); @@ -430,4 +430,3 @@ int main (int argc, char *argv[]) univalue_readwrite(); return 0; } - From 41eb3b05c7a144901ea3bd1311537d294a992128 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 26 Jul 2022 15:24:08 +0200 Subject: [PATCH 15/19] merge bitcoin#25714: Avoid std::string copies --- src/univalue/include/univalue.h | 9 +++------ src/univalue/lib/univalue.cpp | 12 ++++++------ src/univalue/test/object.cpp | 9 +++++++++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 241c55e02958..42562ffe9b1d 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -20,10 +20,7 @@ class UniValue { enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; UniValue() { typ = VNULL; } - UniValue(UniValue::VType initialType, const std::string& initialStr = "") { - typ = initialType; - val = initialStr; - } + UniValue(UniValue::VType type, std::string str = {}) : typ{type}, val{std::move(str)} {} template >, std::enable_if_t || // setFloat std::is_same_v || // setBool @@ -49,12 +46,12 @@ class UniValue { void setNull(); void setBool(bool val); - void setNumStr(const std::string& val); + void setNumStr(std::string str); void setInt(uint64_t val); void setInt(int64_t val); void setInt(int val_) { return setInt(int64_t{val_}); } void setFloat(double val); - void setStr(const std::string& val); + void setStr(std::string str); void setArray(); void setObject(); diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index 9062e4853908..ce2ad780f6b7 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -44,15 +44,15 @@ static bool validNumStr(const std::string& s) return (tt == JTOK_NUMBER); } -void UniValue::setNumStr(const std::string& val_) +void UniValue::setNumStr(std::string str) { - if (!validNumStr(val_)) { - throw std::runtime_error{"The string '" + val_ + "' is not a valid JSON number"}; + if (!validNumStr(str)) { + throw std::runtime_error{"The string '" + str + "' is not a valid JSON number"}; } clear(); typ = VNUM; - val = val_; + val = std::move(str); } void UniValue::setInt(uint64_t val_) @@ -82,11 +82,11 @@ void UniValue::setFloat(double val_) return setNumStr(oss.str()); } -void UniValue::setStr(const std::string& val_) +void UniValue::setStr(std::string str) { clear(); typ = VSTR; - val = val_; + val = std::move(str); } void UniValue::setArray() diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index 94d7343ff35c..65e82543e438 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #define BOOST_CHECK(expr) assert(expr) @@ -160,6 +161,14 @@ void univalue_set() BOOST_CHECK(v.isStr()); BOOST_CHECK_EQUAL(v.getValStr(), "zum"); + { + std::string_view sv{"ab\0c", 4}; + UniValue j{sv}; + BOOST_CHECK(j.isStr()); + BOOST_CHECK_EQUAL(j.getValStr(), sv); + BOOST_CHECK_EQUAL(j.write(), "\"ab\\u0000c\""); + } + v.setFloat(-1.01); BOOST_CHECK(v.isNum()); BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); From 203a1c17a84e20dcddf3fde2969014cd276754e7 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 30 Nov 2022 17:42:59 +0000 Subject: [PATCH 16/19] merge bitcoin#26612: pass named argument value as string_view --- src/rpc/client.cpp | 31 ++++++++++++++++--------------- src/rpc/client.h | 5 ++++- src/test/rpc_tests.cpp | 9 +++++++++ src/univalue/include/univalue.h | 5 ++--- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index ab433de19eb0..eeb75eba835d 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -5,9 +5,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include +#include +#include class CRPCConvertParam { @@ -262,15 +265,15 @@ class CRPCConvertTable CRPCConvertTable(); /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ - UniValue ArgToUniValue(const std::string& arg_value, const std::string& method, int param_idx) + UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx) { - return members.count(std::make_pair(method, param_idx)) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; + return members.count({method, param_idx}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; } /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ - UniValue ArgToUniValue(const std::string& arg_value, const std::string& method, const std::string& param_name) + UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name) { - return membersByName.count(std::make_pair(method, param_name)) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; + return membersByName.count({method, param_name}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; } }; @@ -287,13 +290,11 @@ static CRPCConvertTable rpcCvtTable; /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) * as well as objects and arrays. */ -UniValue ParseNonRFCJSONValue(const std::string& strVal) +UniValue ParseNonRFCJSONValue(std::string_view raw) { - UniValue jVal; - if (!jVal.read(std::string("[")+strVal+std::string("]")) || - !jVal.isArray() || jVal.size()!=1) - throw std::runtime_error(std::string("Error parsing JSON: ") + strVal); - return jVal[0]; + UniValue parsed; + if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw)); + return parsed; } UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) @@ -301,8 +302,8 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector +#include + #include /** Convert positional arguments to command-specific RPC representation */ @@ -17,6 +20,6 @@ UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector #include #include +#include #include #include @@ -91,9 +92,7 @@ class UniValue { bool read(const char *raw, size_t len); bool read(const char *raw) { return read(raw, strlen(raw)); } - bool read(const std::string& rawStr) { - return read(rawStr.data(), rawStr.size()); - } + bool read(std::string_view raw) { return read(raw.data(), raw.size()); } private: UniValue::VType typ; From 6d81d06090fb584fb5d216de3fc012ae78c87637 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 9 May 2023 09:21:37 +0200 Subject: [PATCH 17/19] merge bitcoin#27605: Replace global find_value function with UniValue::find_value method --- src/bitcoin-cli.cpp | 22 ++++----- src/httprpc.cpp | 4 +- src/qt/governancelist.cpp | 10 ++-- src/qt/rpcconsole.cpp | 6 +-- src/rpc/mining.cpp | 8 +-- src/rpc/node.cpp | 14 +++--- src/rpc/rawtransaction_util.cpp | 10 ++-- src/rpc/request.cpp | 6 +-- src/rpc/util.cpp | 10 ++-- src/test/fuzz/rpc.cpp | 2 +- src/test/key_io_tests.cpp | 14 +++--- src/test/rpc_tests.cpp | 84 ++++++++++++++++---------------- src/test/system_tests.cpp | 4 +- src/univalue/include/univalue.h | 4 +- src/univalue/lib/univalue.cpp | 11 +++-- src/wallet/rpc/coins.cpp | 2 +- src/wallet/test/wallet_tests.cpp | 42 ++++++++-------- 17 files changed, 126 insertions(+), 127 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index d55a4083f92e..430ebb9257b6 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -876,7 +876,7 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str try { response = CallRPC(rh, strMethod, args, rpcwallet); if (fWait) { - const UniValue& error = find_value(response, "error"); + const UniValue& error = response.find_value("error"); if (!error.isNull() && error["code"].getInt() == RPC_IN_WARMUP) { throw CConnectionFailed("server in warmup"); } @@ -904,8 +904,8 @@ static void ParseResult(const UniValue& result, std::string& strPrint) static void ParseError(const UniValue& error, std::string& strPrint, int& nRet) { if (error.isObject()) { - const UniValue& err_code = find_value(error, "code"); - const UniValue& err_msg = find_value(error, "message"); + const UniValue& err_code = error.find_value("code"); + const UniValue& err_msg = error.find_value("message"); if (!err_code.isNull()) { strPrint = "error code: " + err_code.getValStr() + "\n"; } @@ -931,15 +931,15 @@ static void GetWalletBalances(UniValue& result) { DefaultRequestHandler rh; const UniValue listwallets = ConnectAndCallRPC(&rh, "listwallets", /* args=*/{}); - if (!find_value(listwallets, "error").isNull()) return; - const UniValue& wallets = find_value(listwallets, "result"); + if (!listwallets.find_value("error").isNull()) return; + const UniValue& wallets = listwallets.find_value("result"); if (wallets.size() <= 1) return; UniValue balances(UniValue::VOBJ); for (const UniValue& wallet : wallets.getValues()) { const std::string wallet_name = wallet.get_str(); const UniValue getbalances = ConnectAndCallRPC(&rh, "getbalances", /* args=*/{}, wallet_name); - const UniValue& balance = find_value(getbalances, "result")["mine"]["trusted"]; + const UniValue& balance = getbalances.find_value("result")["mine"]["trusted"]; balances.pushKV(wallet_name, balance); } result.pushKV("balances", balances); @@ -975,7 +975,7 @@ static void GetProgressBar(double progress, std::string& progress_bar) */ static void ParseGetInfoResult(UniValue& result) { - if (!find_value(result, "error").isNull()) return; + if (!result.find_value("error").isNull()) return; std::string RESET, GREEN, BLUE, YELLOW, MAGENTA, CYAN; bool should_colorize = false; @@ -1191,9 +1191,9 @@ static int CommandLineRPC(int argc, char *argv[]) rh.reset(new NetinfoRequestHandler()); } else if (gArgs.GetBoolArg("-generate", false)) { const UniValue getnewaddress{GetNewAddress()}; - const UniValue& error{find_value(getnewaddress, "error")}; + const UniValue& error{getnewaddress.find_value("error")}; if (error.isNull()) { - SetGenerateToAddressArgs(find_value(getnewaddress, "result").get_str(), args); + SetGenerateToAddressArgs(getnewaddress.find_value("result").get_str(), args); rh.reset(new GenerateToAddressRequestHandler()); } else { ParseError(error, strPrint, nRet); @@ -1215,8 +1215,8 @@ static int CommandLineRPC(int argc, char *argv[]) const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name); // Parse reply - UniValue result = find_value(reply, "result"); - const UniValue& error = find_value(reply, "error"); + UniValue result = reply.find_value("result"); + const UniValue& error = reply.find_value("error"); if (error.isNull()) { if (gArgs.GetBoolArg("-getinfo", false)) { if (!gArgs.IsArgSet("-rpcwallet")) { diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 8ba570062a55..22c1be063a8b 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -116,7 +116,7 @@ static bool JSONErrorReply(RpcHttpRequest& rpcRequest, const UniValue& objError, { // Send error reply from json-rpc error object int nStatus = HTTP_INTERNAL_SERVER_ERROR; - int code = find_value(objError, "code").getInt(); + int code = objError.find_value("code").getInt(); if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; @@ -253,7 +253,7 @@ static bool HTTPReq_JSONRPC(const CoreContext& context, HTTPRequest* req) } else { const UniValue& request = valRequest[reqIdx].get_obj(); // Parse method - std::string strMethod = find_value(request, "method").get_str(); + std::string strMethod = request.find_value("method").get_str(); if (!whitelisted(jreq)) { LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, strMethod); return rpcRequest.send_reply(HTTP_FORBIDDEN); diff --git a/src/qt/governancelist.cpp b/src/qt/governancelist.cpp index 2aa54a3ea88f..c001a03de796 100644 --- a/src/qt/governancelist.cpp +++ b/src/qt/governancelist.cpp @@ -45,23 +45,23 @@ Proposal::Proposal(ClientModel* _clientModel, const CGovernanceObject& _govObj, { UniValue prop_data; if (prop_data.read(govObj.GetDataAsPlainString())) { - if (UniValue titleValue = find_value(prop_data, "name"); titleValue.isStr()) { + if (UniValue titleValue = prop_data.find_value("name"); titleValue.isStr()) { m_title = QString::fromStdString(titleValue.get_str()); } - if (UniValue paymentStartValue = find_value(prop_data, "start_epoch"); paymentStartValue.isNum()) { + if (UniValue paymentStartValue = prop_data.find_value("start_epoch"); paymentStartValue.isNum()) { m_startDate = QDateTime::fromSecsSinceEpoch(paymentStartValue.getInt()); } - if (UniValue paymentEndValue = find_value(prop_data, "end_epoch"); paymentEndValue.isNum()) { + if (UniValue paymentEndValue = prop_data.find_value("end_epoch"); paymentEndValue.isNum()) { m_endDate = QDateTime::fromSecsSinceEpoch(paymentEndValue.getInt()); } - if (UniValue amountValue = find_value(prop_data, "payment_amount"); amountValue.isNum()) { + if (UniValue amountValue = prop_data.find_value("payment_amount"); amountValue.isNum()) { m_paymentAmount = amountValue.get_real(); } - if (UniValue urlValue = find_value(prop_data, "url"); urlValue.isStr()) { + if (UniValue urlValue = prop_data.find_value("url"); urlValue.isStr()) { m_url = QString::fromStdString(urlValue.get_str()); } } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index fe0357c1ab25..74a59ff04035 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -261,7 +261,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes subelement = lastResult[parsed.value()]; } else if (lastResult.isObject()) - subelement = find_value(lastResult, curarg); + subelement = lastResult.find_value(curarg); else throw std::runtime_error("Invalid result query"); //no array or object: abort lastResult = subelement; @@ -460,8 +460,8 @@ void RPCExecutor::request(const QString &command, const WalletModel* wallet_mode { try // Nice formatting for standard-format error { - int code = find_value(objError, "code").getInt(); - std::string message = find_value(objError, "message").get_str(); + int code = objError.find_value("code").getInt(); + std::string message = objError.find_value("message").get_str(); Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); } catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index bc40a7a99f54..ec3723e1d9bd 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -668,7 +668,7 @@ static RPCHelpMan getblocktemplate() if (!request.params[0].isNull()) { const UniValue& oparam = request.params[0].get_obj(); - const UniValue& modeval = find_value(oparam, "mode"); + const UniValue& modeval = oparam.find_value("mode"); if (modeval.isStr()) strMode = modeval.get_str(); else if (modeval.isNull()) @@ -677,11 +677,11 @@ static RPCHelpMan getblocktemplate() } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); - lpval = find_value(oparam, "longpollid"); + lpval = oparam.find_value("longpollid"); if (strMode == "proposal") { - const UniValue& dataval = find_value(oparam, "data"); + const UniValue& dataval = oparam.find_value("data"); if (!dataval.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); @@ -711,7 +711,7 @@ static RPCHelpMan getblocktemplate() return BIP22ValidationResult(state); } - const UniValue& aClientRules = find_value(oparam, "rules"); + const UniValue& aClientRules = oparam.find_value("rules"); if (aClientRules.isArray()) { for (unsigned int i = 0; i < aClientRules.size(); ++i) { const UniValue& v = aClientRules[i]; diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp index 7a062af65531..0e9d6dd023ee 100644 --- a/src/rpc/node.cpp +++ b/src/rpc/node.cpp @@ -357,7 +357,7 @@ static bool getAddressesFromParams(const UniValue& params, std::vector UniValue { - UniValue startValue = find_value(request.params[0].get_obj(), "start"); - UniValue endValue = find_value(request.params[0].get_obj(), "end"); + UniValue startValue = request.params[0].get_obj().find_value("start"); + UniValue endValue = request.params[0].get_obj().find_value("end"); int start = 0; int end = 0; @@ -715,8 +715,8 @@ static RPCHelpMan getaddresstxids() int start = 0; int end = 0; if (request.params[0].isObject()) { - UniValue startValue = find_value(request.params[0].get_obj(), "start"); - UniValue endValue = find_value(request.params[0].get_obj(), "end"); + UniValue startValue = request.params[0].get_obj().find_value("start"); + UniValue endValue = request.params[0].get_obj().find_value("end"); if (startValue.isNum() && endValue.isNum()) { start = startValue.getInt(); end = endValue.getInt(); @@ -789,8 +789,8 @@ static RPCHelpMan getspentinfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - UniValue txidValue = find_value(request.params[0].get_obj(), "txid"); - UniValue indexValue = find_value(request.params[0].get_obj(), "index"); + UniValue txidValue = request.params[0].get_obj().find_value("txid"); + UniValue indexValue = request.params[0].get_obj().find_value("index"); if (!txidValue.isStr() || !indexValue.isNum()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid txid or index"); diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index d7aa72eff0ad..e66a5b2d3aa9 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -51,7 +51,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal uint256 txid = ParseHashO(o, "txid"); - const UniValue& vout_v = find_value(o, "vout"); + const UniValue& vout_v = o.find_value("vout"); if (!vout_v.isNum()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); int nOutput = vout_v.getInt(); @@ -66,7 +66,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal } // set the sequence number if passed in the parameters object - const UniValue& sequenceObj = find_value(o, "sequence"); + const UniValue& sequenceObj = o.find_value("sequence"); if (sequenceObj.isNum()) { int64_t seqNr64 = sequenceObj.getInt(); if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) @@ -164,7 +164,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst uint256 txid = ParseHashO(prevOut, "txid"); - int nOut = find_value(prevOut, "vout").getInt(); + int nOut = prevOut.find_value("vout").getInt(); if (nOut < 0) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative"); } @@ -185,7 +185,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst newcoin.out.scriptPubKey = scriptPubKey; newcoin.out.nValue = 0; if (prevOut.exists("amount")) { - newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount")); + newcoin.out.nValue = AmountFromValue(prevOut.find_value("amount")); } newcoin.nHeight = 1; coins[out] = std::move(newcoin); @@ -198,7 +198,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst { {"redeemScript", UniValueType(UniValue::VSTR)}, }); - UniValue rs = find_value(prevOut, "redeemScript"); + const UniValue& rs{prevOut.find_value("redeemScript")}; if (rs.isNull()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing redeemScript"); } diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index 586bd5d1cad7..f1cd256e3549 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -163,10 +163,10 @@ void JSONRPCRequest::parse(const UniValue& valRequest) const UniValue& request = valRequest.get_obj(); // Parse id now so errors from here on will have the id - id = find_value(request, "id"); + id = request.find_value("id"); // Parse method - UniValue valMethod = find_value(request, "method"); + const UniValue& valMethod{request.find_value("method")}; if (valMethod.isNull()) throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method"); if (!valMethod.isStr()) @@ -181,7 +181,7 @@ void JSONRPCRequest::parse(const UniValue& valRequest) } // Parse params - UniValue valParams = find_value(request, "params"); + const UniValue& valParams{request.find_value("params")}; if (valParams.isArray() || valParams.isObject()) params = valParams; else if (valParams.isNull()) diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 07cea61ab6b7..482caccec770 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -61,7 +61,7 @@ void RPCTypeCheckObj(const UniValue& o, bool fStrict) { for (const auto& t : typesExpected) { - const UniValue& v = find_value(o, t.first); + const UniValue& v = o.find_value(t.first); if (!fAllowNull && v.isNull()) throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); @@ -108,7 +108,7 @@ uint256 ParseHashV(const UniValue& v, std::string strName) } uint256 ParseHashO(const UniValue& o, std::string strKey) { - return ParseHashV(find_value(o, strKey), strKey); + return ParseHashV(o.find_value(strKey), strKey); } std::vector ParseHexV(const UniValue& v, std::string strName) { @@ -121,7 +121,7 @@ std::vector ParseHexV(const UniValue& v, std::string strName) } std::vector ParseHexO(const UniValue& o, std::string strKey) { - return ParseHexV(find_value(o, strKey), strKey); + return ParseHexV(o.find_value(strKey), strKey); } int32_t ParseInt32V(const UniValue& v, const std::string &strName) @@ -1009,10 +1009,10 @@ std::vector EvalDescriptorStringOrObject(const UniValue& scanobject, Fl if (scanobject.isStr()) { desc_str = scanobject.get_str(); } else if (scanobject.isObject()) { - UniValue desc_uni = find_value(scanobject, "desc"); + const UniValue& desc_uni{scanobject.find_value("desc")}; if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object"); desc_str = desc_uni.get_str(); - UniValue range_uni = find_value(scanobject, "range"); + const UniValue& range_uni{scanobject.find_value("range")}; if (!range_uni.isNull()) { range = ParseDescriptorRange(range_uni); } diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp index 2ca48f787575..892823dea067 100644 --- a/src/test/fuzz/rpc.cpp +++ b/src/test/fuzz/rpc.cpp @@ -356,7 +356,7 @@ FUZZ_TARGET(rpc, .init = initialize_rpc) try { rpc_testing_setup->CallRPC(rpc_command, arguments); } catch (const UniValue& json_rpc_error) { - const std::string error_msg{find_value(json_rpc_error, "message").get_str()}; + const std::string error_msg{json_rpc_error.find_value("message").get_str()}; if (error_msg.starts_with("Internal bug detected")) { // Only allow the intentional internal bug assert(error_msg.find("trigger_internal_bug") != std::string::npos); diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index 2548e51d889c..d01e4cb6fbe7 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -37,11 +37,11 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse) std::string exp_base58string = test[0].get_str(); const std::vector exp_payload{ParseHex(test[1].get_str())}; const UniValue &metadata = test[2].get_obj(); - bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); - SelectParams(find_value(metadata, "chain").get_str()); - bool try_case_flip = find_value(metadata, "tryCaseFlip").isNull() ? false : find_value(metadata, "tryCaseFlip").get_bool(); + bool isPrivkey = metadata.find_value("isPrivkey").get_bool(); + SelectParams(metadata.find_value("chain").get_str()); + bool try_case_flip = metadata.find_value("tryCaseFlip").isNull() ? false : metadata.find_value("tryCaseFlip").get_bool(); if (isPrivkey) { - bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + bool isCompressed = metadata.find_value("isCompressed").get_bool(); // Must be valid private key privkey = DecodeSecret(exp_base58string); BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest); @@ -96,10 +96,10 @@ BOOST_AUTO_TEST_CASE(key_io_valid_gen) std::string exp_base58string = test[0].get_str(); std::vector exp_payload = ParseHex(test[1].get_str()); const UniValue &metadata = test[2].get_obj(); - bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); - SelectParams(find_value(metadata, "chain").get_str()); + bool isPrivkey = metadata.find_value("isPrivkey").get_bool(); + SelectParams(metadata.find_value("chain").get_str()); if (isPrivkey) { - bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + bool isCompressed = metadata.find_value("isCompressed").get_bool(); CKey key; key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); assert(key.IsValid()); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 81ade13e8385..6a6bc9fbba34 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -80,7 +80,7 @@ UniValue RPCTestingSetup::CallRPC(std::string args) return result; } catch (const UniValue& objError) { - throw std::runtime_error(find_value(objError, "message").get_str()); + throw std::runtime_error(objError.find_value("message").get_str()); } } @@ -139,9 +139,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams) BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), std::runtime_error); std::string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx)); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").getInt(), 193); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").getInt(), 1); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").getInt(), 0); + BOOST_CHECK_EQUAL(r.get_obj().find_value("size").getInt(), 193); + BOOST_CHECK_EQUAL(r.get_obj().find_value("version").getInt(), 1); + BOOST_CHECK_EQUAL(r.get_obj().find_value("locktime").getInt(), 0); BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error); // Only check failure cases for sendrawtransaction, there's no network to send to... @@ -156,20 +156,20 @@ BOOST_AUTO_TEST_CASE(rpc_togglenetwork) UniValue r; r = CallRPC("getnetworkinfo"); - bool netState = find_value(r.get_obj(), "networkactive").get_bool(); + bool netState = r.get_obj().find_value("networkactive").get_bool(); BOOST_CHECK_EQUAL(netState, true); BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive false")); r = CallRPC("getnetworkinfo"); - int numConnection = find_value(r.get_obj(), "connections").getInt(); + int numConnection = r.get_obj().find_value("connections").getInt(); BOOST_CHECK_EQUAL(numConnection, 0); - netState = find_value(r.get_obj(), "networkactive").get_bool(); + netState = r.get_obj().find_value("networkactive").get_bool(); BOOST_CHECK_EQUAL(netState, false); BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive true")); r = CallRPC("getnetworkinfo"); - netState = find_value(r.get_obj(), "networkactive").get_bool(); + netState = r.get_obj().find_value("networkactive").get_bool(); BOOST_CHECK_EQUAL(netState, true); } @@ -187,9 +187,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) std::string privkey1 = "\"XEwTRsCX3CiWSQf8YmKMTeb84KyTbibkUv9mDTZHQ5MwuKG2ZzES\""; std::string privkey2 = "\"XDmZ7LjGd94Q81eUBjb2h6uV5Y14s7fmeXWEGYabfBJP8RVpprBu\""; r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" [] "+prevout); - BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false); + BOOST_CHECK(r.get_obj().find_value("complete").get_bool() == false); r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" ["+privkey1+","+privkey2+"] "+prevout); - BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); + BOOST_CHECK(r.get_obj().find_value("complete").get_bool() == true); } BOOST_AUTO_TEST_CASE(rpc_createraw_op_return) @@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); UniValue ar = r.get_array(); UniValue o1 = ar[0].get_obj(); - UniValue adr = find_value(o1, "address"); + UniValue adr = o1.find_value("address"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32"); BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0 remove"))); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); @@ -343,8 +343,8 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); - int64_t banned_until{find_value(o1, "banned_until").getInt()}; + adr = o1.find_value("address"); + int64_t banned_until{o1.find_value("banned_until").getInt()}; BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); BOOST_CHECK_EQUAL(banned_until, 9907731200); // absolute time check @@ -358,11 +358,11 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); - banned_until = find_value(o1, "banned_until").getInt(); - const int64_t ban_created{find_value(o1, "ban_created").getInt()}; - const int64_t ban_duration{find_value(o1, "ban_duration").getInt()}; - const int64_t time_remaining{find_value(o1, "time_remaining").getInt()}; + adr = o1.find_value("address"); + banned_until = o1.find_value("banned_until").getInt(); + const int64_t ban_created{o1.find_value("ban_created").getInt()}; + const int64_t ban_duration{o1.find_value("ban_duration").getInt()}; + const int64_t time_remaining{o1.find_value("time_remaining").getInt()}; BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); BOOST_CHECK_EQUAL(banned_until, time_remaining_expected + now.count()); BOOST_CHECK_EQUAL(ban_duration, banned_until - ban_created); @@ -392,7 +392,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); + adr = o1.find_value("address"); BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128"); BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); @@ -400,7 +400,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); + adr = o1.find_value("address"); BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30"); BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); @@ -408,7 +408,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); - adr = find_value(o1, "address"); + adr = o1.find_value("address"); BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128"); } @@ -555,45 +555,45 @@ BOOST_AUTO_TEST_CASE(rpc_bls) UniValue r; BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls generate"))); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "basic"); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "basic"); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls generate 1"))); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "legacy"); - std::string secret_legacy = find_value(r.get_obj(), "secret").get_str(); - std::string public_legacy = find_value(r.get_obj(), "public").get_str(); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "legacy"); + std::string secret_legacy = r.get_obj().find_value("secret").get_str(); + std::string public_legacy = r.get_obj().find_value("public").get_str(); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls generate 0"))); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "basic"); - std::string secret_basic = find_value(r.get_obj(), "secret").get_str(); - std::string public_basic = find_value(r.get_obj(), "public").get_str(); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "basic"); + std::string secret_basic = r.get_obj().find_value("secret").get_str(); + std::string public_basic = r.get_obj().find_value("public").get_str(); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls fromsecret ") + secret_basic)); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "basic"); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "public").get_str(), public_basic); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "basic"); + BOOST_CHECK_EQUAL(r.get_obj().find_value("public").get_str(), public_basic); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls fromsecret ") + secret_legacy + std::string(" 1"))); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "legacy"); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "public").get_str(), public_legacy); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "legacy"); + BOOST_CHECK_EQUAL(r.get_obj().find_value("public").get_str(), public_legacy); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls fromsecret ") + secret_basic + std::string(" 0"))); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "basic"); - BOOST_CHECK(find_value(r.get_obj(), "public").get_str() != public_legacy); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "basic"); + BOOST_CHECK(r.get_obj().find_value("public").get_str() != public_legacy); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls fromsecret ") + secret_basic + std::string(" 0"))); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "basic"); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "public").get_str(), public_basic); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "basic"); + BOOST_CHECK_EQUAL(r.get_obj().find_value("public").get_str(), public_basic); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls fromsecret ") + secret_basic + std::string(" 1"))); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "legacy"); - BOOST_CHECK(find_value(r.get_obj(), "public").get_str() != public_basic); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "legacy"); + BOOST_CHECK(r.get_obj().find_value("public").get_str() != public_basic); std::string secret = "0b072b1b8b28335b0460aa695ee8ce1f60dc01e6eb12655ece2a877379dfdb51"; BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls fromsecret ") + secret + " 1")); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "legacy"); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "public").get_str(), "9379c28e0f50546906fe733f1222c8f7e39574d513790034f1fec1476286eb652a350c8c0e630cd2cc60d10c26d6f6ee"); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "legacy"); + BOOST_CHECK_EQUAL(r.get_obj().find_value("public").get_str(), "9379c28e0f50546906fe733f1222c8f7e39574d513790034f1fec1476286eb652a350c8c0e630cd2cc60d10c26d6f6ee"); BOOST_CHECK_NO_THROW(r = CallRPC(std::string("bls fromsecret ") + secret)); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "scheme").get_str(), "basic"); - BOOST_CHECK_EQUAL(find_value(r.get_obj(), "public").get_str(), "b379c28e0f50546906fe733f1222c8f7e39574d513790034f1fec1476286eb652a350c8c0e630cd2cc60d10c26d6f6ee"); + BOOST_CHECK_EQUAL(r.get_obj().find_value("scheme").get_str(), "basic"); + BOOST_CHECK_EQUAL(r.get_obj().find_value("public").get_str(), "b379c28e0f50546906fe733f1222c8f7e39574d513790034f1fec1476286eb652a350c8c0e630cd2cc60d10c26d6f6ee"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index 11e67f4dacbb..deef4f12b1b1 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(run_command) const UniValue result = RunCommandParseJSON("echo \"{\"success\": true}\""); #endif BOOST_CHECK(result.isObject()); - const UniValue& success = find_value(result, "success"); + const UniValue& success = result.find_value("success"); BOOST_CHECK(!success.isNull()); BOOST_CHECK_EQUAL(success.getBool(), true); } @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(run_command) { const UniValue result = RunCommandParseJSON("cat", "{\"success\": true}"); BOOST_CHECK(result.isObject()); - const UniValue& success = find_value(result, "success"); + const UniValue& success = result.find_value("success"); BOOST_CHECK(!success.isNull()); BOOST_CHECK_EQUAL(success.getBool(), true); } diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index bf8365adfb02..ec4a1aae64b8 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -130,7 +130,7 @@ class UniValue { const UniValue& get_array() const; enum VType type() const { return getType(); } - friend const UniValue& find_value( const UniValue& obj, const std::string& name); + const UniValue& find_value(std::string_view key) const; }; template @@ -195,6 +195,4 @@ static inline bool json_isspace(int ch) extern const UniValue NullUniValue; -const UniValue& find_value( const UniValue& obj, const std::string& name); - #endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index ce2ad780f6b7..a00c9f348146 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -221,12 +221,13 @@ const char *uvTypeName(UniValue::VType t) return nullptr; } -const UniValue& find_value(const UniValue& obj, const std::string& name) +const UniValue& UniValue::find_value(std::string_view key) const { - for (unsigned int i = 0; i < obj.keys.size(); i++) - if (obj.keys[i] == name) - return obj.values.at(i); - + for (unsigned int i = 0; i < keys.size(); ++i) { + if (keys[i] == key) { + return values.at(i); + } + } return NullUniValue; } diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index 3d16cc3df39e..ffc0ad8f0c8a 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -329,7 +329,7 @@ RPCHelpMan lockunspent() }); const uint256 txid(ParseHashO(o, "txid")); - const int nOutput{find_value(o, "vout").getInt()}; + const int nOutput{o.find_value("vout").getInt()}; if (nOutput < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); } diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 2e671c33888d..7f6cea0186be 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -919,15 +919,15 @@ BOOST_FIXTURE_TEST_CASE(rpc_getaddressinfo, TestChain100Setup) request.params.push_back(addr); BOOST_CHECK_NO_THROW(response = wallet::getaddressinfo().HandleRequest(request).get_obj()); - BOOST_CHECK_EQUAL(find_value(response, "ismine").get_bool(), true); - BOOST_CHECK_EQUAL(find_value(response, "solvable").get_bool(), true); - BOOST_CHECK_EQUAL(find_value(response, "iswatchonly").get_bool(), false); - BOOST_CHECK_EQUAL(find_value(response, "isscript").get_bool(), false); - BOOST_CHECK_EQUAL(find_value(response, "ischange").get_bool(), true); - BOOST_CHECK(find_value(response, "pubkeys").isNull()); - BOOST_CHECK(find_value(response, "addresses").isNull()); - BOOST_CHECK(find_value(response, "sigsrequired").isNull()); - BOOST_CHECK(find_value(response, "label").isNull()); + BOOST_CHECK_EQUAL(response.find_value("ismine").get_bool(), true); + BOOST_CHECK_EQUAL(response.find_value("solvable").get_bool(), true); + BOOST_CHECK_EQUAL(response.find_value("iswatchonly").get_bool(), false); + BOOST_CHECK_EQUAL(response.find_value("isscript").get_bool(), false); + BOOST_CHECK_EQUAL(response.find_value("ischange").get_bool(), true); + BOOST_CHECK(response.find_value("pubkeys").isNull()); + BOOST_CHECK(response.find_value("addresses").isNull()); + BOOST_CHECK(response.find_value("sigsrequired").isNull()); + BOOST_CHECK(response.find_value("label").isNull()); // test p2sh/multisig std::string addr1; @@ -947,24 +947,24 @@ BOOST_FIXTURE_TEST_CASE(rpc_getaddressinfo, TestChain100Setup) BOOST_CHECK_NO_THROW(response = wallet::addmultisigaddress().HandleRequest(request)); - std::string multisig = find_value(response.get_obj(), "address").get_str(); + std::string multisig = response.get_obj().find_value("address").get_str(); request.params.clear(); request.params.setArray(); request.params.push_back(multisig); BOOST_CHECK_NO_THROW(response = wallet::getaddressinfo().HandleRequest(request).get_obj()); - BOOST_CHECK_EQUAL(find_value(response, "ismine").get_bool(), true); - BOOST_CHECK_EQUAL(find_value(response, "solvable").get_bool(), true); - BOOST_CHECK_EQUAL(find_value(response, "iswatchonly").get_bool(), false); - BOOST_CHECK_EQUAL(find_value(response, "isscript").get_bool(), true); - BOOST_CHECK_EQUAL(find_value(response, "ischange").get_bool(), false); - BOOST_CHECK_EQUAL(find_value(response, "sigsrequired").getInt(), 2); - BOOST_CHECK(find_value(response, "label").isNull()); - - UniValue labels = find_value(response, "labels").get_array(); - UniValue pubkeys = find_value(response, "pubkeys").get_array(); - UniValue addresses = find_value(response, "addresses").get_array(); + BOOST_CHECK_EQUAL(response.find_value("ismine").get_bool(), true); + BOOST_CHECK_EQUAL(response.find_value("solvable").get_bool(), true); + BOOST_CHECK_EQUAL(response.find_value("iswatchonly").get_bool(), false); + BOOST_CHECK_EQUAL(response.find_value("isscript").get_bool(), true); + BOOST_CHECK_EQUAL(response.find_value("ischange").get_bool(), false); + BOOST_CHECK_EQUAL(response.find_value("sigsrequired").getInt(), 2); + BOOST_CHECK(response.find_value("label").isNull()); + + UniValue labels = response.find_value("labels").get_array(); + UniValue pubkeys = response.find_value("pubkeys").get_array(); + UniValue addresses = response.find_value("addresses").get_array(); BOOST_CHECK_EQUAL(labels.size(), 1); BOOST_CHECK_EQUAL(labels[0].get_str(), ""); From f00dc7813419d0dd6d09d405dc44b8be2d2e3cd6 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 23 Jul 2025 07:29:43 +0000 Subject: [PATCH 18/19] build: drop `-Wdangling-reference` GCC suppression --- configure.ac | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index c2598bd69da8..ac4bd086422d 100644 --- a/configure.ac +++ b/configure.ac @@ -450,7 +450,7 @@ if test "$enable_werror" = "yes"; then fi ERROR_CXXFLAGS=$CXXFLAG_WERROR - dnl -Warray-bounds and -Wdangling-reference cause problems with GCC. Do not treat these warnings as errors. + dnl -Warray-bounds cause problems with GCC. Do not treat these warnings as errors. dnl Suppress -Warray-bounds entirely because of noisy output, currently unhappy with immer implementation. AX_CHECK_COMPILE_FLAG([-Warray-bounds], [NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-array-bounds"], [], [$CXXFLAG_WERROR], [AC_LANG_SOURCE([ #if defined(__clang__) || defined(__INTEL_COMPILER) || !defined(__GNUC__) @@ -458,13 +458,6 @@ if test "$enable_werror" = "yes"; then #endif int main(void) { return 0; } ])]) - dnl TODO: Remove suppression after backporting bitcoin#27605 - AX_CHECK_COMPILE_FLAG([-Wdangling-reference], [NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-error=dangling-reference"], [], [$CXXFLAG_WERROR], [AC_LANG_SOURCE([ - #if defined(__clang__) || defined(__INTEL_COMPILER) || !defined(__GNUC__) - #error Non-GCC compiler detected, not setting flag - #endif - int main(void) { return 0; } - ])]) dnl -Wattributes cause problems with some versions of GCC. Do not treat these warnings as errors. AX_CHECK_COMPILE_FLAG([-Wattributes], [NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-error=attributes"], [], [$CXXFLAG_WERROR], [AC_LANG_SOURCE([ From 05e2091ca24fd3492aadd7e3c1aacf75dfb6b873 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 16 Jul 2024 22:23:53 +0100 Subject: [PATCH 19/19] merge bitcoin#30464: Fix MSVC warning C4101 "unreferenced local variable" --- src/univalue/test/object.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index 65e82543e438..ccb5024a1eca 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -20,17 +20,17 @@ try { \ (stmt); \ assert(0 && "No exception caught"); \ - } catch (excMatch & e) { \ - } catch (...) { \ - assert(0 && "Wrong exception caught"); \ - } \ + } catch (excMatch&) { \ + } catch (...) { \ + assert(0 && "Wrong exception caught"); \ + } \ } #define BOOST_CHECK_NO_THROW(stmt) { \ try { \ (stmt); \ - } catch (...) { \ - assert(0); \ - } \ + } catch (...) { \ + assert(0); \ + } \ } void univalue_constructor()