diff --git a/doc/release-notes.md b/doc/release-notes.md index bbaec0108..cd53531f2 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,6 +1,6 @@ Bitcoin ABC version 0.19.6 is now available from: This release includes the following features and fixes: - + - Using addresses in createmultisig is now deprectated. Use -deprecatedrpc=createmultisig to get the old behavior. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ace4a21be..565c39851 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,359 +1,360 @@ # Copyright (c) 2017 The Bitcoin developers cmake_minimum_required(VERSION 3.5) project(BitcoinABC) set(CMAKE_CXX_STANDARD 14) # Default visibility is hidden on all targets. set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_CXX_VISIBILITY_PRESET hidden) option(BUILD_BITCOIN_WALLET "Activate the wallet functionality" ON) option(BUILD_BITCOIN_ZMQ "Activate the ZeroMQ functionalities" ON) option(BUILD_BITCOIN_SEEDER "Build bitcoin-seeder" ON) option(BUILD_BITCOIN_CLI "Build bitcoin-cli" ON) option(BUILD_BITCOIN_TX "Build bitcoin-tx" ON) option(BUILD_BITCOIN_QT "Build bitcoin-qt" ON) option(ENABLE_HARDENING "Harden the executables" ON) # Cmake uses the CMAKE_BUILD_TYPE variable to select the build configuration. # By default it supports more configurations that needed for Bitcoin ABC, and # all the releases types set NDEBUG which is unwanted as it disables the assert # completely. # Remove the -DNDEBUG flag from the CFLAGS/CXXFLAGS in all the configurations include(AddCompilerFlags) remove_compiler_flags(-DNDEBUG) # Overrides the flags for the Debug build type # This mimics the autotools behavior by setting the CFLAGS to '-g -O2`, which # are not well suited for debugging. # FIXME: update CFLAGS with better debug oriented optimization flags set(CMAKE_C_FLAGS_DEBUG "-g -O2") # Prefer -g3, defaults to -g if unavailable add_cxx_compiler_flag_with_fallback(CMAKE_CXX_FLAGS_DEBUG -g3 -g) # Prefer -Og, defaults to -O0 if unavailable add_cxx_compiler_flag_with_fallback(CMAKE_CXX_FLAGS_DEBUG -Og -O0) # Define the debugging symbols DEBUG and DEBUG_LOCKORDER when the Debug build # type is selected. string(APPEND CMAKE_CXX_FLAGS_DEBUG " -DDEBUG -DDEBUG_LOCKORDER") # Ensure that WINDRES_PREPROC is enabled when using windres. if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") # Ensure that WINDRES_PREPROC is enabled when using windres. list(APPEND CMAKE_RC_FLAGS "-DWINDRES_PREPROC") # Build all static so there is no dll file to distribute. add_compiler_flag(-static) endif() # All windows code is PIC, forcing it on just adds useless compile warnings if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") add_compiler_flag(-fPIC) endif() if(ENABLE_HARDENING) # Enable stack protection add_cxx_compiler_flag(-fstack-protector-all -Wstack-protector) # Enable some buffer overflow checking add_compiler_flag(-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2) # Enable ASLR (these flags are primarily targeting MinGw) add_linker_flag(-Wl,--dynamicbase -Wl,--nxcompat -Wl,--high-entropy-va) # Make the relocated sections read-only add_linker_flag(-Wl,-z,relro -Wl,-z,now) # CMake provides the POSITION_INDEPENDENT_CODE property to set PIC/PIE. # Unfortunately setting the -pie linker flag this way require CMake >= 3.14, # which is not widely distributed at the time of writing. # FIXME: use the POSITION_INDEPENDENT_CODE property instead if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") add_compiler_flag(-fPIE) add_linker_flag(-pie) else() # MinGw provides its own libssp for stack smashing protection link_libraries(ssp) endif() endif() # Enable warning add_c_compiler_flag(-Wnested-externs -Wstrict-prototypes) add_compiler_flag( -Wall -Wextra -Wformat -Wvla -Wformat-security -Wcast-align -Wunused-parameter -Wmissing-braces # FIXME: Activating this flag cause cmake to fail on leveldb. # -Wthread-safety-analysis -Wshadow ) option(EXTRA_WARNINGS "Enable extra warnings" OFF) if(EXTRA_WARNINGS) add_cxx_compiler_flag(-Wsuggest-override) else() add_compiler_flag(-Wno-unused-parameter) endif() # Create a target for OpenSSL include(BrewHelper) find_brew_prefix(OPENSSL_ROOT_DIR openssl) find_package(OpenSSL REQUIRED) # libtool style configure add_subdirectory(config) # libraries add_subdirectory(crypto) add_subdirectory(leveldb) add_subdirectory(secp256k1) add_subdirectory(univalue) # Because the Bitcoin ABc source code is disorganised, we # end up with a bunch of libraries without any aparent # cohesive structure. This is inherited from Bitcoin Core # and reflecting this. # TODO: Improve the structure once cmake is rocking. # Various completely unrelated features shared by all executables. add_library(util chainparamsbase.cpp clientversion.cpp compat/glibc_sanity.cpp compat/glibcxx_sanity.cpp compat/strnlen.cpp fs.cpp logging.cpp random.cpp rcu.cpp rpc/protocol.cpp + rpc/util.cpp support/cleanse.cpp support/lockedpool.cpp sync.cpp threadinterrupt.cpp uint256.cpp util.cpp utilmoneystr.cpp utilstrencodings.cpp utiltime.cpp ) target_compile_definitions(util PUBLIC HAVE_CONFIG_H) target_include_directories(util PUBLIC . # To access the config. ${CMAKE_CURRENT_BINARY_DIR} ) # Target specific configs if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(Boost_USE_STATIC_LIBS ON) set(Boost_THREADAPI win32) find_package(SHLWAPI REQUIRED) target_link_libraries(util ${SHLWAPI_LIBRARY}) target_include_directories(util PUBLIC ${SHLWAPI_INCLUDE_DIR}) find_library(WS2_32_LIBRARY NAMES ws2_32) target_link_libraries(util ${WS2_32_LIBRARY}) target_compile_definitions(util PUBLIC BOOST_THREAD_USE_LIB) endif() # Boost packages set(BOOST_PACKAGES_REQUIRED chrono filesystem program_options thread) function(prepend var prefix) set(listVar "") foreach(f ${ARGN}) list(APPEND listVar "${prefix}${f}") endforeach(f) set(${var} "${listVar}" PARENT_SCOPE) endfunction(prepend) prepend(BOOST_LIBRARIES "Boost::" ${BOOST_PACKAGES_REQUIRED}) find_package(Boost 1.58 REQUIRED ${BOOST_PACKAGES_REQUIRED}) target_link_libraries(util univalue crypto ${BOOST_LIBRARIES}) # Make sure boost uses std::atomic (it doesn't before 1.63) target_compile_definitions(util PUBLIC BOOST_SP_USE_STD_ATOMIC BOOST_AC_USE_STD_ATOMIC) # More completely unrelated features shared by all executables. # Because nothing says this is different from util than "common" add_library(common amount.cpp base58.cpp cashaddr.cpp cashaddrenc.cpp chainparams.cpp config.cpp consensus/merkle.cpp coins.cpp compressor.cpp dstencode.cpp feerate.cpp globals.cpp core_read.cpp core_write.cpp key.cpp keystore.cpp netaddress.cpp netbase.cpp primitives/block.cpp protocol.cpp scheduler.cpp script/sign.cpp script/standard.cpp warnings.cpp ) target_link_libraries(common util secp256k1) # libbitcoinconsensus add_library(bitcoinconsensus arith_uint256.cpp hash.cpp primitives/transaction.cpp pubkey.cpp script/bitcoinconsensus.cpp script/interpreter.cpp script/script.cpp script/script_error.cpp script/sigencoding.cpp uint256.cpp utilstrencodings.cpp ) target_link_libraries(bitcoinconsensus common) # Bitcoin server facilities add_library(server addrman.cpp addrdb.cpp avalanche.cpp bloom.cpp blockencodings.cpp blockfilter.cpp chain.cpp checkpoints.cpp config.cpp consensus/activation.cpp consensus/tx_verify.cpp globals.cpp httprpc.cpp httpserver.cpp init.cpp interfaces/handler.cpp interfaces/node.cpp dbwrapper.cpp merkleblock.cpp miner.cpp net.cpp net_processing.cpp noui.cpp policy/fees.cpp policy/policy.cpp pow.cpp rest.cpp rpc/abc.cpp rpc/blockchain.cpp rpc/command.cpp rpc/jsonrpcrequest.cpp rpc/mining.cpp rpc/misc.cpp rpc/net.cpp rpc/rawtransaction.cpp rpc/server.cpp script/scriptcache.cpp script/sigcache.cpp script/ismine.cpp timedata.cpp torcontrol.cpp txdb.cpp txmempool.cpp ui_interface.cpp validation.cpp validationinterface.cpp ) # This require libevent find_package(Event REQUIRED) target_include_directories(server PRIVATE leveldb/helpers/memenv) target_link_libraries(server Event bitcoinconsensus leveldb memenv ) # Test suite. add_subdirectory(test) # Benchmark suite. add_subdirectory(bench) # Wallet if(BUILD_BITCOIN_WALLET) add_subdirectory(wallet) target_link_libraries(server wallet) endif() # ZeroMQ if(BUILD_BITCOIN_ZMQ) add_subdirectory(zmq) target_link_libraries(server zmq) endif() # RPC client support add_library(rpcclient rpc/client.cpp) target_link_libraries(rpcclient univalue util) # bitcoin-seeder if(BUILD_BITCOIN_SEEDER) add_subdirectory(seeder) endif() # bitcoin-cli if(BUILD_BITCOIN_CLI) add_executable(bitcoin-cli bitcoin-cli.cpp) if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") target_sources(bitcoin-cli PRIVATE bitcoin-cli-res.rc) endif() target_link_libraries(bitcoin-cli common rpcclient Event) endif() # bitcoin-tx if(BUILD_BITCOIN_TX) add_executable(bitcoin-tx bitcoin-tx.cpp) if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") target_sources(bitcoin-tx PRIVATE bitcoin-tx-res.rc) endif() target_link_libraries(bitcoin-tx bitcoinconsensus) endif() # bitcoind add_executable(bitcoind bitcoind.cpp) target_link_libraries(bitcoind server) if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") target_sources(bitcoind PRIVATE bitcoind-res.rc) endif() # Bitcoin-qt if(BUILD_BITCOIN_QT) add_subdirectory(qt) endif() diff --git a/src/Makefile.am b/src/Makefile.am index 74f29c027..e5c495618 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,657 +1,659 @@ # Copyright (c) 2013-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(SANITIZER_LDFLAGS) AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) $(SANITIZER_CXXFLAGS) AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS) AM_LIBTOOLFLAGS = --preserve-dup-deps EXTRA_LIBRARIES = if EMBEDDED_UNIVALUE LIBUNIVALUE = univalue/libunivalue.la $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) else LIBUNIVALUE = $(UNIVALUE_LIBS) endif BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) BITCOIN_SEEDER_INCLUDES = -I$(srcdir)/seeder BITCOIN_SEEDER_INCLUDES += $(BITCOIN_INCLUDES) LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO_BASE=crypto/libbitcoin_crypto_base.a LIBBITCOINQT=qt/libbitcoinqt.a LIBSECP256K1=secp256k1/libsecp256k1.la if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a endif if BUILD_BITCOIN_LIBS LIBBITCOINCONSENSUS=libbitcoinconsensus.la endif if BUILD_BITCOIN_SEEDER LIBBITCOIN_SEEDER=libbitcoin_seeder.a endif if ENABLE_WALLET LIBBITCOIN_WALLET=libbitcoin_wallet.a endif LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE) if ENABLE_SSE41 LIBBITCOIN_CRYPTO_SSE41 = crypto/libbitcoin_crypto_sse41.a LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SSE41) endif if ENABLE_AVX2 LIBBITCOIN_CRYPTO_AVX2 = crypto/libbitcoin_crypto_avx2.a LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_AVX2) endif if ENABLE_SHANI LIBBITCOIN_CRYPTO_SHANI = crypto/libbitcoin_crypto_shani.a LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SHANI) endif $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: EXTRA_LIBRARIES += \ $(LIBBITCOIN_CRYPTO) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_CLI) \ $(LIBBITCOIN_SEEDER) \ $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_ZMQ) lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS) bin_PROGRAMS = noinst_PROGRAMS = TESTS = BENCHMARKS = if BUILD_BITCOIND bin_PROGRAMS += bitcoind endif if BUILD_BITCOIN_SEEDER bin_PROGRAMS += bitcoin-seeder endif if BUILD_BITCOIN_UTILS bin_PROGRAMS += bitcoin-cli bitcoin-tx endif .PHONY: FORCE check-symbols check-security # bitcoin core # BITCOIN_CORE_H = \ addrdb.h \ addrman.h \ avalanche.h \ base58.h \ bloom.h \ blockencodings.h \ blockfileinfo.h \ blockfilter.h \ blockindexworkcomparator.h \ blockstatus.h \ blockvalidity.h \ cashaddr.h \ cashaddrenc.h \ chain.h \ chainparams.h \ chainparamsbase.h \ chainparamsseeds.h \ checkpoints.h \ checkqueue.h \ clientversion.h \ coins.h \ compat.h \ compat/byteswap.h \ compat/endian.h \ compat/sanity.h \ compressor.h \ config.h \ consensus/activation.h \ consensus/consensus.h \ consensus/tx_verify.h \ core_io.h \ core_memusage.h \ cuckoocache.h \ diskblockpos.h \ dstencode.h \ fs.h \ globals.h \ httprpc.h \ httpserver.h \ indirectmap.h \ init.h \ interfaces/handler.h \ interfaces/node.h \ interfaces/wallet.h \ key.h \ keystore.h \ dbwrapper.h \ limitedmap.h \ logging.h \ memusage.h \ merkleblock.h \ miner.h \ net.h \ net_processing.h \ netaddress.h \ netbase.h \ netmessagemaker.h \ noui.h \ policy/fees.h \ policy/policy.h \ pow.h \ protocol.h \ radix.h \ random.h \ rcu.h \ reverse_iterator.h \ reverselock.h \ rpc/blockchain.h \ rpc/client.h \ rpc/command.h \ rpc/jsonrpcrequest.h \ rpc/mining.h \ rpc/misc.h \ rpc/protocol.h \ rpc/rawtransaction.h \ rpc/server.h \ rpc/tojson.h \ rpc/register.h \ + rpc/util.h \ rwcollection.h \ scheduler.h \ script/scriptcache.h \ script/sigcache.h \ script/sign.h \ script/standard.h \ script/ismine.h \ streams.h \ support/allocators/secure.h \ support/allocators/zeroafterfree.h \ support/cleanse.h \ support/events.h \ support/lockedpool.h \ sync.h \ threadsafety.h \ threadinterrupt.h \ timedata.h \ torcontrol.h \ txdb.h \ txmempool.h \ ui_interface.h \ undo.h \ util.h \ utilmoneystr.h \ utiltime.h \ validation.h \ validationinterface.h \ versionbits.h \ walletinitinterface.h \ wallet/coincontrol.h \ wallet/crypter.h \ wallet/db.h \ wallet/finaltx.h \ wallet/rpcdump.h \ wallet/fees.h \ wallet/rpcwallet.h \ wallet/wallet.h \ wallet/walletdb.h \ wallet/walletutil.h \ warnings.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h\ zmq/zmqnotificationinterface.h \ zmq/zmqpublishnotifier.h obj/build.h: FORCE @$(MKDIR_P) "$(builddir)/obj" @$(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \ "$(abs_top_srcdir)" libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: shared between bitcoind and bitcoin-qt libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ addrdb.cpp \ avalanche.cpp \ bloom.cpp \ blockencodings.cpp \ blockfilter.cpp \ chain.cpp \ checkpoints.cpp \ config.cpp \ consensus/activation.cpp \ consensus/tx_verify.cpp \ globals.cpp \ httprpc.cpp \ httpserver.cpp \ init.cpp \ interfaces/handler.cpp \ interfaces/node.cpp \ dbwrapper.cpp \ merkleblock.cpp \ miner.cpp \ net.cpp \ net_processing.cpp \ noui.cpp \ policy/fees.cpp \ policy/policy.cpp \ pow.cpp \ rest.cpp \ rpc/abc.cpp \ rpc/blockchain.cpp \ rpc/command.cpp \ rpc/jsonrpcrequest.cpp \ rpc/mining.cpp \ rpc/misc.cpp \ rpc/net.cpp \ rpc/rawtransaction.cpp \ rpc/server.cpp \ script/scriptcache.cpp \ script/sigcache.cpp \ script/ismine.cpp \ timedata.cpp \ torcontrol.cpp \ txdb.cpp \ txmempool.cpp \ ui_interface.cpp \ validation.cpp \ validationinterface.cpp \ $(BITCOIN_CORE_H) if ENABLE_ZMQ libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_zmq_a_SOURCES = \ zmq/zmqabstractnotifier.cpp \ zmq/zmqnotificationinterface.cpp \ zmq/zmqpublishnotifier.cpp endif # wallet: shared between bitcoind and bitcoin-qt, but only linked # when wallet enabled libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ interfaces/wallet.cpp \ wallet/crypter.cpp \ wallet/db.cpp \ wallet/finaltx.cpp \ wallet/fees.cpp \ wallet/init.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/wallet.cpp \ wallet/walletdb.cpp \ wallet/walletutil.cpp \ $(BITCOIN_CORE_H) # crypto primitives library crypto_libbitcoin_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_base_a_SOURCES = \ crypto/aes.cpp \ crypto/aes.h \ crypto/chacha20.h \ crypto/chacha20.cpp \ crypto/common.h \ crypto/hmac_sha256.cpp \ crypto/hmac_sha256.h \ crypto/hmac_sha512.cpp \ crypto/hmac_sha512.h \ crypto/ripemd160.cpp \ crypto/ripemd160.h \ crypto/sha1.cpp \ crypto/sha1.h \ crypto/sha256.cpp \ crypto/sha256.h \ crypto/sha512.cpp \ crypto/sha512.h \ crypto/siphash.cpp \ crypto/siphash.h if USE_ASM crypto_libbitcoin_crypto_base_a_SOURCES += crypto/sha256_sse4.cpp endif crypto_libbitcoin_crypto_sse41_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_sse41_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_sse41_a_CXXFLAGS += $(SSE41_CXXFLAGS) crypto_libbitcoin_crypto_sse41_a_CPPFLAGS += -DENABLE_SSE41 crypto_libbitcoin_crypto_sse41_a_SOURCES = crypto/sha256_sse41.cpp crypto_libbitcoin_crypto_avx2_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_avx2_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_avx2_a_CXXFLAGS += $(AVX2_CXXFLAGS) crypto_libbitcoin_crypto_avx2_a_CPPFLAGS += -DENABLE_AVX2 crypto_libbitcoin_crypto_avx2_a_SOURCES = crypto/sha256_avx2.cpp crypto_libbitcoin_crypto_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_shani_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_shani_a_CXXFLAGS += $(SHANI_CXXFLAGS) crypto_libbitcoin_crypto_shani_a_CPPFLAGS += -DENABLE_SHANI crypto_libbitcoin_crypto_shani_a_SOURCES = crypto/sha256_shani.cpp # consensus: shared between all executables that validate any consensus rules. libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_consensus_a_SOURCES = \ amount.h \ arith_uint256.cpp \ arith_uint256.h \ consensus/merkle.cpp \ consensus/merkle.h \ consensus/params.h \ consensus/validation.h \ feerate.h \ hash.cpp \ hash.h \ prevector.h \ primitives/block.cpp \ primitives/block.h \ primitives/transaction.cpp \ primitives/transaction.h \ primitives/txid.h \ pubkey.cpp \ pubkey.h \ script/bitcoinconsensus.cpp \ script/sighashtype.h \ script/interpreter.cpp \ script/interpreter.h \ script/script.cpp \ script/script.h \ script/script_error.cpp \ script/script_error.h \ script/script_flags.h \ script/sigencoding.cpp \ script/sigencoding.h \ serialize.h \ tinyformat.h \ uint256.cpp \ uint256.h \ utilstrencodings.cpp \ utilstrencodings.h \ version.h # common: shared between bitcoind, and bitcoin-qt and non-server tools libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ amount.cpp \ base58.cpp \ cashaddr.cpp \ cashaddrenc.cpp \ chainparams.cpp \ config.cpp \ coins.cpp \ compressor.cpp \ dstencode.cpp \ feerate.cpp \ globals.cpp \ core_read.cpp \ core_write.cpp \ key.cpp \ keystore.cpp \ netaddress.cpp \ netbase.cpp \ protocol.cpp \ scheduler.cpp \ script/sign.cpp \ script/standard.cpp \ warnings.cpp \ $(BITCOIN_CORE_H) # util: shared between all executables. # This library *must* be included to make sure that the glibc # backward-compatibility objects and their sanity checks are linked. libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/lockedpool.cpp \ chainparamsbase.cpp \ clientversion.cpp \ compat/glibc_sanity.cpp \ compat/glibcxx_sanity.cpp \ compat/strnlen.cpp \ fs.cpp \ logging.cpp \ random.cpp \ rcu.cpp \ rpc/protocol.cpp \ + rpc/util.cpp \ support/cleanse.cpp \ sync.cpp \ threadinterrupt.cpp \ uint256.cpp \ uint256.h \ util.cpp \ utilmoneystr.cpp \ utilstrencodings.cpp \ utiltime.cpp \ $(BITCOIN_CORE_H) if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp AM_LDFLAGS += $(COMPAT_LDFLAGS) endif # cli: shared between bitcoin-cli and bitcoin-qt libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ rpc/client.cpp \ $(BITCOIN_CORE_H) # seeder library libbitcoin_seeder_a_CPPFLAGS = $(AM_CPPFLAGS) $(PIE_FLAGS) $(BITCOIN_SEEDER_INCLUDES) libbitcoin_seeder_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_seeder_a_SOURCES = \ seeder/bitcoin.cpp \ seeder/bitcoin.h \ seeder/db.cpp \ seeder/db.h \ seeder/dns.cpp \ seeder/dns.h \ seeder/strlcpy.h \ seeder/util.h nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # # bitcoind binary # bitcoind_SOURCES = bitcoind.cpp bitcoind_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) bitcoind_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS bitcoind_SOURCES += bitcoind-res.rc endif bitcoind_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_ZMQ) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) \ $(LIBMEMENV) \ $(LIBSECP256K1) bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) # bitcoin-cli binary # bitcoin_cli_SOURCES = bitcoin-cli.cpp bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) bitcoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS bitcoin_cli_SOURCES += bitcoin-cli-res.rc endif bitcoin_cli_LDADD = \ $(LIBBITCOIN_CLI) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) # # bitcoin-seeder binary # bitcoin_seeder_SOURCES = seeder/main.cpp bitcoin_seeder_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_SEEDER_INCLUDES) bitcoin_seeder_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_seeder_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) bitcoin_seeder_LDADD = \ $(LIBBITCOIN_SEEDER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) bitcoin_seeder_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # # bitcoin-tx binary # bitcoin_tx_SOURCES = bitcoin-tx.cpp bitcoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) bitcoin_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS bitcoin_tx_SOURCES += bitcoin-tx-res.rc endif bitcoin_tx_LDADD = \ $(LIBUNIVALUE) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # # bitcoinconsensus library # if BUILD_BITCOIN_LIBS include_HEADERS = script/bitcoinconsensus.h libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_base_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) if GLIBC_BACK_COMPAT libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp endif libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) endif # CTAES_DIST = crypto/ctaes/bench.c CTAES_DIST += crypto/ctaes/ctaes.c CTAES_DIST += crypto/ctaes/ctaes.h CTAES_DIST += crypto/ctaes/README.md CTAES_DIST += crypto/ctaes/test.c CLEANFILES = $(EXTRA_LIBRARIES) CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno CLEANFILES += policy/*.gcda policy/*.gcno CLEANFILES += primitives/*.gcda primitives/*.gcno CLEANFILES += script/*.gcda script/*.gcno CLEANFILES += support/*.gcda support/*.gcno CLEANFILES += univalue/*.gcda univalue/*.gcno CLEANFILES += wallet/*.gcda wallet/*.gcno CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno CLEANFILES += zmq/*.gcda zmq/*.gcno DISTCLEANFILES = obj/build.h EXTRA_DIST = $(CTAES_DIST) clean-local: -$(MAKE) -C secp256k1 clean -$(MAKE) -C univalue clean -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno -rm -rf test/__pycache__ .rc.o: @test -f $(WINDRES) ## FIXME: How to get the appropriate modulename_CPPFLAGS in here? $(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@ .mm.o: $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $< check-symbols: $(bin_PROGRAMS) if GLIBC_BACK_COMPAT @echo "Checking glibc back compat..." $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS) endif check-security: $(bin_PROGRAMS) if HARDEN @echo "Checking binary security..." $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) endif %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$( #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #ifdef ENABLE_WALLET #include #include #include #endif #include #include #include #ifdef HAVE_MALLOC_INFO #include #endif /** * @note Do not add or change anything in the information returned by this * method. `getinfo` exists for backwards-compatibility only. It combines * information from wildly different sources in the program, which is a mess, * and is thus planned to be deprecated eventually. * * Based on the source of the information, new information should be added to: * - `getblockchaininfo`, * - `getnetworkinfo` or * - `getwalletinfo` * * Or alternatively, create a specific query method for the information. **/ static UniValue getinfo(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( "getinfo\n" "\nDEPRECATED. Returns an object containing various state info.\n" "\nResult:\n" "{\n" " \"version\": xxxxx, (numeric) the server version\n" " \"protocolversion\": xxxxx, (numeric) the protocol version\n" " \"walletversion\": xxxxx, (numeric) the wallet version\n" " \"balance\": xxxxxxx, (numeric) the total bitcoin " "balance of the wallet\n" " \"blocks\": xxxxxx, (numeric) the current number of " "blocks processed in the server\n" " \"timeoffset\": xxxxx, (numeric) the time offset\n" " \"connections\": xxxxx, (numeric) the number of " "connections\n" " \"proxy\": \"host:port\", (string, optional) the proxy used " "by the server\n" " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" " \"testnet\": true|false, (boolean) if the server is using " "testnet or not\n" " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds " "since Unix epoch) of the oldest pre-generated key in the key " "pool\n" " \"keypoolsize\": xxxx, (numeric) how many new keys are " "pre-generated\n" " \"unlocked_until\": ttt, (numeric) the timestamp in " "seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is " "unlocked for transfers, or 0 if the wallet is locked\n" " \"paytxfee\": x.xxxx, (numeric) the transaction fee set " "in " + CURRENCY_UNIT + "/kB\n" " \"relayfee\": x.xxxx, (numeric) minimum relay fee for " "non-free transactions in " + CURRENCY_UNIT + "/kB\n" " \"errors\": \"...\" (string) any error messages\n" "}\n" "\nExamples:\n" + HelpExampleCli("getinfo", "") + HelpExampleRpc("getinfo", "")); } #ifdef ENABLE_WALLET CWallet *const pwallet = GetWalletForJSONRPCRequest(request); LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr); #else LOCK(cs_main); #endif proxyType proxy; GetProxy(NET_IPV4, proxy); UniValue obj(UniValue::VOBJ); obj.pushKV("version", CLIENT_VERSION); obj.pushKV("protocolversion", PROTOCOL_VERSION); #ifdef ENABLE_WALLET if (pwallet) { obj.pushKV("walletversion", pwallet->GetVersion()); obj.pushKV("balance", ValueFromAmount(pwallet->GetBalance())); } #endif obj.pushKV("blocks", (int)chainActive.Height()); obj.pushKV("timeoffset", GetTimeOffset()); if (g_connman) { obj.pushKV("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); } obj.pushKV("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string())); obj.pushKV("difficulty", double(GetDifficulty(chainActive.Tip()))); obj.pushKV("testnet", config.GetChainParams().NetworkIDString() == CBaseChainParams::TESTNET); #ifdef ENABLE_WALLET if (pwallet) { obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime()); obj.pushKV("keypoolsize", (int)pwallet->GetKeyPoolSize()); } if (pwallet && pwallet->IsCrypted()) { obj.pushKV("unlocked_until", pwallet->nRelockTime); } obj.pushKV("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())); #endif obj.pushKV("relayfee", ValueFromAmount(config.GetMinFeePerKB().GetFeePerK())); obj.pushKV("errors", GetWarnings("statusbar")); return obj; } #ifdef ENABLE_WALLET class DescribeAddressVisitor : public boost::static_visitor { public: CWallet *const pwallet; explicit DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {} UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); } UniValue operator()(const CKeyID &keyID) const { UniValue obj(UniValue::VOBJ); CPubKey vchPubKey; obj.pushKV("isscript", false); if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) { obj.pushKV("pubkey", HexStr(vchPubKey)); obj.pushKV("iscompressed", vchPubKey.IsCompressed()); } return obj; } UniValue operator()(const CScriptID &scriptID) const { UniValue obj(UniValue::VOBJ); CScript subscript; obj.pushKV("isscript", true); if (pwallet && pwallet->GetCScript(scriptID, subscript)) { std::vector addresses; txnouttype whichType; int nRequired; ExtractDestinations(subscript, whichType, addresses, nRequired); obj.pushKV("script", GetTxnOutputType(whichType)); obj.pushKV("hex", HexStr(subscript.begin(), subscript.end())); UniValue a(UniValue::VARR); for (const CTxDestination &addr : addresses) { a.push_back(EncodeDestination(addr)); } obj.pushKV("addresses", a); if (whichType == TX_MULTISIG) { obj.pushKV("sigsrequired", nRequired); } } return obj; } }; #endif static UniValue validateaddress(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( "validateaddress \"address\"\n" "\nReturn information about the given bitcoin address.\n" "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to " "validate\n" "\nResult:\n" "{\n" " \"isvalid\" : true|false, (boolean) If the address is " "valid or not. If not, this is the only property returned.\n" " \"address\" : \"address\", (string) The bitcoin address " "validated\n" " \"scriptPubKey\" : \"hex\", (string) The hex encoded " "scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is " "yours or not\n" " \"iswatchonly\" : true|false, (boolean) If the address is " "watchonly\n" " \"isscript\" : true|false, (boolean) If the key is a " "script\n" " \"pubkey\" : \"publickeyhex\", (string) The hex value of the " "raw public key\n" " \"iscompressed\" : true|false, (boolean) If the address is " "compressed\n" " \"account\" : \"account\" (string) DEPRECATED. The " "account associated with the address, \"\" is the default account\n" " \"timestamp\" : timestamp, (number, optional) The " "creation time of the key if available in seconds since epoch (Jan " "1 1970 GMT)\n" " \"hdkeypath\" : \"keypath\" (string, optional) The HD " "keypath if the key is HD and available\n" " \"hdmasterkeyid\" : \"\" (string, optional) The " "Hash160 of the HD master pubkey\n" "}\n" "\nExamples:\n" + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")); } #ifdef ENABLE_WALLET CWallet *const pwallet = GetWalletForJSONRPCRequest(request); LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr); #else LOCK(cs_main); #endif CTxDestination dest = DecodeDestination(request.params[0].get_str(), config.GetChainParams()); bool isValid = IsValidDestination(dest); UniValue ret(UniValue::VOBJ); ret.pushKV("isvalid", isValid); if (isValid) { std::string currentAddress = EncodeDestination(dest); ret.pushKV("address", currentAddress); CScript scriptPubKey = GetScriptForDestination(dest); ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())); #ifdef ENABLE_WALLET isminetype mine = pwallet ? IsMine(*pwallet, dest) : ISMINE_NO; ret.pushKV("ismine", (mine & ISMINE_SPENDABLE) ? true : false); ret.pushKV("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true : false); UniValue detail = boost::apply_visitor(DescribeAddressVisitor(pwallet), dest); ret.pushKVs(detail); if (pwallet && pwallet->mapAddressBook.count(dest)) { ret.pushKV("account", pwallet->mapAddressBook[dest].name); } if (pwallet) { const CKeyMetadata *meta = nullptr; if (const CKeyID *key_id = boost::get(&dest)) { auto it = pwallet->mapKeyMetadata.find(*key_id); if (it != pwallet->mapKeyMetadata.end()) { meta = &it->second; } } if (!meta) { auto it = pwallet->m_script_metadata.find(CScriptID(scriptPubKey)); if (it != pwallet->m_script_metadata.end()) { meta = &it->second; } } if (meta) { ret.pushKV("timestamp", meta->nCreateTime); if (!meta->hdKeypath.empty()) { ret.pushKV("hdkeypath", meta->hdKeypath); ret.pushKV("hdmasterkeyid", meta->hdMasterKeyID.GetHex()); } } } #endif } return ret; } // Needed even with !ENABLE_WALLET, to pass (ignored) pointers around class CWallet; -/** - * Used by addmultisigaddress / createmultisig: - */ -CScript createmultisig_redeemScript(CWallet *const pwallet, - const UniValue ¶ms) { - int nRequired = params[0].get_int(); - const UniValue &keys = params[1].get_array(); - - // Gather public keys - if (nRequired < 1) { - throw std::runtime_error( - "a multisignature address must require at least one key to redeem"); - } - if ((int)keys.size() < nRequired) { - throw std::runtime_error( - strprintf("not enough keys supplied " - "(got %u keys, but need at least %d to redeem)", - keys.size(), nRequired)); - } - if (keys.size() > 16) { - throw std::runtime_error( - "Number of addresses involved in the " - "multisignature address creation > 16\nReduce the " - "number"); - } - std::vector pubkeys; - pubkeys.resize(keys.size()); - for (size_t i = 0; i < keys.size(); i++) { - const std::string &ks = keys[i].get_str(); -#ifdef ENABLE_WALLET - // Case 1: Bitcoin address and we have full public key: - if (pwallet) { - CTxDestination dest = DecodeDestination(ks, pwallet->chainParams); - if (IsValidDestination(dest)) { - const CKeyID *keyID = boost::get(&dest); - if (!keyID) { - throw std::runtime_error( - strprintf("%s does not refer to a key", ks)); - } - CPubKey vchPubKey; - if (!pwallet->GetPubKey(*keyID, vchPubKey)) { - throw std::runtime_error( - strprintf("no full public key for address %s", ks)); - } - if (!vchPubKey.IsFullyValid()) { - throw std::runtime_error(" Invalid public key: " + ks); - } - pubkeys[i] = vchPubKey; - continue; - } - } -#endif - // Case 2: hex public key - if (IsHex(ks)) { - CPubKey vchPubKey(ParseHex(ks)); - if (!vchPubKey.IsFullyValid()) { - throw std::runtime_error(" Invalid public key: " + ks); - } - pubkeys[i] = vchPubKey; - } else { - throw std::runtime_error(" Invalid public key: " + ks); - } - } - - CScript result = GetScriptForMultisig(nRequired, pubkeys); - if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) { - throw std::runtime_error( - strprintf("redeemScript exceeds size limit: %d > %d", result.size(), - MAX_SCRIPT_ELEMENT_SIZE)); - } - - return result; -} - static UniValue createmultisig(const Config &config, const JSONRPCRequest &request) { -#ifdef ENABLE_WALLET - CWallet *const pwallet = GetWalletForJSONRPCRequest(request); -#else - CWallet *const pwallet = nullptr; -#endif - if (request.fHelp || request.params.size() < 2 || request.params.size() > 2) { std::string msg = "createmultisig nrequired [\"key\",...]\n" "\nCreates a multi-signature address with n signature of m keys " "required.\n" "It returns a json object with the address and redeemScript.\n" - + "DEPRECATION WARNING: Using addresses with createmultisig is " + "deprecated. Clients must\n" + "transition to using addmultisigaddress to create multisig " + "addresses with addresses known\n" + "to the wallet before upgrading to v0.20. To use the deprecated " + "functionality, start bitcoind with -deprecatedrpc=createmultisig\n" "\nArguments:\n" "1. nrequired (numeric, required) The number of required " "signatures out of the n keys or addresses.\n" - "2. \"keys\" (string, required) A json array of keys which " - "are bitcoin addresses or hex-encoded public keys\n" + "2. \"keys\" (string, required) A json array of hex-encoded " + "public keys\n" " [\n" - " \"key\" (string) bitcoin address or hex-encoded public " - "key\n" + " \"key\" (string) The hex-encoded public key\n" " ,...\n" " ]\n" "\nResult:\n" "{\n" " \"address\":\"multisigaddress\", (string) The value of the new " "multisig address.\n" " \"redeemScript\":\"script\" (string) The string value of " "the hex-encoded redemption script.\n" "}\n" "\nExamples:\n" - "\nCreate a multisig address from 2 addresses\n" + + "\nCreate a multisig address from 2 public keys\n" + HelpExampleCli("createmultisig", "2 " - "\"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\"," - "\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") + + "\"[" + "\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3" + "42cf11ae157a7ace5fd\\\"," + "\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1" + "7e107ef3f6aa5a61626\\\"]\"") + "\nAs a json rpc call\n" + HelpExampleRpc("createmultisig", "2, " - "\"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\"," - "\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\""); + "\"[" + "\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3" + "42cf11ae157a7ace5fd\\\"," + "\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1" + "7e107ef3f6aa5a61626\\\"]\""); throw std::runtime_error(msg); } + int required = request.params[0].get_int(); + + // Get the public keys + const UniValue &keys = request.params[1].get_array(); + std::vector pubkeys; + for (size_t i = 0; i < keys.size(); ++i) { + if (IsHex(keys[i].get_str()) && (keys[i].get_str().length() == 66 || + keys[i].get_str().length() == 130)) { + pubkeys.push_back(HexToPubKey(keys[i].get_str())); + } else { +#ifdef ENABLE_WALLET + CWallet *const pwallet = GetWalletForJSONRPCRequest(request); + if (IsDeprecatedRPCEnabled(gArgs, "createmultisig") && + EnsureWalletIsAvailable(pwallet, false)) { + pubkeys.push_back(AddrToPubKey(config.GetChainParams(), pwallet, + keys[i].get_str())); + } else +#endif + throw JSONRPCError( + RPC_INVALID_ADDRESS_OR_KEY, + strprintf("Invalid public key: %s\nNote that from v0.19.6, " + "createmultisig no longer accepts addresses." + " Clients must transition to using " + "addmultisigaddress to create multisig addresses " + "with addresses known to the wallet before " + "upgrading to v0.20." + " To use the deprecated functionality, start " + "bitcoind with -deprecatedrpc=createmultisig", + keys[i].get_str())); + } + } + // Construct using pay-to-script-hash: - CScript inner = createmultisig_redeemScript(pwallet, request.params); + CScript inner = CreateMultisigRedeemscript(required, pubkeys); CScriptID innerID(inner); UniValue result(UniValue::VOBJ); result.pushKV("address", EncodeDestination(innerID)); result.pushKV("redeemScript", HexStr(inner.begin(), inner.end())); return result; } static UniValue verifymessage(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 3) { throw std::runtime_error( "verifymessage \"address\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to " "use for the signature.\n" "2. \"signature\" (string, required) The signature provided " "by the signer in base 64 encoding (see signmessage).\n" "3. \"message\" (string, required) The message that was " "signed.\n" "\nResult:\n" "true|false (boolean) If the signature is verified or not.\n" "\nExamples:\n" "\nUnlock the wallet for 30 seconds\n" + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + "\nCreate the signature\n" + HelpExampleCli( "signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + "\nVerify the signature\n" + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" "XX\" \"signature\" \"my " "message\"") + "\nAs json rpc\n" + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" "XX\", \"signature\", \"my " "message\"")); } LOCK(cs_main); std::string strAddress = request.params[0].get_str(); std::string strSign = request.params[1].get_str(); std::string strMessage = request.params[2].get_str(); CTxDestination destination = DecodeDestination(strAddress, config.GetChainParams()); if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } const CKeyID *keyID = boost::get(&destination); if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } bool fInvalid = false; std::vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); if (fInvalid) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); } CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; ss << strMessage; CPubKey pubkey; if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) { return false; } return (pubkey.GetID() == *keyID); } static UniValue signmessagewithprivkey(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 2) { throw std::runtime_error( "signmessagewithprivkey \"privkey\" \"message\"\n" "\nSign a message with the private key of an address\n" "\nArguments:\n" "1. \"privkey\" (string, required) The private key to sign " "the message with.\n" "2. \"message\" (string, required) The message to create a " "signature of.\n" "\nResult:\n" "\"signature\" (string) The signature of the message " "encoded in base 64\n" "\nExamples:\n" "\nCreate the signature\n" + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") + "\nVerify the signature\n" + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" "XX\" \"signature\" \"my " "message\"") + "\nAs json rpc\n" + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")); } std::string strPrivkey = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(strPrivkey); if (!fGood) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); } CKey key = vchSecret.GetKey(); if (!key.IsValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range"); } CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; ss << strMessage; std::vector vchSig; if (!key.SignCompact(ss.GetHash(), vchSig)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); } return EncodeBase64(&vchSig[0], vchSig.size()); } static UniValue setmocktime(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( "setmocktime timestamp\n" "\nSet the local time to given timestamp (-regtest only)\n" "\nArguments:\n" "1. timestamp (integer, required) Unix seconds-since-epoch " "timestamp\n" " Pass 0 to go back to using the system time."); } if (!config.GetChainParams().MineBlocksOnDemand()) { throw std::runtime_error( "setmocktime for regression testing (-regtest mode) only"); } // For now, don't change mocktime if we're in the middle of validation, as // this could have an effect on mempool time-based eviction, as well as // IsInitialBlockDownload(). // TODO: figure out the right way to synchronize around mocktime, and // ensure all callsites of GetTime() are accessing this safely. LOCK(cs_main); RPCTypeCheck(request.params, {UniValue::VNUM}); SetMockTime(request.params[0].get_int64()); return NullUniValue; } static UniValue RPCLockedMemoryInfo() { LockedPool::Stats stats = LockedPoolManager::Instance().stats(); UniValue obj(UniValue::VOBJ); obj.pushKV("used", uint64_t(stats.used)); obj.pushKV("free", uint64_t(stats.free)); obj.pushKV("total", uint64_t(stats.total)); obj.pushKV("locked", uint64_t(stats.locked)); obj.pushKV("chunks_used", uint64_t(stats.chunks_used)); obj.pushKV("chunks_free", uint64_t(stats.chunks_free)); return obj; } #ifdef HAVE_MALLOC_INFO static std::string RPCMallocInfo() { char *ptr = nullptr; size_t size = 0; FILE *f = open_memstream(&ptr, &size); if (f) { malloc_info(0, f); fclose(f); if (ptr) { std::string rv(ptr, size); free(ptr); return rv; } } return ""; } #endif static UniValue getmemoryinfo(const Config &config, const JSONRPCRequest &request) { /* Please, avoid using the word "pool" here in the RPC interface or help, * as users will undoubtedly confuse it with the other "memory pool" */ if (request.fHelp || request.params.size() > 1) { throw std::runtime_error( "getmemoryinfo (\"mode\")\n" "Returns an object containing information about memory usage.\n" "Arguments:\n" "1. \"mode\" determines what kind of information is returned. This " "argument is optional, the default mode is \"stats\".\n" " - \"stats\" returns general statistics about memory usage in " "the daemon.\n" " - \"mallocinfo\" returns an XML string describing low-level " "heap state (only available if compiled with glibc 2.10+).\n" "\nResult (mode \"stats\"):\n" "{\n" " \"locked\": { (json object) Information about " "locked memory manager\n" " \"used\": xxxxx, (numeric) Number of bytes used\n" " \"free\": xxxxx, (numeric) Number of bytes available " "in current arenas\n" " \"total\": xxxxxxx, (numeric) Total number of bytes " "managed\n" " \"locked\": xxxxxx, (numeric) Amount of bytes that " "succeeded locking. If this number is smaller than total, locking " "pages failed at some point and key data could be swapped to " "disk.\n" " \"chunks_used\": xxxxx, (numeric) Number allocated chunks\n" " \"chunks_free\": xxxxx, (numeric) Number unused chunks\n" " }\n" "}\n" "\nResult (mode \"mallocinfo\"):\n" "\"...\"\n" "\nExamples:\n" + HelpExampleCli("getmemoryinfo", "") + HelpExampleRpc("getmemoryinfo", "")); } std::string mode = (request.params.size() < 1 || request.params[0].isNull()) ? "stats" : request.params[0].get_str(); if (mode == "stats") { UniValue obj(UniValue::VOBJ); obj.pushKV("locked", RPCLockedMemoryInfo()); return obj; } else if (mode == "mallocinfo") { #ifdef HAVE_MALLOC_INFO return RPCMallocInfo(); #else throw JSONRPCError( RPC_INVALID_PARAMETER, "mallocinfo is only available when compiled with glibc 2.10+"); #endif } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode); } } static UniValue echo(const Config &config, const JSONRPCRequest &request) { if (request.fHelp) { throw std::runtime_error( "echo|echojson \"message\" ...\n" "\nSimply echo back the input arguments. This command is for " "testing.\n" "\nThe difference between echo and echojson is that echojson has " "argument conversion enabled in the client-side table in" "bitcoin-cli and the GUI. There is no server-side difference."); } return request.params; } // clang-format off static const ContextFreeRPCCommand commands[] = { // category name actor (function) argNames // ------------------- ------------------------ ---------------------- ---------- { "control", "getinfo", getinfo, {} }, /* uses wallet if enabled */ { "control", "getmemoryinfo", getmemoryinfo, {"mode"} }, { "util", "validateaddress", validateaddress, {"address"} }, /* uses wallet if enabled */ { "util", "createmultisig", createmultisig, {"nrequired","keys"} }, { "util", "verifymessage", verifymessage, {"address","signature","message"} }, { "util", "signmessagewithprivkey", signmessagewithprivkey, {"privkey","message"} }, /* Not shown in help */ { "hidden", "setmocktime", setmocktime, {"timestamp"}}, { "hidden", "echo", echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, { "hidden", "echojson", echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, }; // clang-format on void RegisterMiscRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) { t.appendCommand(commands[vcidx].name, &commands[vcidx]); } } diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp new file mode 100644 index 000000000..e603518a6 --- /dev/null +++ b/src/rpc/util.cpp @@ -0,0 +1,86 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include + +// Converts a hex string to a public key if possible +CPubKey HexToPubKey(const std::string &hex_in) { + if (!IsHex(hex_in)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, + "Invalid public key: " + hex_in); + } + CPubKey vchPubKey(ParseHex(hex_in)); + if (!vchPubKey.IsFullyValid()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, + "Invalid public key: " + hex_in); + } + return vchPubKey; +} + +// Retrieves a public key for an address from the given CKeyStore +CPubKey AddrToPubKey(const CChainParams &chainparams, CKeyStore *const keystore, + const std::string &addr_in) { + CTxDestination dest = DecodeDestination(addr_in, chainparams); + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, + "Invalid address: " + addr_in); + } + CKeyID key = boost::get(dest); + if (key.IsNull()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, + strprintf("%s does not refer to a key", addr_in)); + } + CPubKey vchPubKey; + if (!keystore->GetPubKey(key, vchPubKey)) { + throw JSONRPCError( + RPC_INVALID_ADDRESS_OR_KEY, + strprintf("no full public key for address %s", addr_in)); + } + if (!vchPubKey.IsFullyValid()) { + throw JSONRPCError(RPC_INTERNAL_ERROR, + "Wallet contains an invalid public key"); + } + return vchPubKey; +} + +// Creates a multisig redeemscript from a given list of public keys and number +// required. +CScript CreateMultisigRedeemscript(const int required, + const std::vector &pubkeys) { + // Gather public keys + if (required < 1) { + throw JSONRPCError( + RPC_INVALID_PARAMETER, + "a multisignature address must require at least one key to redeem"); + } + if ((int)pubkeys.size() < required) { + throw JSONRPCError(RPC_INVALID_PARAMETER, + strprintf("not enough keys supplied (got %u keys, " + "but need at least %d to redeem)", + pubkeys.size(), required)); + } + if (pubkeys.size() > 16) { + throw JSONRPCError(RPC_INVALID_PARAMETER, + "Number of keys involved in the multisignature " + "address creation > 16\nReduce the number"); + } + + CScript result = GetScriptForMultisig(required, pubkeys); + + if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) { + throw JSONRPCError( + RPC_INVALID_PARAMETER, + (strprintf("redeemScript exceeds size limit: %d > %d", + result.size(), MAX_SCRIPT_ELEMENT_SIZE))); + } + + return result; +} diff --git a/src/rpc/util.h b/src/rpc/util.h new file mode 100644 index 000000000..c9eee7b75 --- /dev/null +++ b/src/rpc/util.h @@ -0,0 +1,22 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RPC_UTIL_H +#define BITCOIN_RPC_UTIL_H + +#include +#include + +class CChainParams; +class CKeyStore; +class CPubKey; +class CScript; + +CPubKey HexToPubKey(const std::string &hex_in); +CPubKey AddrToPubKey(const CChainParams &chainparams, CKeyStore *const keystore, + const std::string &addr_in); +CScript CreateMultisigRedeemscript(const int required, + const std::vector &pubkeys); + +#endif // BITCOIN_RPC_UTIL_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7062d6523..2de9d4909 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1,3942 +1,3978 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include // for GetConsensus. #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include // Input src/init.h (not wallet/init.h) for StartShutdown #include #include #include static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; static std::string urlDecode(const std::string &urlEncoded) { std::string res; if (!urlEncoded.empty()) { char *decoded = evhttp_uridecode(urlEncoded.c_str(), false, nullptr); if (decoded) { res = std::string(decoded); free(decoded); } } return res; } CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest &request) { if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) { // wallet endpoint was used std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size())); for (CWalletRef pwallet : ::vpwallets) { if (pwallet->GetName() == requestedWallet) { return pwallet; } } throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded"); } return ::vpwallets.size() == 1 || (request.fHelp && ::vpwallets.size() > 0) ? ::vpwallets[0] : nullptr; } std::string HelpRequiringPassphrase(CWallet *const pwallet) { return pwallet && pwallet->IsCrypted() ? "\nRequires wallet passphrase to " "be set with walletpassphrase " "call." : ""; } bool EnsureWalletIsAvailable(CWallet *const pwallet, bool avoidException) { if (pwallet) { return true; } if (avoidException) { return false; } if (::vpwallets.empty()) { // Note: It isn't currently possible to trigger this error because // wallet RPC methods aren't registered unless a wallet is loaded. But // this error is being kept as a precaution, because it's possible in // the future that wallet RPC methods might get or remain registered // when no wallets are loaded. throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (wallet " "method is disabled because " "no wallet is loaded)"); } throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED, "Wallet file not specified (must request wallet RPC " "through /wallet/ uri-path)."); } void EnsureWalletIsUnlocked(CWallet *const pwallet) { if (pwallet->IsLocked()) { throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the " "wallet passphrase with " "walletpassphrase first."); } } void WalletTxToJSON(const CWalletTx &wtx, UniValue &entry) { int confirms = wtx.GetDepthInMainChain(); entry.pushKV("confirmations", confirms); if (wtx.IsCoinBase()) { entry.pushKV("generated", true); } if (confirms > 0) { entry.pushKV("blockhash", wtx.hashBlock.GetHex()); entry.pushKV("blockindex", wtx.nIndex); entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime()); } else { entry.pushKV("trusted", wtx.IsTrusted()); } uint256 hash = wtx.GetId(); entry.pushKV("txid", hash.GetHex()); UniValue conflicts(UniValue::VARR); for (const uint256 &conflict : wtx.GetConflicts()) { conflicts.push_back(conflict.GetHex()); } entry.pushKV("walletconflicts", conflicts); entry.pushKV("time", wtx.GetTxTime()); entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived); for (const std::pair &item : wtx.mapValue) { entry.pushKV(item.first, item.second); } } std::string LabelFromValue(const UniValue &value) { std::string label = value.get_str(); if (label == "*") { throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name"); } return label; } static UniValue getnewaddress(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() > 1) { throw std::runtime_error( "getnewaddress ( \"label\" )\n" "\nReturns a new Bitcoin address for receiving payments.\n" "If 'label' is specified, it is added to the address book \n" "so payments received with the address will be associated with " "'label'.\n" "\nArguments:\n" "1. \"label\" (string, optional) The label name for the " "address to be linked to. If not provided, the default label \"\" " "is used. It can also be set to the empty string \"\" to represent " "the default label. The label does not need to exist, it will be " "created if there is no label by the given name.\n" "\nResult:\n" "\"address\" (string) The new bitcoin address\n" "\nExamples:\n" + HelpExampleRpc("getnewaddress", "")); } LOCK2(cs_main, pwallet->cs_wallet); // Parse the label first so we don't generate a key if there's an error std::string label; if (!request.params[0].isNull()) { label = LabelFromValue(request.params[0]); } if (!pwallet->IsLocked()) { pwallet->TopUpKeyPool(); } // Generate a new key that is added to wallet CPubKey newKey; if (!pwallet->GetKeyFromPool(newKey)) { throw JSONRPCError( RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); } CKeyID keyID = newKey.GetID(); pwallet->SetAddressBook(keyID, label, "receive"); return EncodeDestination(keyID); } CTxDestination GetLabelAddress(CWallet *const pwallet, const std::string &label, bool bForceNew = false) { CPubKey pubKey; if (!pwallet->GetLabelAddress(pubKey, label, bForceNew)) { throw JSONRPCError( RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); } return pubKey.GetID(); } UniValue getlabeladdress(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( "getlabeladdress \"label\"\n" "\nReturns the current Bitcoin address for receiving payments to " "this label.\n" "\nArguments:\n" "1. \"label\" (string, required) The label name for the " "address. It can also be set to the empty string \"\" to represent " "the default label. The label does not need to exist, it will be " "created and a new address created if there is no label by the " "given name.\n" "\nResult:\n" "\"address\" (string) The label bitcoin address\n" "\nExamples:\n" + HelpExampleCli("getlabeladdress", "") + HelpExampleCli("getlabeladdress", "\"\"") + HelpExampleCli("getlabeladdress", "\"mylabel\"") + HelpExampleRpc("getlabeladdress", "\"mylabel\"")); } LOCK2(cs_main, pwallet->cs_wallet); // Parse the label first so we don't generate a key if there's an error std::string label = LabelFromValue(request.params[0]); UniValue ret(UniValue::VSTR); ret = EncodeDestination(GetLabelAddress(pwallet, label)); return ret; } static UniValue getrawchangeaddress(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() > 0) { throw std::runtime_error( "getrawchangeaddress\n" "\nReturns a new Bitcoin address, for receiving change.\n" "This is for use with raw transactions, NOT normal use.\n" "\nResult:\n" "\"address\" (string) The address\n" "\nExamples:\n" + HelpExampleCli("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", "")); } LOCK2(cs_main, pwallet->cs_wallet); if (!pwallet->IsLocked()) { pwallet->TopUpKeyPool(); } CReserveKey reservekey(pwallet); CPubKey vchPubKey; if (!reservekey.GetReservedKey(vchPubKey, true)) { throw JSONRPCError( RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); } reservekey.KeepKey(); CKeyID keyID = vchPubKey.GetID(); return EncodeDestination(keyID); } UniValue setlabel(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( "setlabel \"address\" \"label\"\n" "\nSets the label associated with the given address.\n" "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to " "be associated with a label.\n" "2. \"label\" (string, required) The label to assign the " "address to.\n" "\nExamples:\n" + HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") + HelpExampleRpc( "setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")); } LOCK2(cs_main, pwallet->cs_wallet); CTxDestination dest = DecodeDestination(request.params[0].get_str(), config.GetChainParams()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); } std::string label; if (!request.params[1].isNull()) { label = LabelFromValue(request.params[1]); } // Only add the label if the address is yours. if (IsMine(*pwallet, dest)) { // Detect when changing the label of an address that is the 'unused // current key' of another label: if (pwallet->mapAddressBook.count(dest)) { std::string old_label = pwallet->mapAddressBook[dest].name; if (dest == GetLabelAddress(pwallet, old_label)) { GetLabelAddress(pwallet, old_label, true); } } pwallet->SetAddressBook(dest, label, "receive"); } else { throw JSONRPCError(RPC_MISC_ERROR, "setlabel can only be used with own address"); } return NullUniValue; } static UniValue getaccount(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( "getaccount \"address\"\n" "\nDEPRECATED. Returns the account associated with the given " "address.\n" "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address for " "account lookup.\n" "\nResult:\n" "\"accountname\" (string) the account address\n" "\nExamples:\n" + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"")); } LOCK2(cs_main, pwallet->cs_wallet); CTxDestination dest = DecodeDestination(request.params[0].get_str(), config.GetChainParams()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); } std::string strAccount; std::map::iterator mi = pwallet->mapAddressBook.find(dest); if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) { strAccount = (*mi).second.name; } return strAccount; } static UniValue getaddressesbyaccount(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( "getaddressesbyaccount \"account\"\n" "\nDEPRECATED. Returns the list of addresses for the given " "account.\n" "\nArguments:\n" "1. \"account\" (string, required) The account name.\n" "\nResult:\n" "[ (json array of string)\n" " \"address\" (string) a bitcoin address associated with " "the given account\n" " ,...\n" "]\n" "\nExamples:\n" + HelpExampleCli("getaddressesbyaccount", "\"tabby\"") + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")); } LOCK2(cs_main, pwallet->cs_wallet); std::string strAccount = LabelFromValue(request.params[0]); // Find all addresses that have the given account UniValue ret(UniValue::VARR); for (const std::pair &item : pwallet->mapAddressBook) { const CTxDestination &dest = item.first; const std::string &strName = item.second.name; if (strName == strAccount) { ret.push_back(EncodeDestination(dest)); } } return ret; } static CTransactionRef SendMoney(CWallet *const pwallet, const CTxDestination &address, Amount nValue, bool fSubtractFeeFromAmount, mapValue_t mapValue, std::string fromAccount) { Amount curBalance = pwallet->GetBalance(); // Check amount if (nValue <= Amount::zero()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); } if (nValue > curBalance) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); } if (pwallet->GetBroadcastTransactions() && !g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } // Parse Bitcoin address CScript scriptPubKey = GetScriptForDestination(address); // Create and send the transaction CReserveKey reservekey(pwallet); Amount nFeeRequired; std::string strError; std::vector vecSend; int nChangePosRet = -1; CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; vecSend.push_back(recipient); CCoinControl coinControl; CTransactionRef tx; if (!pwallet->CreateTransaction(vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coinControl)) { if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) { strError = strprintf("Error: This transaction requires a " "transaction fee of at least %s", FormatMoney(nFeeRequired)); } throw JSONRPCError(RPC_WALLET_ERROR, strError); } CValidationState state; if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(fromAccount), reservekey, g_connman.get(), state)) { strError = strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()); throw JSONRPCError(RPC_WALLET_ERROR, strError); } return tx; } static UniValue sendtoaddress(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) { throw std::runtime_error( "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" " "subtractfeefromamount )\n" "\nSend an amount to a given address.\n" + HelpRequiringPassphrase(pwallet) + "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address " "to send to.\n" "2. \"amount\" (numeric or string, required) The " "amount in " + CURRENCY_UNIT + " to send. eg 0.1\n" "3. \"comment\" (string, optional) A comment used to " "store what the transaction is for. \n" " This is not part of the transaction, " "just kept in your wallet.\n" "4. \"comment_to\" (string, optional) A comment to store " "the name of the person or organization \n" " to which you're sending the " "transaction. This is not part of the \n" " transaction, just kept in your " "wallet.\n" "5. subtractfeefromamount (boolean, optional, default=false) The " "fee will be deducted from the amount being sent.\n" " The recipient will receive less " "bitcoins than you enter in the amount field.\n" "\nResult:\n" "\"txid\" (string) The transaction id.\n" "\nExamples:\n" + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1") + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvay" "dd\" 0.1 \"donation\" \"seans " "outpost\"") + HelpExampleCli( "sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true") + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvay" "dd\", 0.1, \"donation\", \"seans " "outpost\"")); } // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now pwallet->BlockUntilSyncedToCurrentChain(); LOCK2(cs_main, pwallet->cs_wallet); CTxDestination dest = DecodeDestination(request.params[0].get_str(), config.GetChainParams()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); } // Amount Amount nAmount = AmountFromValue(request.params[1]); if (nAmount <= Amount::zero()) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); } // Wallet comments mapValue_t mapValue; if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty()) { mapValue["comment"] = request.params[2].get_str(); } if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty()) { mapValue["to"] = request.params[3].get_str(); } bool fSubtractFeeFromAmount = false; if (request.params.size() > 4) { fSubtractFeeFromAmount = request.params[4].get_bool(); } EnsureWalletIsUnlocked(pwallet); CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, std::move(mapValue), {} /* fromAccount */); return tx->GetId().GetHex(); } static UniValue listaddressgroupings(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( "listaddressgroupings\n" "\nLists groups of addresses which have had their common " "ownership\n" "made public by common use as inputs or as the resulting change\n" "in past transactions\n" "\nResult:\n" "[\n" " [\n" " [\n" " \"address\", (string) The bitcoin address\n" " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n" " \"label\" (string, optional) The label\n" " ]\n" " ,...\n" " ]\n" " ,...\n" "]\n" "\nExamples:\n" + HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "")); } // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now pwallet->BlockUntilSyncedToCurrentChain(); LOCK2(cs_main, pwallet->cs_wallet); UniValue jsonGroupings(UniValue::VARR); std::map balances = pwallet->GetAddressBalances(); for (const std::set &grouping : pwallet->GetAddressGroupings()) { UniValue jsonGrouping(UniValue::VARR); for (const CTxDestination &address : grouping) { UniValue addressInfo(UniValue::VARR); addressInfo.push_back(EncodeDestination(address)); addressInfo.push_back(ValueFromAmount(balances[address])); if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) { addressInfo.push_back( pwallet->mapAddressBook.find(address)->second.name); } jsonGrouping.push_back(addressInfo); } jsonGroupings.push_back(jsonGrouping); } return jsonGroupings; } static UniValue signmessage(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() != 2) { throw std::runtime_error( "signmessage \"address\" \"message\"\n" "\nSign a message with the private key of an address" + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to " "use for the private key.\n" "2. \"message\" (string, required) The message to create a " "signature of.\n" "\nResult:\n" "\"signature\" (string) The signature of the message " "encoded in base 64\n" "\nExamples:\n" "\nUnlock the wallet for 30 seconds\n" + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + "\nCreate the signature\n" + HelpExampleCli( "signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + "\nVerify the signature\n" + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" "XX\" \"signature\" \"my " "message\"") + "\nAs json rpc\n" + HelpExampleRpc( "signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")); } LOCK2(cs_main, pwallet->cs_wallet); EnsureWalletIsUnlocked(pwallet); std::string strAddress = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); CTxDestination dest = DecodeDestination(strAddress, config.GetChainParams()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } const CKeyID *keyID = boost::get(&dest); if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } CKey key; if (!pwallet->GetKey(*keyID, key)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); } CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; ss << strMessage; std::vector vchSig; if (!key.SignCompact(ss.GetHash(), vchSig)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); } return EncodeBase64(&vchSig[0], vchSig.size()); } static UniValue getreceivedbyaddress(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( "getreceivedbyaddress \"address\" ( minconf )\n" "\nReturns the total amount received by the given address in " "transactions with at least minconf confirmations.\n" "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address for " "transactions.\n" "2. minconf (numeric, optional, default=1) Only " "include transactions confirmed at least this many times.\n" "\nResult:\n" "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n" "\nExamples:\n" "\nThe amount from transactions with at least 1 confirmation\n" + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") + "\nThe amount including unconfirmed transactions, zero " "confirmations\n" + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 0") + "\nThe amount with at least 6 confirmations\n" + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 6") + "\nAs a json rpc call\n" + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")); } // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now pwallet->BlockUntilSyncedToCurrentChain(); LOCK2(cs_main, pwallet->cs_wallet); // Bitcoin address CTxDestination dest = DecodeDestination(request.params[0].get_str(), config.GetChainParams()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); } CScript scriptPubKey = GetScriptForDestination(dest); if (!IsMine(*pwallet, scriptPubKey)) { throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet"); } // Minimum confirmations int nMinDepth = 1; if (!request.params[1].isNull()) { nMinDepth = request.params[1].get_int(); } // Tally Amount nAmount = Amount::zero(); for (const std::pair &pairWtx : pwallet->mapWallet) { const CWalletTx &wtx = pairWtx.second; CValidationState state; if (wtx.IsCoinBase() || !ContextualCheckTransactionForCurrentBlock( config, *wtx.tx, state)) { continue; } for (const CTxOut &txout : wtx.tx->vout) { if (txout.scriptPubKey == scriptPubKey) { if (wtx.GetDepthInMainChain() >= nMinDepth) { nAmount += txout.nValue; } } } } return ValueFromAmount(nAmount); } UniValue getreceivedbylabel(const Config &config, const JSONRPCRequest &request) { CWallet *const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( "getreceivedbylabel \"label\" ( minconf )\n" "\nReturns the total amount received by addresses with