Initial Vexta Core v0.1.0 release
This commit is contained in:
commit
25c454329d
2481 changed files with 689289 additions and 0 deletions
56
src/.clang-format
Normal file
56
src/.clang-format
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: true
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterFunction: true
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
IndentCaseLabels: false
|
||||
IndentFunctionDeclarationAfterType: false
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
918
src/Makefile.am
Normal file
918
src/Makefile.am
Normal file
|
|
@ -0,0 +1,918 @@
|
|||
# Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
# Copyright (c) 2014-2019 The Vexta Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
# Pattern rule to print variables, e.g. make print-top_srcdir
|
||||
print-%: FORCE
|
||||
@echo '$*'='$($*)'
|
||||
|
||||
DIST_SUBDIRS = secp256k1 univalue
|
||||
|
||||
AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
|
||||
AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS)
|
||||
AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS)
|
||||
AM_LIBTOOLFLAGS = --preserve-dup-deps
|
||||
PTHREAD_FLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
|
||||
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
|
||||
|
||||
VEXTA_INCLUDES=-I$(builddir) -I$(srcdir)/secp256k1/include $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
|
||||
|
||||
VEXTA_INCLUDES += $(UNIVALUE_CFLAGS)
|
||||
|
||||
LIBVEXTA_SERVER=libvexta_server.a
|
||||
LIBVEXTA_COMMON=libvexta_common.a
|
||||
LIBVEXTA_CONSENSUS=libvexta_consensus.a
|
||||
LIBVEXTA_CLI=libvexta_cli.a
|
||||
LIBVEXTA_UTIL=libvexta_util.a
|
||||
LIBVEXTA_CRYPTO_BASE=crypto/libvexta_crypto_base.a
|
||||
LIBVEXTAQT=qt/libvextaqt.a
|
||||
LIBSECP256K1=secp256k1/libsecp256k1.la
|
||||
|
||||
if ENABLE_ZMQ
|
||||
LIBVEXTA_ZMQ=libvexta_zmq.a
|
||||
endif
|
||||
if BUILD_VEXTA_LIBS
|
||||
LIBVEXTACONSENSUS=libvextaconsensus.la
|
||||
endif
|
||||
if ENABLE_WALLET
|
||||
LIBVEXTA_WALLET=libvexta_wallet.a
|
||||
LIBVEXTA_WALLET_TOOL=libvexta_wallet_tool.a
|
||||
endif
|
||||
|
||||
LIBVEXTA_CRYPTO= $(LIBVEXTA_CRYPTO_BASE)
|
||||
if ENABLE_SSE41
|
||||
LIBVEXTA_CRYPTO_SSE41 = crypto/libvexta_crypto_sse41.a
|
||||
LIBVEXTA_CRYPTO += $(LIBVEXTA_CRYPTO_SSE41)
|
||||
endif
|
||||
if ENABLE_AVX2
|
||||
LIBVEXTA_CRYPTO_AVX2 = crypto/libvexta_crypto_avx2.a
|
||||
LIBVEXTA_CRYPTO += $(LIBVEXTA_CRYPTO_AVX2)
|
||||
endif
|
||||
if ENABLE_SHANI
|
||||
LIBVEXTA_CRYPTO_SHANI = crypto/libvexta_crypto_shani.a
|
||||
LIBVEXTA_CRYPTO += $(LIBVEXTA_CRYPTO_SHANI)
|
||||
endif
|
||||
|
||||
$(LIBSECP256K1): $(wildcard secp256k1/src/*.h) $(wildcard secp256k1/src/*.c) $(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 += \
|
||||
$(LIBVEXTA_CRYPTO) \
|
||||
$(LIBVEXTA_UTIL) \
|
||||
$(LIBVEXTA_COMMON) \
|
||||
$(LIBVEXTA_CONSENSUS) \
|
||||
$(LIBVEXTA_SERVER) \
|
||||
$(LIBVEXTA_CLI) \
|
||||
$(LIBVEXTA_IPC) \
|
||||
$(LIBVEXTA_WALLET) \
|
||||
$(LIBVEXTA_WALLET_TOOL) \
|
||||
$(LIBVEXTA_ZMQ)
|
||||
|
||||
lib_LTLIBRARIES = $(LIBVEXTACONSENSUS)
|
||||
|
||||
bin_PROGRAMS =
|
||||
noinst_PROGRAMS =
|
||||
TESTS =
|
||||
BENCHMARKS =
|
||||
|
||||
if BUILD_DIGIBYTED
|
||||
bin_PROGRAMS += vextad
|
||||
endif
|
||||
|
||||
if BUILD_VEXTA_NODE
|
||||
bin_PROGRAMS += vexta-node
|
||||
endif
|
||||
|
||||
if BUILD_VEXTA_CLI
|
||||
bin_PROGRAMS += vexta-cli
|
||||
endif
|
||||
|
||||
if BUILD_VEXTA_TX
|
||||
bin_PROGRAMS += vexta-tx
|
||||
endif
|
||||
|
||||
if ENABLE_WALLET
|
||||
if BUILD_VEXTA_WALLET
|
||||
bin_PROGRAMS += vexta-wallet
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_VEXTA_UTIL
|
||||
bin_PROGRAMS += vexta-util
|
||||
endif
|
||||
|
||||
.PHONY: FORCE check-symbols check-security
|
||||
# digibyte core #
|
||||
VEXTA_CORE_H = \
|
||||
addrdb.h \
|
||||
addrman.h \
|
||||
attributes.h \
|
||||
banman.h \
|
||||
base58.h \
|
||||
bech32.h \
|
||||
blockencodings.h \
|
||||
blockfilter.h \
|
||||
bloom.h \
|
||||
chain.h \
|
||||
chainparams.h \
|
||||
chainparamsbase.h \
|
||||
chainparamsseeds.h \
|
||||
checkqueue.h \
|
||||
clientversion.h \
|
||||
coins.h \
|
||||
compat.h \
|
||||
compat/assumptions.h \
|
||||
compat/byteswap.h \
|
||||
compat/cpuid.h \
|
||||
compat/endian.h \
|
||||
compat/sanity.h \
|
||||
compressor.h \
|
||||
consensus/consensus.h \
|
||||
consensus/tx_check.h \
|
||||
consensus/tx_verify.h \
|
||||
core_io.h \
|
||||
core_memusage.h \
|
||||
cuckoocache.h \
|
||||
dbwrapper.h \
|
||||
deploymentinfo.h \
|
||||
deploymentstatus.h \
|
||||
external_signer.h \
|
||||
flatfile.h \
|
||||
fs.h \
|
||||
httprpc.h \
|
||||
httpserver.h \
|
||||
i2p.h \
|
||||
index/base.h \
|
||||
index/blockfilterindex.h \
|
||||
index/coinstatsindex.h \
|
||||
index/disktxpos.h \
|
||||
index/txindex.h \
|
||||
indirectmap.h \
|
||||
init.h \
|
||||
init/common.h \
|
||||
interfaces/chain.h \
|
||||
interfaces/echo.h \
|
||||
interfaces/handler.h \
|
||||
interfaces/init.h \
|
||||
interfaces/ipc.h \
|
||||
interfaces/node.h \
|
||||
interfaces/wallet.h \
|
||||
key.h \
|
||||
key_io.h \
|
||||
logging.h \
|
||||
logging/timer.h \
|
||||
mapport.h \
|
||||
memusage.h \
|
||||
merkleblock.h \
|
||||
miner.h \
|
||||
net.h \
|
||||
net_permissions.h \
|
||||
net_processing.h \
|
||||
net_types.h \
|
||||
netaddress.h \
|
||||
netbase.h \
|
||||
netmessagemaker.h \
|
||||
node/blockstorage.h \
|
||||
node/coin.h \
|
||||
node/coinstats.h \
|
||||
node/context.h \
|
||||
node/psbt.h \
|
||||
node/transaction.h \
|
||||
node/ui_interface.h \
|
||||
node/utxo_snapshot.h \
|
||||
noui.h \
|
||||
outputtype.h \
|
||||
policy/feerate.h \
|
||||
policy/fees.h \
|
||||
policy/packages.h \
|
||||
policy/policy.h \
|
||||
policy/rbf.h \
|
||||
policy/settings.h \
|
||||
pow.h \
|
||||
protocol.h \
|
||||
psbt.h \
|
||||
random.h \
|
||||
randomenv.h \
|
||||
reverse_iterator.h \
|
||||
rpc/blockchain.h \
|
||||
rpc/client.h \
|
||||
rpc/mining.h \
|
||||
rpc/net.h \
|
||||
rpc/protocol.h \
|
||||
rpc/rawtransaction_util.h \
|
||||
rpc/register.h \
|
||||
rpc/request.h \
|
||||
rpc/server.h \
|
||||
rpc/util.h \
|
||||
scheduler.h \
|
||||
script/descriptor.h \
|
||||
script/keyorigin.h \
|
||||
script/sigcache.h \
|
||||
script/sign.h \
|
||||
script/signingprovider.h \
|
||||
script/standard.h \
|
||||
shutdown.h \
|
||||
signet.h \
|
||||
streams.h \
|
||||
support/allocators/secure.h \
|
||||
support/allocators/zeroafterfree.h \
|
||||
support/cleanse.h \
|
||||
support/events.h \
|
||||
support/lockedpool.h \
|
||||
sync.h \
|
||||
threadinterrupt.h \
|
||||
threadsafety.h \
|
||||
timedata.h \
|
||||
torcontrol.h \
|
||||
txdb.h \
|
||||
txmempool.h \
|
||||
txorphanage.h \
|
||||
txrequest.h \
|
||||
undo.h \
|
||||
util/asmap.h \
|
||||
util/bip32.h \
|
||||
util/bytevectorhash.h \
|
||||
util/check.h \
|
||||
util/epochguard.h \
|
||||
util/error.h \
|
||||
util/fees.h \
|
||||
util/getuniquepath.h \
|
||||
util/golombrice.h \
|
||||
util/hash_type.h \
|
||||
util/hasher.h \
|
||||
util/macros.h \
|
||||
util/message.h \
|
||||
util/moneystr.h \
|
||||
util/rbf.h \
|
||||
util/readwritefile.h \
|
||||
util/serfloat.h \
|
||||
util/settings.h \
|
||||
util/sock.h \
|
||||
util/spanparsing.h \
|
||||
util/string.h \
|
||||
util/system.h \
|
||||
util/thread.h \
|
||||
util/threadnames.h \
|
||||
util/time.h \
|
||||
util/tokenpipe.h \
|
||||
util/trace.h \
|
||||
util/translation.h \
|
||||
util/ui_change_type.h \
|
||||
util/url.h \
|
||||
util/vector.h \
|
||||
validation.h \
|
||||
validationinterface.h \
|
||||
versionbits.h \
|
||||
wallet/bdb.h \
|
||||
wallet/coincontrol.h \
|
||||
wallet/coinselection.h \
|
||||
wallet/context.h \
|
||||
wallet/crypter.h \
|
||||
wallet/db.h \
|
||||
wallet/dump.h \
|
||||
wallet/external_signer_scriptpubkeyman.h \
|
||||
wallet/feebumper.h \
|
||||
wallet/fees.h \
|
||||
wallet/ismine.h \
|
||||
wallet/load.h \
|
||||
wallet/receive.h \
|
||||
wallet/rpcwallet.h \
|
||||
wallet/salvage.h \
|
||||
wallet/scriptpubkeyman.h \
|
||||
wallet/spend.h \
|
||||
wallet/sqlite.h \
|
||||
wallet/transaction.h \
|
||||
wallet/wallet.h \
|
||||
wallet/walletdb.h \
|
||||
wallet/wallettool.h \
|
||||
wallet/walletutil.h \
|
||||
walletinitinterface.h \
|
||||
warnings.h \
|
||||
zmq/zmqabstractnotifier.h \
|
||||
zmq/zmqnotificationinterface.h \
|
||||
zmq/zmqpublishnotifier.h \
|
||||
zmq/zmqrpc.h \
|
||||
zmq/zmqutil.h
|
||||
|
||||
|
||||
obj/build.h: FORCE
|
||||
@$(MKDIR_P) $(builddir)/obj
|
||||
@$(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \
|
||||
"$(abs_top_srcdir)"
|
||||
libvexta_util_a-clientversion.$(OBJEXT): obj/build.h
|
||||
|
||||
ipc/capnp/libvexta_ipc_a-ipc.$(OBJEXT): $(libvexta_ipc_mpgen_input:=.h)
|
||||
|
||||
# server: shared between vextad and vexta-qt
|
||||
# Contains code accessing mempool and chain state that is meant to be separated
|
||||
# from wallet and gui code (see node/README.md). Shared code should go in
|
||||
# libvexta_common or libvexta_util libraries, instead.
|
||||
libvexta_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
|
||||
libvexta_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libvexta_server_a_SOURCES = \
|
||||
addrdb.cpp \
|
||||
addrman.cpp \
|
||||
banman.cpp \
|
||||
blockencodings.cpp \
|
||||
blockfilter.cpp \
|
||||
chain.cpp \
|
||||
consensus/tx_verify.cpp \
|
||||
dandelion.cpp \
|
||||
dbwrapper.cpp \
|
||||
deploymentstatus.cpp \
|
||||
flatfile.cpp \
|
||||
httprpc.cpp \
|
||||
httpserver.cpp \
|
||||
i2p.cpp \
|
||||
index/base.cpp \
|
||||
index/blockfilterindex.cpp \
|
||||
index/coinstatsindex.cpp \
|
||||
index/txindex.cpp \
|
||||
init.cpp \
|
||||
mapport.cpp \
|
||||
miner.cpp \
|
||||
net.cpp \
|
||||
net_processing.cpp \
|
||||
node/blockstorage.cpp \
|
||||
node/coin.cpp \
|
||||
node/coinstats.cpp \
|
||||
node/context.cpp \
|
||||
node/interfaces.cpp \
|
||||
node/psbt.cpp \
|
||||
node/transaction.cpp \
|
||||
node/ui_interface.cpp \
|
||||
noui.cpp \
|
||||
policy/fees.cpp \
|
||||
policy/packages.cpp \
|
||||
policy/rbf.cpp \
|
||||
policy/settings.cpp \
|
||||
pow.cpp \
|
||||
rest.cpp \
|
||||
rpc/blockchain.cpp \
|
||||
rpc/mining.cpp \
|
||||
rpc/misc.cpp \
|
||||
rpc/net.cpp \
|
||||
rpc/rawtransaction.cpp \
|
||||
rpc/server.cpp \
|
||||
script/sigcache.cpp \
|
||||
shutdown.cpp \
|
||||
signet.cpp \
|
||||
timedata.cpp \
|
||||
torcontrol.cpp \
|
||||
txdb.cpp \
|
||||
txmempool.cpp \
|
||||
txorphanage.cpp \
|
||||
txrequest.cpp \
|
||||
validation.cpp \
|
||||
validationinterface.cpp \
|
||||
versionbits.cpp \
|
||||
$(VEXTA_CORE_H)
|
||||
|
||||
if ENABLE_WALLET
|
||||
libvexta_server_a_SOURCES += wallet/init.cpp
|
||||
endif
|
||||
if !ENABLE_WALLET
|
||||
libvexta_server_a_SOURCES += dummywallet.cpp
|
||||
endif
|
||||
|
||||
if ENABLE_ZMQ
|
||||
libvexta_zmq_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES) $(ZMQ_CFLAGS)
|
||||
libvexta_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libvexta_zmq_a_SOURCES = \
|
||||
zmq/zmqabstractnotifier.cpp \
|
||||
zmq/zmqnotificationinterface.cpp \
|
||||
zmq/zmqpublishnotifier.cpp \
|
||||
zmq/zmqrpc.cpp \
|
||||
zmq/zmqutil.cpp
|
||||
endif
|
||||
|
||||
|
||||
# wallet: shared between vextad and vexta-qt, but only linked
|
||||
# when wallet enabled
|
||||
libvexta_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES) $(SQLITE_CFLAGS)
|
||||
libvexta_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libvexta_wallet_a_SOURCES = \
|
||||
wallet/coincontrol.cpp \
|
||||
wallet/context.cpp \
|
||||
wallet/crypter.cpp \
|
||||
wallet/db.cpp \
|
||||
wallet/dump.cpp \
|
||||
wallet/external_signer_scriptpubkeyman.cpp \
|
||||
wallet/feebumper.cpp \
|
||||
wallet/fees.cpp \
|
||||
wallet/interfaces.cpp \
|
||||
wallet/load.cpp \
|
||||
wallet/receive.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
wallet/scriptpubkeyman.cpp \
|
||||
wallet/spend.cpp \
|
||||
wallet/transaction.cpp \
|
||||
wallet/wallet.cpp \
|
||||
wallet/walletdb.cpp \
|
||||
wallet/walletutil.cpp \
|
||||
wallet/coinselection.cpp \
|
||||
$(VEXTA_CORE_H)
|
||||
|
||||
if USE_SQLITE
|
||||
libvexta_wallet_a_SOURCES += wallet/sqlite.cpp
|
||||
endif
|
||||
if USE_BDB
|
||||
libvexta_wallet_a_SOURCES += wallet/bdb.cpp wallet/salvage.cpp
|
||||
endif
|
||||
|
||||
libvexta_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
libvexta_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libvexta_wallet_tool_a_SOURCES = \
|
||||
wallet/wallettool.cpp \
|
||||
$(VEXTA_CORE_H)
|
||||
|
||||
# crypto primitives library
|
||||
crypto_libvexta_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
crypto_libvexta_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
crypto_libvexta_crypto_base_a_SOURCES = \
|
||||
crypto/aes.cpp \
|
||||
crypto/aes_helper.cpp \
|
||||
crypto/aes.h \
|
||||
crypto/chacha_poly_aead.h \
|
||||
crypto/chacha_poly_aead.cpp \
|
||||
crypto/chacha20.h \
|
||||
crypto/chacha20.cpp \
|
||||
crypto/common.h \
|
||||
crypto/hkdf_sha256_32.cpp \
|
||||
crypto/hkdf_sha256_32.h \
|
||||
crypto/hmac_sha256.cpp \
|
||||
crypto/hmac_sha256.h \
|
||||
crypto/hmac_sha512.cpp \
|
||||
crypto/hmac_sha512.h \
|
||||
crypto/KeccakP-800-reference.cpp \
|
||||
crypto/KeccakP-800-SnP.h \
|
||||
crypto/poly1305.h \
|
||||
crypto/poly1305.cpp \
|
||||
crypto/muhash.h \
|
||||
crypto/muhash.cpp \
|
||||
crypto/ripemd160.cpp \
|
||||
crypto/ripemd160.h \
|
||||
crypto/sha1.cpp \
|
||||
crypto/sha1.h \
|
||||
crypto/sha256.cpp \
|
||||
crypto/sha256.h \
|
||||
crypto/sha3.cpp \
|
||||
crypto/sha3.h \
|
||||
crypto/sha512.cpp \
|
||||
crypto/sha512.h \
|
||||
crypto/siphash.cpp \
|
||||
crypto/siphash.h
|
||||
|
||||
|
||||
if USE_ASM
|
||||
crypto_libvexta_crypto_base_a_SOURCES += crypto/sha256_sse4.cpp
|
||||
endif
|
||||
|
||||
crypto_libvexta_crypto_sse41_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
crypto_libvexta_crypto_sse41_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
crypto_libvexta_crypto_sse41_a_CXXFLAGS += $(SSE41_CXXFLAGS)
|
||||
crypto_libvexta_crypto_sse41_a_CPPFLAGS += -DENABLE_SSE41
|
||||
crypto_libvexta_crypto_sse41_a_SOURCES = crypto/sha256_sse41.cpp
|
||||
|
||||
crypto_libvexta_crypto_avx2_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
crypto_libvexta_crypto_avx2_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
crypto_libvexta_crypto_avx2_a_CXXFLAGS += $(AVX2_CXXFLAGS)
|
||||
crypto_libvexta_crypto_avx2_a_CPPFLAGS += -DENABLE_AVX2
|
||||
crypto_libvexta_crypto_avx2_a_SOURCES = crypto/sha256_avx2.cpp
|
||||
|
||||
crypto_libvexta_crypto_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
crypto_libvexta_crypto_shani_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
crypto_libvexta_crypto_shani_a_CXXFLAGS += $(SHANI_CXXFLAGS)
|
||||
crypto_libvexta_crypto_shani_a_CPPFLAGS += -DENABLE_SHANI
|
||||
crypto_libvexta_crypto_shani_a_SOURCES = crypto/sha256_shani.cpp
|
||||
|
||||
# consensus: shared between all executables that validate any consensus rules.
|
||||
libvexta_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
libvexta_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libvexta_consensus_a_SOURCES = \
|
||||
amount.h \
|
||||
arith_uint256.cpp \
|
||||
arith_uint256.h \
|
||||
consensus/merkle.cpp \
|
||||
consensus/merkle.h \
|
||||
consensus/params.h \
|
||||
consensus/tx_check.cpp \
|
||||
consensus/validation.h \
|
||||
crypto/blake.cpp \
|
||||
crypto/bmw.cpp \
|
||||
crypto/cubehash.cpp \
|
||||
crypto/echo.cpp \
|
||||
crypto/jh.cpp \
|
||||
crypto/keccak.cpp \
|
||||
crypto/luffa.cpp \
|
||||
crypto/shavite.cpp \
|
||||
crypto/simd.cpp \
|
||||
crypto/hashodo.h \
|
||||
crypto/sph_blake.h \
|
||||
crypto/sph_bmw.h \
|
||||
crypto/sph_cubehash.h \
|
||||
crypto/sph_echo.h \
|
||||
crypto/sph_jh.h \
|
||||
crypto/sph_keccak.h \
|
||||
crypto/sph_luffa.h \
|
||||
crypto/sph_shavite.h \
|
||||
crypto/sph_simd.h \
|
||||
crypto/sph_types.h \
|
||||
hash.cpp \
|
||||
hash.h \
|
||||
prevector.h \
|
||||
primitives/block.cpp \
|
||||
primitives/block.h \
|
||||
primitives/transaction.cpp \
|
||||
primitives/transaction.h \
|
||||
pubkey.cpp \
|
||||
pubkey.h \
|
||||
script/vextaconsensus.cpp \
|
||||
script/interpreter.cpp \
|
||||
script/interpreter.h \
|
||||
script/script.cpp \
|
||||
script/script.h \
|
||||
script/script_error.cpp \
|
||||
script/script_error.h \
|
||||
serialize.h \
|
||||
span.h \
|
||||
tinyformat.h \
|
||||
uint256.cpp \
|
||||
uint256.h \
|
||||
util/strencodings.cpp \
|
||||
util/strencodings.h \
|
||||
version.h
|
||||
|
||||
# common: shared between vextad, and vexta-qt and non-server tools
|
||||
libvexta_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
libvexta_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libvexta_common_a_SOURCES = \
|
||||
base58.cpp \
|
||||
bech32.cpp \
|
||||
bloom.cpp \
|
||||
chainparams.cpp \
|
||||
coins.cpp \
|
||||
compressor.cpp \
|
||||
core_read.cpp \
|
||||
core_write.cpp \
|
||||
deploymentinfo.cpp \
|
||||
external_signer.cpp \
|
||||
init/common.cpp \
|
||||
key.cpp \
|
||||
key_io.cpp \
|
||||
merkleblock.cpp \
|
||||
netaddress.cpp \
|
||||
netbase.cpp \
|
||||
net_permissions.cpp \
|
||||
outputtype.cpp \
|
||||
policy/feerate.cpp \
|
||||
policy/policy.cpp \
|
||||
protocol.cpp \
|
||||
psbt.cpp \
|
||||
rpc/rawtransaction_util.cpp \
|
||||
rpc/external_signer.cpp \
|
||||
rpc/util.cpp \
|
||||
scheduler.cpp \
|
||||
script/descriptor.cpp \
|
||||
script/sign.cpp \
|
||||
script/signingprovider.cpp \
|
||||
script/standard.cpp \
|
||||
warnings.cpp \
|
||||
$(VEXTA_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.
|
||||
libvexta_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
libvexta_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libvexta_util_a_SOURCES = \
|
||||
support/lockedpool.cpp \
|
||||
chainparamsbase.cpp \
|
||||
clientversion.cpp \
|
||||
compat/glibcxx_sanity.cpp \
|
||||
compat/strnlen.cpp \
|
||||
fs.cpp \
|
||||
interfaces/echo.cpp \
|
||||
interfaces/handler.cpp \
|
||||
interfaces/init.cpp \
|
||||
logging.cpp \
|
||||
random.cpp \
|
||||
randomenv.cpp \
|
||||
rpc/request.cpp \
|
||||
support/cleanse.cpp \
|
||||
sync.cpp \
|
||||
threadinterrupt.cpp \
|
||||
util/asmap.cpp \
|
||||
util/bip32.cpp \
|
||||
util/bytevectorhash.cpp \
|
||||
util/error.cpp \
|
||||
util/fees.cpp \
|
||||
util/getuniquepath.cpp \
|
||||
util/hasher.cpp \
|
||||
util/sock.cpp \
|
||||
util/system.cpp \
|
||||
util/message.cpp \
|
||||
util/moneystr.cpp \
|
||||
util/rbf.cpp \
|
||||
util/readwritefile.cpp \
|
||||
util/settings.cpp \
|
||||
util/thread.cpp \
|
||||
util/threadnames.cpp \
|
||||
util/serfloat.cpp \
|
||||
util/spanparsing.cpp \
|
||||
util/strencodings.cpp \
|
||||
util/string.cpp \
|
||||
util/time.cpp \
|
||||
util/tokenpipe.cpp \
|
||||
$(VEXTA_CORE_H)
|
||||
|
||||
if USE_LIBEVENT
|
||||
libvexta_util_a_SOURCES += util/url.cpp
|
||||
endif
|
||||
|
||||
if GLIBC_BACK_COMPAT
|
||||
libvexta_util_a_SOURCES += compat/glibc_compat.cpp
|
||||
AM_LDFLAGS += $(COMPAT_LDFLAGS)
|
||||
endif
|
||||
|
||||
# cli: shared between vexta-cli and vexta-qt
|
||||
libvexta_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
libvexta_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libvexta_cli_a_SOURCES = \
|
||||
compat/stdin.h \
|
||||
compat/stdin.cpp \
|
||||
rpc/client.cpp \
|
||||
$(VEXTA_CORE_H)
|
||||
|
||||
nodist_libvexta_util_a_SOURCES = $(srcdir)/obj/build.h
|
||||
#
|
||||
|
||||
# vextad # vextad & digibyte-node binaries # vexta-node binaries #
|
||||
vexta_daemon_sources = vextad.cpp
|
||||
vexta_bin_cppflags = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
vexta_bin_cxxflags = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
vexta_bin_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
|
||||
if TARGET_WINDOWS
|
||||
vexta_daemon_sources += vextad-res.rc
|
||||
endif
|
||||
|
||||
vexta_bin_ldadd = \
|
||||
$(LIBVEXTA_WALLET) \
|
||||
$(LIBVEXTA_COMMON) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBVEXTA_UTIL) \
|
||||
$(LIBVEXTA_ZMQ) \
|
||||
$(LIBVEXTA_CONSENSUS) \
|
||||
$(LIBVEXTA_CRYPTO) \
|
||||
$(LIBLEVELDB) \
|
||||
$(LIBLEVELDB_SSE42) \
|
||||
$(LIBMEMENV) \
|
||||
$(LIBSECP256K1)
|
||||
|
||||
vexta_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS)
|
||||
|
||||
vextad_SOURCES = $(vexta_daemon_sources) init/digibyted.cpp
|
||||
vextad_CPPFLAGS = $(vexta_bin_cppflags)
|
||||
vextad_CXXFLAGS = $(vexta_bin_cxxflags)
|
||||
vextad_LDFLAGS = $(vexta_bin_ldflags)
|
||||
vextad_LDADD = $(LIBVEXTA_SERVER) $(vexta_bin_ldadd)
|
||||
|
||||
vexta_node_SOURCES = $(vexta_daemon_sources) init/vexta-node.cpp
|
||||
vexta_node_CPPFLAGS = $(vexta_bin_cppflags)
|
||||
vexta_node_CXXFLAGS = $(vexta_bin_cxxflags)
|
||||
vexta_node_LDFLAGS = $(vexta_bin_ldflags)
|
||||
vexta_node_LDADD = $(LIBVEXTA_SERVER) $(vexta_bin_ldadd) $(LIBVEXTA_IPC) $(LIBMULTIPROCESS_LIBS)
|
||||
|
||||
# vexta-cli binary #
|
||||
vexta_cli_SOURCES = vexta-cli.cpp
|
||||
vexta_cli_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES) $(EVENT_CFLAGS)
|
||||
vexta_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
vexta_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
|
||||
if TARGET_WINDOWS
|
||||
vexta_cli_SOURCES += vexta-cli-res.rc
|
||||
endif
|
||||
|
||||
vexta_cli_LDADD = \
|
||||
$(LIBVEXTA_CLI) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBVEXTA_CONSENSUS) \
|
||||
$(LIBVEXTA_UTIL) \
|
||||
$(LIBVEXTA_CRYPTO)
|
||||
|
||||
vexta_cli_LDADD += $(BOOST_LIBS) $(EVENT_LIBS)
|
||||
#
|
||||
|
||||
# digibyte-tx binary #
|
||||
vexta_tx_SOURCES = vexta-tx.cpp
|
||||
vexta_tx_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
vexta_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
vexta_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
|
||||
if TARGET_WINDOWS
|
||||
vexta_tx_SOURCES += vexta-tx-res.rc
|
||||
endif
|
||||
|
||||
vexta_tx_LDADD = \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBVEXTA_COMMON) \
|
||||
$(LIBVEXTA_UTIL) \
|
||||
$(LIBVEXTA_CONSENSUS) \
|
||||
$(LIBVEXTA_CRYPTO) \
|
||||
$(LIBSECP256K1)
|
||||
|
||||
vexta_tx_LDADD += $(BOOST_LIBS)
|
||||
#
|
||||
|
||||
# digibyte-wallet binary #
|
||||
vexta_wallet_SOURCES = vexta-wallet.cpp
|
||||
vexta_wallet_CPPFLAGS = $(vexta_bin_cppflags)
|
||||
vexta_wallet_CXXFLAGS = $(vexta_bin_cxxflags)
|
||||
vexta_wallet_LDFLAGS = $(vexta_bin_ldflags)
|
||||
vexta_wallet_LDADD = $(LIBVEXTA_WALLET_TOOL) $(vexta_bin_ldadd)
|
||||
|
||||
if TARGET_WINDOWS
|
||||
vexta_wallet_SOURCES += vexta-wallet-res.rc
|
||||
endif
|
||||
#
|
||||
|
||||
# digibyte-util binary #
|
||||
vexta_util_SOURCES = vexta-util.cpp
|
||||
vexta_util_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
vexta_util_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
vexta_util_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
|
||||
if TARGET_WINDOWS
|
||||
vexta_util_SOURCES += vexta-util-res.rc
|
||||
endif
|
||||
|
||||
vexta_util_LDADD = \
|
||||
$(LIBVEXTA_COMMON) \
|
||||
$(LIBVEXTA_UTIL) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBVEXTA_CONSENSUS) \
|
||||
$(LIBVEXTA_CRYPTO) \
|
||||
$(LIBSECP256K1)
|
||||
|
||||
vexta_util_LDADD += $(BOOST_LIBS)
|
||||
#
|
||||
|
||||
# vextaconsensus library #
|
||||
if BUILD_VEXTA_LIBS
|
||||
include_HEADERS = script/vextaconsensus.h
|
||||
libvextaconsensus_la_SOURCES = support/cleanse.cpp $(crypto_libvexta_crypto_base_a_SOURCES) $(libvexta_consensus_a_SOURCES)
|
||||
|
||||
if GLIBC_BACK_COMPAT
|
||||
libvextaconsensus_la_SOURCES += compat/glibc_compat.cpp
|
||||
endif
|
||||
|
||||
libvextaconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
|
||||
libvextaconsensus_la_LIBADD = $(LIBSECP256K1)
|
||||
libvextaconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_VEXTA_INTERNAL
|
||||
libvextaconsensus_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 += crc32c/src/*.gcda crc32c/src/*.gcno
|
||||
CLEANFILES += crypto/*.gcda crypto/*.gcno
|
||||
CLEANFILES += index/*.gcda index/*.gcno
|
||||
CLEANFILES += interfaces/*.gcda interfaces/*.gcno
|
||||
CLEANFILES += node/*.gcda node/*.gcno
|
||||
CLEANFILES += policy/*.gcda policy/*.gcno
|
||||
CLEANFILES += primitives/*.gcda primitives/*.gcno
|
||||
CLEANFILES += rpc/*.gcda rpc/*.gcno
|
||||
CLEANFILES += script/*.gcda script/*.gcno
|
||||
CLEANFILES += support/*.gcda support/*.gcno
|
||||
CLEANFILES += univalue/*.gcda univalue/*.gcno
|
||||
CLEANFILES += util/*.gcda util/*.gcno
|
||||
CLEANFILES += wallet/*.gcda wallet/*.gcno
|
||||
CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno
|
||||
CLEANFILES += zmq/*.gcda zmq/*.gcno
|
||||
CLEANFILES += obj/build.h
|
||||
|
||||
EXTRA_DIST = $(CTAES_DIST)
|
||||
|
||||
|
||||
config/vexta-config.h: config/stamp-h1
|
||||
@$(MAKE) -C $(top_builddir) $(subdir)/$(@)
|
||||
config/stamp-h1: $(top_srcdir)/$(subdir)/config/vexta-config.h.in $(top_builddir)/config.status
|
||||
$(AM_V_at)$(MAKE) -C $(top_builddir) $(subdir)/$(@)
|
||||
$(top_srcdir)/$(subdir)/config/vexta-config.h.in: $(am__configure_deps)
|
||||
$(AM_V_at)$(MAKE) -C $(top_srcdir) $(subdir)/config/vexta-config.h.in
|
||||
|
||||
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 -f config.h
|
||||
-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 $@
|
||||
|
||||
check-symbols: $(bin_PROGRAMS)
|
||||
if TARGET_DARWIN
|
||||
@echo "Checking macOS dynamic libraries..."
|
||||
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
|
||||
endif
|
||||
|
||||
if TARGET_WINDOWS
|
||||
@echo "Checking Windows dynamic libraries..."
|
||||
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
|
||||
endif
|
||||
|
||||
if TARGET_LINUX
|
||||
@echo "Checking glibc back compat..."
|
||||
$(AM_V_at) CPPFILT='$(CPPFILT)' $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
|
||||
endif
|
||||
|
||||
check-security: $(bin_PROGRAMS)
|
||||
if HARDEN
|
||||
@echo "Checking binary security..."
|
||||
$(AM_V_at) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS)
|
||||
endif
|
||||
|
||||
libvexta_ipc_mpgen_input = \
|
||||
ipc/capnp/echo.capnp \
|
||||
ipc/capnp/init.capnp
|
||||
EXTRA_DIST += $(libvexta_ipc_mpgen_input)
|
||||
%.capnp:
|
||||
|
||||
if BUILD_MULTIPROCESS
|
||||
LIBVEXTA_IPC=libvexta_ipc.a
|
||||
libvexta_ipc_a_SOURCES = \
|
||||
ipc/capnp/init-types.h \
|
||||
ipc/capnp/protocol.cpp \
|
||||
ipc/capnp/protocol.h \
|
||||
ipc/exception.h \
|
||||
ipc/interfaces.cpp \
|
||||
ipc/process.cpp \
|
||||
ipc/process.h \
|
||||
ipc/protocol.h
|
||||
libvexta_ipc_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES)
|
||||
libvexta_ipc_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) $(LIBMULTIPROCESS_CFLAGS)
|
||||
|
||||
include $(MPGEN_PREFIX)/include/mpgen.mk
|
||||
libvexta_ipc_mpgen_output = \
|
||||
$(libvexta_ipc_mpgen_input:=.c++) \
|
||||
$(libvexta_ipc_mpgen_input:=.h) \
|
||||
$(libvexta_ipc_mpgen_input:=.proxy-client.c++) \
|
||||
$(libvexta_ipc_mpgen_input:=.proxy-server.c++) \
|
||||
$(libvexta_ipc_mpgen_input:=.proxy-types.c++) \
|
||||
$(libvexta_ipc_mpgen_input:=.proxy-types.h) \
|
||||
$(libvexta_ipc_mpgen_input:=.proxy.h)
|
||||
nodist_libvexta_ipc_a_SOURCES = $(libvexta_ipc_mpgen_output)
|
||||
CLEANFILES += $(libvexta_ipc_mpgen_output)
|
||||
endif
|
||||
|
||||
if EMBEDDED_LEVELDB
|
||||
include Makefile.crc32c.include
|
||||
include Makefile.leveldb.include
|
||||
endif
|
||||
|
||||
include Makefile.test_util.include
|
||||
include Makefile.test_fuzz.include
|
||||
|
||||
if ENABLE_TESTS
|
||||
include Makefile.test.include
|
||||
endif
|
||||
|
||||
if ENABLE_BENCH
|
||||
include Makefile.bench.include
|
||||
endif
|
||||
|
||||
if ENABLE_QT
|
||||
include Makefile.qt.include
|
||||
endif
|
||||
|
||||
if ENABLE_QT_TESTS
|
||||
include Makefile.qttest.include
|
||||
endif
|
||||
103
src/Makefile.bench.include
Normal file
103
src/Makefile.bench.include
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# Copyright (c) 2015-2016 The DigiByte Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
bin_PROGRAMS += bench/bench_digibyte
|
||||
BENCH_SRCDIR = bench
|
||||
BENCH_BINARY = bench/bench_digibyte$(EXEEXT)
|
||||
|
||||
RAW_BENCH_FILES = \
|
||||
bench/data/block413567.raw
|
||||
GENERATED_BENCH_FILES = $(RAW_BENCH_FILES:.raw=.raw.h)
|
||||
|
||||
bench_bench_vexta_SOURCES = \
|
||||
$(RAW_BENCH_FILES) \
|
||||
bench/addrman.cpp \
|
||||
bench/bench_digibyte.cpp \
|
||||
bench/bench.cpp \
|
||||
bench/bench.h \
|
||||
bench/block_assemble.cpp \
|
||||
bench/checkblock.cpp \
|
||||
bench/checkqueue.cpp \
|
||||
bench/data.h \
|
||||
bench/data.cpp \
|
||||
bench/duplicate_inputs.cpp \
|
||||
bench/examples.cpp \
|
||||
bench/rollingbloom.cpp \
|
||||
bench/chacha20.cpp \
|
||||
bench/chacha_poly_aead.cpp \
|
||||
bench/crypto_hash.cpp \
|
||||
bench/ccoins_caching.cpp \
|
||||
bench/gcs_filter.cpp \
|
||||
bench/hashpadding.cpp \
|
||||
bench/merkle_root.cpp \
|
||||
bench/mempool_eviction.cpp \
|
||||
bench/mempool_stress.cpp \
|
||||
bench/nanobench.h \
|
||||
bench/nanobench.cpp \
|
||||
bench/peer_eviction.cpp \
|
||||
bench/rpc_blockchain.cpp \
|
||||
bench/rpc_mempool.cpp \
|
||||
bench/util_time.cpp \
|
||||
bench/verify_script.cpp \
|
||||
bench/base58.cpp \
|
||||
bench/bech32.cpp \
|
||||
bench/lockedpool.cpp \
|
||||
bench/poly1305.cpp \
|
||||
bench/prevector.cpp
|
||||
|
||||
nodist_bench_bench_vexta_SOURCES = $(GENERATED_BENCH_FILES)
|
||||
|
||||
bench_bench_vexta_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
|
||||
bench_bench_vexta_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
bench_bench_vexta_LDADD = \
|
||||
$(LIBVEXTA_SERVER) \
|
||||
$(LIBVEXTA_WALLET) \
|
||||
$(LIBVEXTA_SERVER) \
|
||||
$(LIBVEXTA_COMMON) \
|
||||
$(LIBVEXTA_UTIL) \
|
||||
$(LIBVEXTA_CONSENSUS) \
|
||||
$(LIBVEXTA_CRYPTO) \
|
||||
$(LIBTEST_UTIL) \
|
||||
$(LIBLEVELDB) \
|
||||
$(LIBLEVELDB_SSE42) \
|
||||
$(LIBMEMENV) \
|
||||
$(LIBSECP256K1) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(EVENT_PTHREADS_LIBS) \
|
||||
$(EVENT_LIBS)
|
||||
|
||||
if ENABLE_ZMQ
|
||||
bench_bench_vexta_LDADD += $(LIBVEXTA_ZMQ) $(ZMQ_LIBS)
|
||||
endif
|
||||
|
||||
if ENABLE_WALLET
|
||||
bench_bench_vexta_SOURCES += bench/coin_selection.cpp
|
||||
bench_bench_vexta_SOURCES += bench/wallet_balance.cpp
|
||||
endif
|
||||
|
||||
bench_bench_vexta_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
|
||||
bench_bench_vexta_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
|
||||
CLEAN_VEXTA_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
|
||||
|
||||
CLEANFILES += $(CLEAN_VEXTA_BENCH)
|
||||
|
||||
bench/data.cpp: bench/data/block413567.raw.h
|
||||
|
||||
vexta_bench: $(BENCH_BINARY)
|
||||
|
||||
bench: $(BENCH_BINARY) FORCE
|
||||
$(BENCH_BINARY)
|
||||
|
||||
vexta_bench_clean : FORCE
|
||||
rm -f $(CLEAN_VEXTA_BENCH) $(bench_bench_vexta_OBJECTS) $(BENCH_BINARY)
|
||||
|
||||
%.raw.h: %.raw
|
||||
@$(MKDIR_P) $(@D)
|
||||
@{ \
|
||||
echo "static unsigned const char $(*F)_raw[] = {" && \
|
||||
$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
|
||||
echo "};"; \
|
||||
} > "$@.new" && mv -f "$@.new" "$@"
|
||||
@echo "Generated $@"
|
||||
75
src/Makefile.crc32c.include
Normal file
75
src/Makefile.crc32c.include
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Copyright (c) 2019 The DigiByte Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
LIBCRC32C_INT = crc32c/libcrc32c.a
|
||||
LIBLEVELDB_SSE42_INT = leveldb/libleveldb_sse42.a
|
||||
|
||||
EXTRA_LIBRARIES += $(LIBCRC32C_INT)
|
||||
|
||||
LIBCRC32C = $(LIBCRC32C_INT)
|
||||
|
||||
CRC32C_CPPFLAGS_INT =
|
||||
CRC32C_CPPFLAGS_INT += -I$(srcdir)/crc32c/include
|
||||
CRC32C_CPPFLAGS_INT += -DHAVE_BUILTIN_PREFETCH=@HAVE_BUILTIN_PREFETCH@
|
||||
CRC32C_CPPFLAGS_INT += -DHAVE_MM_PREFETCH=@HAVE_MM_PREFETCH@
|
||||
CRC32C_CPPFLAGS_INT += -DHAVE_STRONG_GETAUXVAL=@HAVE_STRONG_GETAUXVAL@
|
||||
CRC32C_CPPFLAGS_INT += -DHAVE_WEAK_GETAUXVAL=@HAVE_WEAK_GETAUXVAL@
|
||||
CRC32C_CPPFLAGS_INT += -DCRC32C_TESTS_BUILT_WITH_GLOG=0
|
||||
|
||||
if ENABLE_SSE42
|
||||
CRC32C_CPPFLAGS_INT += -DHAVE_SSE42=1
|
||||
else
|
||||
CRC32C_CPPFLAGS_INT += -DHAVE_SSE42=0
|
||||
endif
|
||||
|
||||
if ENABLE_ARM_CRC
|
||||
CRC32C_CPPFLAGS_INT += -DHAVE_ARM64_CRC32C=1
|
||||
else
|
||||
CRC32C_CPPFLAGS_INT += -DHAVE_ARM64_CRC32C=0
|
||||
endif
|
||||
|
||||
if WORDS_BIGENDIAN
|
||||
CRC32C_CPPFLAGS_INT += -DBYTE_ORDER_BIG_ENDIAN=1
|
||||
else
|
||||
CRC32C_CPPFLAGS_INT += -DBYTE_ORDER_BIG_ENDIAN=0
|
||||
endif
|
||||
|
||||
crc32c_libcrc32c_a_CPPFLAGS = $(AM_CPPFLAGS) $(CRC32C_CPPFLAGS_INT) $(CRC32C_CPPFLAGS)
|
||||
crc32c_libcrc32c_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
|
||||
crc32c_libcrc32c_a_SOURCES =
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/include/crc32c/crc32c.h
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_arm64.h
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_arm64_check.h
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_internal.h
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_prefetch.h
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_read_le.h
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_round_up.h
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_sse42_check.h
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_sse42.h
|
||||
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c.cc
|
||||
crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_portable.cc
|
||||
|
||||
if ENABLE_SSE42
|
||||
LIBCRC32C_SSE42_INT = crc32c/libcrc32c_sse42.a
|
||||
EXTRA_LIBRARIES += $(LIBCRC32C_SSE42_INT)
|
||||
LIBCRC32C += $(LIBCRC32C_SSE42_INT)
|
||||
|
||||
crc32c_libcrc32c_sse42_a_CPPFLAGS = $(crc32c_libcrc32c_a_CPPFLAGS)
|
||||
crc32c_libcrc32c_sse42_a_CXXFLAGS = $(crc32c_libcrc32c_a_CXXFLAGS) $(SSE42_CXXFLAGS)
|
||||
|
||||
crc32c_libcrc32c_sse42_a_SOURCES = crc32c/src/crc32c_sse42.cc
|
||||
endif
|
||||
|
||||
if ENABLE_ARM_CRC
|
||||
LIBCRC32C_ARM_CRC_INT = crc32c/libcrc32c_arm_crc.a
|
||||
EXTRA_LIBRARIES += $(LIBCRC32C_ARM_CRC_INT)
|
||||
LIBCRC32C += $(LIBCRC32C_ARM_CRC_INT)
|
||||
|
||||
crc32c_libcrc32c_arm_crc_a_CPPFLAGS = $(crc32c_libcrc32c_a_CPPFLAGS)
|
||||
crc32c_libcrc32c_arm_crc_a_CXXFLAGS = $(crc32c_libcrc32c_a_CXXFLAGS) $(ARM_CRC_CXXFLAGS)
|
||||
|
||||
crc32c_libcrc32c_arm_crc_a_SOURCES = crc32c/src/crc32c_arm64.cc
|
||||
endif
|
||||
146
src/Makefile.leveldb.include
Normal file
146
src/Makefile.leveldb.include
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
# Copyright (c) 2016 The DigiByte Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
LIBLEVELDB_INT = leveldb/libleveldb.a
|
||||
LIBMEMENV_INT = leveldb/libmemenv.a
|
||||
|
||||
EXTRA_LIBRARIES += $(LIBLEVELDB_INT)
|
||||
EXTRA_LIBRARIES += $(LIBMEMENV_INT)
|
||||
|
||||
LIBLEVELDB += $(LIBLEVELDB_INT) $(LIBCRC32C)
|
||||
LIBMEMENV += $(LIBMEMENV_INT)
|
||||
|
||||
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
|
||||
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv
|
||||
|
||||
LEVELDB_CPPFLAGS_INT =
|
||||
LEVELDB_CPPFLAGS_INT += -I$(srcdir)/leveldb
|
||||
LEVELDB_CPPFLAGS_INT += -I$(srcdir)/crc32c/include
|
||||
LEVELDB_CPPFLAGS_INT += -D__STDC_LIMIT_MACROS
|
||||
LEVELDB_CPPFLAGS_INT += -DHAVE_SNAPPY=0 -DHAVE_CRC32C=1
|
||||
LEVELDB_CPPFLAGS_INT += -DHAVE_FDATASYNC=@HAVE_FDATASYNC@
|
||||
LEVELDB_CPPFLAGS_INT += -DHAVE_FULLFSYNC=@HAVE_FULLFSYNC@
|
||||
LEVELDB_CPPFLAGS_INT += -DHAVE_O_CLOEXEC=@HAVE_O_CLOEXEC@
|
||||
LEVELDB_CPPFLAGS_INT += -DFALLTHROUGH_INTENDED=[[fallthrough]]
|
||||
|
||||
if WORDS_BIGENDIAN
|
||||
LEVELDB_CPPFLAGS_INT += -DLEVELDB_IS_BIG_ENDIAN=1
|
||||
else
|
||||
LEVELDB_CPPFLAGS_INT += -DLEVELDB_IS_BIG_ENDIAN=0
|
||||
endif
|
||||
|
||||
if TARGET_WINDOWS
|
||||
LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_WINDOWS -D_UNICODE -DUNICODE -D__USE_MINGW_ANSI_STDIO=1
|
||||
else
|
||||
LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_POSIX
|
||||
endif
|
||||
|
||||
leveldb_libleveldb_a_CPPFLAGS = $(AM_CPPFLAGS) $(LEVELDB_CPPFLAGS_INT) $(LEVELDB_CPPFLAGS)
|
||||
leveldb_libleveldb_a_CXXFLAGS = $(filter-out -Wconditional-uninitialized -Werror=conditional-uninitialized -Wsuggest-override -Werror=suggest-override, $(AM_CXXFLAGS)) $(PIE_FLAGS)
|
||||
|
||||
leveldb_libleveldb_a_SOURCES=
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/port/port_stdcxx.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/port/port.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/port/thread_annotations.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/db.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/options.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/comparator.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/filter_policy.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/slice.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/table_builder.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/env.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/export.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/c.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/iterator.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/cache.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/dumpfile.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/table.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/write_batch.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/include/leveldb/status.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/log_format.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/memtable.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/version_set.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/write_batch_internal.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/filename.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/version_edit.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/dbformat.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/builder.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/log_writer.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/db_iter.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/skiplist.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/db_impl.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/table_cache.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/snapshot.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/log_reader.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/filter_block.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/block_builder.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/block.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/two_level_iterator.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/merger.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/format.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/iterator_wrapper.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/crc32c.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/env_posix_test_helper.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/env_windows_test_helper.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/arena.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/random.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/posix_logger.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/hash.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/histogram.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/coding.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/testutil.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/mutexlock.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/logging.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/no_destructor.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/testharness.h
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/windows_logger.h
|
||||
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/builder.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/c.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/dbformat.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/db_impl.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/db_iter.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/dumpfile.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/filename.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/log_reader.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/log_writer.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/memtable.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/repair.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/table_cache.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/version_edit.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/version_set.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/db/write_batch.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/block_builder.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/block.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/filter_block.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/format.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/iterator.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/merger.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/table_builder.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/table.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/table/two_level_iterator.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/arena.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/bloom.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/cache.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/coding.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/comparator.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/crc32c.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/env.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/filter_policy.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/hash.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/histogram.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/logging.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/options.cc
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/status.cc
|
||||
|
||||
if TARGET_WINDOWS
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/env_windows.cc
|
||||
else
|
||||
leveldb_libleveldb_a_SOURCES += leveldb/util/env_posix.cc
|
||||
endif
|
||||
|
||||
leveldb_libmemenv_a_CPPFLAGS = $(leveldb_libleveldb_a_CPPFLAGS)
|
||||
leveldb_libmemenv_a_CXXFLAGS = $(leveldb_libleveldb_a_CXXFLAGS)
|
||||
leveldb_libmemenv_a_SOURCES = leveldb/helpers/memenv/memenv.cc
|
||||
leveldb_libmemenv_a_SOURCES += leveldb/helpers/memenv/memenv.h
|
||||
417
src/Makefile.qt.include
Normal file
417
src/Makefile.qt.include
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
# Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
# Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
bin_PROGRAMS += qt/vexta-qt
|
||||
|
||||
if BUILD_VEXTA_GUI
|
||||
bin_PROGRAMS += vexta-gui
|
||||
endif
|
||||
|
||||
EXTRA_LIBRARIES += qt/libvextaqt.a
|
||||
|
||||
# digibyte qt core #
|
||||
include Makefile.qt_locale.include
|
||||
|
||||
QT_FORMS_UI = \
|
||||
qt/forms/addressbookpage.ui \
|
||||
qt/forms/askpassphrasedialog.ui \
|
||||
qt/forms/coincontroldialog.ui \
|
||||
qt/forms/createwalletdialog.ui \
|
||||
qt/forms/editaddressdialog.ui \
|
||||
qt/forms/helpmessagedialog.ui \
|
||||
qt/forms/intro.ui \
|
||||
qt/forms/modaloverlay.ui \
|
||||
qt/forms/openuridialog.ui \
|
||||
qt/forms/optionsdialog.ui \
|
||||
qt/forms/overviewpage.ui \
|
||||
qt/forms/psbtoperationsdialog.ui \
|
||||
qt/forms/receivecoinsdialog.ui \
|
||||
qt/forms/receiverequestdialog.ui \
|
||||
qt/forms/debugwindow.ui \
|
||||
qt/forms/sendcoinsdialog.ui \
|
||||
qt/forms/sendcoinsentry.ui \
|
||||
qt/forms/signverifymessagedialog.ui \
|
||||
qt/forms/transactiondescdialog.ui
|
||||
|
||||
QT_MOC_CPP = \
|
||||
qt/moc_addressbookpage.cpp \
|
||||
qt/moc_addresstablemodel.cpp \
|
||||
qt/moc_askpassphrasedialog.cpp \
|
||||
qt/moc_createwalletdialog.cpp \
|
||||
qt/moc_bantablemodel.cpp \
|
||||
qt/moc_digibyteaddressvalidator.cpp \
|
||||
qt/moc_digibyteamountfield.cpp \
|
||||
qt/moc_digibyte.cpp \
|
||||
qt/moc_digibytegui.cpp \
|
||||
qt/moc_digibyteunits.cpp \
|
||||
qt/moc_clientmodel.cpp \
|
||||
qt/moc_coincontroldialog.cpp \
|
||||
qt/moc_coincontroltreewidget.cpp \
|
||||
qt/moc_csvmodelwriter.cpp \
|
||||
qt/moc_editaddressdialog.cpp \
|
||||
qt/moc_guiutil.cpp \
|
||||
qt/moc_initexecutor.cpp \
|
||||
qt/moc_intro.cpp \
|
||||
qt/moc_macdockiconhandler.cpp \
|
||||
qt/moc_macnotificationhandler.cpp \
|
||||
qt/moc_modaloverlay.cpp \
|
||||
qt/moc_notificator.cpp \
|
||||
qt/moc_openuridialog.cpp \
|
||||
qt/moc_optionsdialog.cpp \
|
||||
qt/moc_optionsmodel.cpp \
|
||||
qt/moc_overviewpage.cpp \
|
||||
qt/moc_peertablemodel.cpp \
|
||||
qt/moc_peertablesortproxy.cpp \
|
||||
qt/moc_paymentserver.cpp \
|
||||
qt/moc_psbtoperationsdialog.cpp \
|
||||
qt/moc_qrimagewidget.cpp \
|
||||
qt/moc_qvalidatedlineedit.cpp \
|
||||
qt/moc_qvaluecombobox.cpp \
|
||||
qt/moc_receivecoinsdialog.cpp \
|
||||
qt/moc_receiverequestdialog.cpp \
|
||||
qt/moc_recentrequeststablemodel.cpp \
|
||||
qt/moc_rpcconsole.cpp \
|
||||
qt/moc_sendcoinsdialog.cpp \
|
||||
qt/moc_sendcoinsentry.cpp \
|
||||
qt/moc_signverifymessagedialog.cpp \
|
||||
qt/moc_splashscreen.cpp \
|
||||
qt/moc_trafficgraphwidget.cpp \
|
||||
qt/moc_transactiondesc.cpp \
|
||||
qt/moc_transactiondescdialog.cpp \
|
||||
qt/moc_transactionfilterproxy.cpp \
|
||||
qt/moc_transactionoverviewwidget.cpp \
|
||||
qt/moc_transactiontablemodel.cpp \
|
||||
qt/moc_transactionview.cpp \
|
||||
qt/moc_utilitydialog.cpp \
|
||||
qt/moc_walletcontroller.cpp \
|
||||
qt/moc_walletframe.cpp \
|
||||
qt/moc_walletmodel.cpp \
|
||||
qt/moc_walletview.cpp
|
||||
|
||||
VEXTA_MM = \
|
||||
qt/macdockiconhandler.mm \
|
||||
qt/macnotificationhandler.mm \
|
||||
qt/macos_appnap.mm
|
||||
|
||||
QT_MOC = \
|
||||
qt/digibyteamountfield.moc \
|
||||
qt/intro.moc \
|
||||
qt/overviewpage.moc \
|
||||
qt/rpcconsole.moc
|
||||
|
||||
QT_QRC_CPP = qt/qrc_vexta.cpp
|
||||
QT_QRC = qt/vexta.qrc
|
||||
QT_QRC_LOCALE_CPP = qt/qrc_vexta_locale.cpp
|
||||
QT_QRC_LOCALE = qt/vexta_locale.qrc
|
||||
|
||||
VEXTA_QT_H = \
|
||||
qt/addressbookpage.h \
|
||||
qt/addresstablemodel.h \
|
||||
qt/askpassphrasedialog.h \
|
||||
qt/bantablemodel.h \
|
||||
qt/digibyteaddressvalidator.h \
|
||||
qt/digibyteamountfield.h \
|
||||
qt/digibyte.h \
|
||||
qt/digibytegui.h \
|
||||
qt/digibyteunits.h \
|
||||
qt/clientmodel.h \
|
||||
qt/coincontroldialog.h \
|
||||
qt/coincontroltreewidget.h \
|
||||
qt/createwalletdialog.h \
|
||||
qt/csvmodelwriter.h \
|
||||
qt/editaddressdialog.h \
|
||||
qt/guiconstants.h \
|
||||
qt/guiutil.h \
|
||||
qt/initexecutor.h \
|
||||
qt/intro.h \
|
||||
qt/macdockiconhandler.h \
|
||||
qt/macnotificationhandler.h \
|
||||
qt/macos_appnap.h \
|
||||
qt/modaloverlay.h \
|
||||
qt/networkstyle.h \
|
||||
qt/notificator.h \
|
||||
qt/openuridialog.h \
|
||||
qt/optionsdialog.h \
|
||||
qt/optionsmodel.h \
|
||||
qt/overviewpage.h \
|
||||
qt/paymentserver.h \
|
||||
qt/peertablemodel.h \
|
||||
qt/peertablesortproxy.h \
|
||||
qt/platformstyle.h \
|
||||
qt/psbtoperationsdialog.h \
|
||||
qt/qrimagewidget.h \
|
||||
qt/qvalidatedlineedit.h \
|
||||
qt/qvaluecombobox.h \
|
||||
qt/receivecoinsdialog.h \
|
||||
qt/receiverequestdialog.h \
|
||||
qt/recentrequeststablemodel.h \
|
||||
qt/rpcconsole.h \
|
||||
qt/sendcoinsdialog.h \
|
||||
qt/sendcoinsentry.h \
|
||||
qt/sendcoinsrecipient.h \
|
||||
qt/signverifymessagedialog.h \
|
||||
qt/splashscreen.h \
|
||||
qt/trafficgraphwidget.h \
|
||||
qt/transactiondesc.h \
|
||||
qt/transactiondescdialog.h \
|
||||
qt/transactionfilterproxy.h \
|
||||
qt/transactionoverviewwidget.h \
|
||||
qt/transactionrecord.h \
|
||||
qt/transactiontablemodel.h \
|
||||
qt/transactionview.h \
|
||||
qt/utilitydialog.h \
|
||||
qt/walletcontroller.h \
|
||||
qt/walletframe.h \
|
||||
qt/walletmodel.h \
|
||||
qt/walletmodeltransaction.h \
|
||||
qt/walletview.h \
|
||||
qt/winshutdownmonitor.h
|
||||
|
||||
RES_FONTS = \
|
||||
qt/res/fonts/RobotoMono-Bold.ttf
|
||||
|
||||
RES_ICONS = \
|
||||
qt/res/icons/add.png \
|
||||
qt/res/icons/address-book.png \
|
||||
qt/res/icons/vexta.ico \
|
||||
qt/res/icons/vexta_testnet.ico \
|
||||
qt/res/icons/vexta.png \
|
||||
qt/res/icons/chevron.png \
|
||||
qt/res/icons/clock1.png \
|
||||
qt/res/icons/clock2.png \
|
||||
qt/res/icons/clock3.png \
|
||||
qt/res/icons/clock4.png \
|
||||
qt/res/icons/clock5.png \
|
||||
qt/res/icons/connect0.png \
|
||||
qt/res/icons/connect1.png \
|
||||
qt/res/icons/connect2.png \
|
||||
qt/res/icons/connect3.png \
|
||||
qt/res/icons/connect4.png \
|
||||
qt/res/icons/edit.png \
|
||||
qt/res/icons/editcopy.png \
|
||||
qt/res/icons/editpaste.png \
|
||||
qt/res/icons/export.png \
|
||||
qt/res/icons/eye.png \
|
||||
qt/res/icons/eye_minus.png \
|
||||
qt/res/icons/eye_plus.png \
|
||||
qt/res/icons/fontbigger.png \
|
||||
qt/res/icons/fontsmaller.png \
|
||||
qt/res/icons/hd_disabled.png \
|
||||
qt/res/icons/hd_enabled.png \
|
||||
qt/res/icons/history.png \
|
||||
qt/res/icons/lock_closed.png \
|
||||
qt/res/icons/lock_open.png \
|
||||
qt/res/icons/network_disabled.png \
|
||||
qt/res/icons/overview.png \
|
||||
qt/res/icons/proxy.png \
|
||||
qt/res/icons/receive.png \
|
||||
qt/res/icons/remove.png \
|
||||
qt/res/icons/send.png \
|
||||
qt/res/icons/synced.png \
|
||||
qt/res/icons/transaction0.png \
|
||||
qt/res/icons/transaction2.png \
|
||||
qt/res/icons/transaction_abandoned.png \
|
||||
qt/res/icons/transaction_conflicted.png \
|
||||
qt/res/icons/tx_inout.png \
|
||||
qt/res/icons/tx_input.png \
|
||||
qt/res/icons/tx_output.png \
|
||||
qt/res/icons/tx_mined.png \
|
||||
qt/res/icons/warning.png
|
||||
|
||||
VEXTA_QT_BASE_CPP = \
|
||||
qt/bantablemodel.cpp \
|
||||
qt/digibyte.cpp \
|
||||
qt/digibyteaddressvalidator.cpp \
|
||||
qt/digibyteamountfield.cpp \
|
||||
qt/digibytegui.cpp \
|
||||
qt/digibyteunits.cpp \
|
||||
qt/clientmodel.cpp \
|
||||
qt/csvmodelwriter.cpp \
|
||||
qt/guiutil.cpp \
|
||||
qt/initexecutor.cpp \
|
||||
qt/intro.cpp \
|
||||
qt/modaloverlay.cpp \
|
||||
qt/networkstyle.cpp \
|
||||
qt/notificator.cpp \
|
||||
qt/optionsdialog.cpp \
|
||||
qt/optionsmodel.cpp \
|
||||
qt/peertablemodel.cpp \
|
||||
qt/peertablesortproxy.cpp \
|
||||
qt/platformstyle.cpp \
|
||||
qt/qvalidatedlineedit.cpp \
|
||||
qt/qvaluecombobox.cpp \
|
||||
qt/rpcconsole.cpp \
|
||||
qt/splashscreen.cpp \
|
||||
qt/trafficgraphwidget.cpp \
|
||||
qt/utilitydialog.cpp
|
||||
|
||||
VEXTA_QT_WINDOWS_CPP = qt/winshutdownmonitor.cpp
|
||||
|
||||
VEXTA_QT_WALLET_CPP = \
|
||||
qt/addressbookpage.cpp \
|
||||
qt/addresstablemodel.cpp \
|
||||
qt/askpassphrasedialog.cpp \
|
||||
qt/coincontroldialog.cpp \
|
||||
qt/coincontroltreewidget.cpp \
|
||||
qt/createwalletdialog.cpp \
|
||||
qt/editaddressdialog.cpp \
|
||||
qt/openuridialog.cpp \
|
||||
qt/overviewpage.cpp \
|
||||
qt/paymentserver.cpp \
|
||||
qt/psbtoperationsdialog.cpp \
|
||||
qt/qrimagewidget.cpp \
|
||||
qt/receivecoinsdialog.cpp \
|
||||
qt/receiverequestdialog.cpp \
|
||||
qt/recentrequeststablemodel.cpp \
|
||||
qt/sendcoinsdialog.cpp \
|
||||
qt/sendcoinsentry.cpp \
|
||||
qt/signverifymessagedialog.cpp \
|
||||
qt/transactiondesc.cpp \
|
||||
qt/transactiondescdialog.cpp \
|
||||
qt/transactionfilterproxy.cpp \
|
||||
qt/transactionrecord.cpp \
|
||||
qt/transactiontablemodel.cpp \
|
||||
qt/transactionview.cpp \
|
||||
qt/walletcontroller.cpp \
|
||||
qt/walletframe.cpp \
|
||||
qt/walletmodel.cpp \
|
||||
qt/walletmodeltransaction.cpp \
|
||||
qt/walletview.cpp
|
||||
|
||||
VEXTA_QT_CPP = $(VEXTA_QT_BASE_CPP)
|
||||
if TARGET_WINDOWS
|
||||
VEXTA_QT_CPP += $(VEXTA_QT_WINDOWS_CPP)
|
||||
endif
|
||||
if ENABLE_WALLET
|
||||
VEXTA_QT_CPP += $(VEXTA_QT_WALLET_CPP)
|
||||
endif # ENABLE_WALLET
|
||||
|
||||
RES_ANIMATION = $(wildcard $(srcdir)/qt/res/animation/spinner-*.png)
|
||||
|
||||
VEXTA_RC = qt/res/vexta-qt-res.rc
|
||||
|
||||
VEXTA_QT_INCLUDES = -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER
|
||||
|
||||
qt_libvextaqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(VEXTA_INCLUDES) $(VEXTA_QT_INCLUDES) \
|
||||
$(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS)
|
||||
qt_libvextaqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
|
||||
qt_libvextaqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
|
||||
|
||||
qt_libvextaqt_a_SOURCES = $(VEXTA_QT_CPP) $(VEXTA_QT_H) $(QT_FORMS_UI) \
|
||||
$(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(RES_FONTS) $(RES_ICONS) $(RES_ANIMATION)
|
||||
if TARGET_DARWIN
|
||||
qt_libvextaqt_a_SOURCES += $(VEXTA_MM)
|
||||
endif
|
||||
|
||||
nodist_qt_libvextaqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP)
|
||||
|
||||
# forms/foo.h -> forms/ui_foo.h
|
||||
QT_FORMS_H=$(join $(dir $(QT_FORMS_UI)),$(addprefix ui_, $(notdir $(QT_FORMS_UI:.ui=.h))))
|
||||
|
||||
# Most files will depend on the forms and moc files as includes. Generate them
|
||||
# before anything else.
|
||||
$(QT_MOC): $(QT_FORMS_H)
|
||||
$(qt_libvextaqt_a_OBJECTS) $(qt_vexta_qt_OBJECTS) $(vexta_gui_OBJECTS) : | $(QT_MOC)
|
||||
|
||||
# vexta-qt and vexta-gui binaries #
|
||||
vexta_qt_cppflags = $(AM_CPPFLAGS) $(VEXTA_INCLUDES) $(VEXTA_QT_INCLUDES) \
|
||||
$(QT_INCLUDES) $(QR_CFLAGS)
|
||||
vexta_qt_cxxflags = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
|
||||
|
||||
vexta_qt_sources = qt/main.cpp
|
||||
if TARGET_WINDOWS
|
||||
vexta_qt_sources += $(VEXTA_RC)
|
||||
endif
|
||||
vexta_qt_ldadd = qt/libvextaqt.a $(LIBVEXTA_SERVER)
|
||||
if ENABLE_WALLET
|
||||
vexta_qt_ldadd += $(LIBVEXTA_UTIL) $(LIBVEXTA_WALLET)
|
||||
endif
|
||||
if ENABLE_ZMQ
|
||||
vexta_qt_ldadd += $(LIBVEXTA_ZMQ) $(ZMQ_LIBS)
|
||||
endif
|
||||
vexta_qt_ldadd += $(LIBVEXTA_CLI) $(LIBVEXTA_COMMON) $(LIBVEXTA_UTIL) $(LIBVEXTA_CONSENSUS) $(LIBVEXTA_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
|
||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS)
|
||||
vexta_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
vexta_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX
|
||||
|
||||
qt_vexta_qt_CPPFLAGS = $(vexta_qt_cppflags)
|
||||
qt_vexta_qt_CXXFLAGS = $(vexta_qt_cxxflags)
|
||||
qt_vexta_qt_SOURCES = $(vexta_qt_sources)
|
||||
qt_vexta_qt_LDADD = $(vexta_qt_ldadd)
|
||||
qt_vexta_qt_LDFLAGS = $(vexta_qt_ldflags)
|
||||
qt_vexta_qt_LIBTOOLFLAGS = $(vexta_qt_libtoolflags)
|
||||
|
||||
vexta_gui_CPPFLAGS = $(vexta_qt_cppflags)
|
||||
vexta_gui_CXXFLAGS = $(vexta_qt_cxxflags)
|
||||
vexta_gui_SOURCES = $(vexta_qt_sources)
|
||||
vexta_gui_LDADD = $(vexta_qt_ldadd)
|
||||
vexta_gui_LDFLAGS = $(vexta_qt_ldflags)
|
||||
vexta_gui_LIBTOOLFLAGS = $(vexta_qt_libtoolflags)
|
||||
|
||||
#locale/foo.ts -> locale/foo.qm
|
||||
QT_QM=$(QT_TS:.ts=.qm)
|
||||
|
||||
SECONDARY: $(QT_QM)
|
||||
|
||||
$(srcdir)/qt/digibytestrings.cpp: FORCE
|
||||
@test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
|
||||
$(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" $(PYTHON) ../share/qt/extract_strings_qt.py $(libvexta_server_a_SOURCES) $(libvexta_wallet_a_SOURCES) $(libvexta_common_a_SOURCES) $(libvexta_zmq_a_SOURCES) $(libvexta_consensus_a_SOURCES) $(libvexta_util_a_SOURCES)
|
||||
|
||||
translate: $(srcdir)/qt/digibytestrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(VEXTA_QT_BASE_CPP) qt/digibyte.cpp $(VEXTA_QT_WINDOWS_CPP) $(VEXTA_QT_WALLET_CPP) $(VEXTA_QT_H) $(VEXTA_MM)
|
||||
@test -n $(LUPDATE) || echo "lupdate is required for updating translations"
|
||||
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) -no-obsolete -I $(srcdir) -locations relative $^ -ts $(srcdir)/qt/locale/vexta_en.ts
|
||||
@test -n $(LCONVERT) || echo "lconvert is required for updating translations"
|
||||
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LCONVERT) -o $(srcdir)/qt/locale/vexta_en.xlf -i $(srcdir)/qt/locale/vexta_en.ts
|
||||
|
||||
$(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM)
|
||||
@test -f $(RCC)
|
||||
@cp -f $< $(@D)/temp_$(<F)
|
||||
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name vexta_locale --format-version 1 $(@D)/temp_$(<F) > $@
|
||||
@rm $(@D)/temp_$(<F)
|
||||
|
||||
$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(RES_FONTS) $(RES_ICONS) $(RES_ANIMATION)
|
||||
@test -f $(RCC)
|
||||
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name digibyte --format-version 1 $< > $@
|
||||
|
||||
CLEAN_QT = $(nodist_qt_libvextaqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno qt/temp_vexta_locale.qrc
|
||||
|
||||
CLEANFILES += $(CLEAN_QT)
|
||||
|
||||
vexta_qt_clean: FORCE
|
||||
rm -f $(CLEAN_QT) $(qt_libvextaqt_a_OBJECTS) $(qt_vexta_qt_OBJECTS) qt/vexta-qt$(EXEEXT) $(LIBVEXTAQT)
|
||||
|
||||
vexta_qt : qt/vexta-qt$(EXEEXT)
|
||||
|
||||
APK_LIB_DIR = qt/android/libs/$(ANDROID_ARCH)
|
||||
QT_BASE_VERSION = $(lastword $(shell $(MOC) --version))
|
||||
QT_BASE_PATH = $(shell find ../depends/sources/ -maxdepth 1 -type f -regex ".*qtbase.*$(QT_BASE_VERSION)\.tar.xz")
|
||||
QT_BASE_TLD = $(shell tar tf $(QT_BASE_PATH) --exclude='*/*')
|
||||
|
||||
vexta_qt_apk: FORCE
|
||||
mkdir -p $(APK_LIB_DIR)
|
||||
cp $(dir $(CC))../sysroot/usr/lib/$(host_alias)/libc++_shared.so $(APK_LIB_DIR)
|
||||
tar xf $(QT_BASE_PATH) -C qt/android/src/ $(QT_BASE_TLD)src/android/jar/src --strip-components=5
|
||||
tar xf $(QT_BASE_PATH) -C qt/android/src/ $(QT_BASE_TLD)src/android/java/src --strip-components=5
|
||||
tar xf $(QT_BASE_PATH) -C qt/android/res/ $(QT_BASE_TLD)src/android/java/res --strip-components=5
|
||||
cp qt/vexta-qt $(APK_LIB_DIR)/libvexta-qt.so
|
||||
cd qt/android && gradle wrapper --gradle-version=6.6.1
|
||||
cd qt/android && ./gradlew build
|
||||
|
||||
ui_%.h: %.ui
|
||||
@test -f $(UIC)
|
||||
@$(MKDIR_P) $(@D)
|
||||
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(UIC) -o $@ $< || (echo "Error creating $@"; false)
|
||||
|
||||
%.moc: %.cpp
|
||||
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES_UNSUPPRESSED) $(MOC_DEFS) $< > $@
|
||||
|
||||
moc_%.cpp: %.h
|
||||
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES_UNSUPPRESSED) $(MOC_DEFS) $< > $@
|
||||
|
||||
%.qm: %.ts
|
||||
@test -f $(LRELEASE)
|
||||
@$(MKDIR_P) $(@D)
|
||||
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LRELEASE) -silent $< -qm $@
|
||||
87
src/Makefile.qt_locale.include
Normal file
87
src/Makefile.qt_locale.include
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
QT_TS = \
|
||||
qt/locale/digibyte_af.ts \
|
||||
qt/locale/digibyte_am.ts \
|
||||
qt/locale/digibyte_ar.ts \
|
||||
qt/locale/digibyte_be.ts \
|
||||
qt/locale/digibyte_bg.ts \
|
||||
qt/locale/digibyte_bn.ts \
|
||||
qt/locale/digibyte_bs.ts \
|
||||
qt/locale/digibyte_ca.ts \
|
||||
qt/locale/digibyte_cs.ts \
|
||||
qt/locale/digibyte_cy.ts \
|
||||
qt/locale/digibyte_da.ts \
|
||||
qt/locale/digibyte_de.ts \
|
||||
qt/locale/digibyte_el.ts \
|
||||
qt/locale/digibyte_en.ts \
|
||||
qt/locale/digibyte_en_GB.ts \
|
||||
qt/locale/digibyte_eo.ts \
|
||||
qt/locale/digibyte_es.ts \
|
||||
qt/locale/digibyte_es_CL.ts \
|
||||
qt/locale/digibyte_es_CO.ts \
|
||||
qt/locale/digibyte_es_DO.ts \
|
||||
qt/locale/digibyte_es_MX.ts \
|
||||
qt/locale/digibyte_es_VE.ts \
|
||||
qt/locale/digibyte_et.ts \
|
||||
qt/locale/digibyte_eu.ts \
|
||||
qt/locale/digibyte_fa.ts \
|
||||
qt/locale/digibyte_fi.ts \
|
||||
qt/locale/digibyte_fil.ts \
|
||||
qt/locale/digibyte_fr.ts \
|
||||
qt/locale/digibyte_gl_ES.ts \
|
||||
qt/locale/digibyte_he.ts \
|
||||
qt/locale/digibyte_hi.ts \
|
||||
qt/locale/digibyte_hr.ts \
|
||||
qt/locale/digibyte_hu.ts \
|
||||
qt/locale/digibyte_id.ts \
|
||||
qt/locale/digibyte_is.ts \
|
||||
qt/locale/digibyte_it.ts \
|
||||
qt/locale/digibyte_ja.ts \
|
||||
qt/locale/digibyte_ka.ts \
|
||||
qt/locale/digibyte_kk.ts \
|
||||
qt/locale/digibyte_km.ts \
|
||||
qt/locale/digibyte_ko.ts \
|
||||
qt/locale/digibyte_ku_IQ.ts \
|
||||
qt/locale/digibyte_ky.ts \
|
||||
qt/locale/digibyte_la.ts \
|
||||
qt/locale/digibyte_lt.ts \
|
||||
qt/locale/digibyte_lv.ts \
|
||||
qt/locale/digibyte_mk.ts \
|
||||
qt/locale/digibyte_ml.ts \
|
||||
qt/locale/digibyte_mn.ts \
|
||||
qt/locale/digibyte_mr_IN.ts \
|
||||
qt/locale/digibyte_ms.ts \
|
||||
qt/locale/digibyte_my.ts \
|
||||
qt/locale/digibyte_nb.ts \
|
||||
qt/locale/digibyte_ne.ts \
|
||||
qt/locale/digibyte_nl.ts \
|
||||
qt/locale/digibyte_pam.ts \
|
||||
qt/locale/digibyte_pl.ts \
|
||||
qt/locale/digibyte_pt.ts \
|
||||
qt/locale/digibyte_pt_BR.ts \
|
||||
qt/locale/digibyte_ro.ts \
|
||||
qt/locale/digibyte_ru.ts \
|
||||
qt/locale/digibyte_si.ts \
|
||||
qt/locale/digibyte_sk.ts \
|
||||
qt/locale/digibyte_sl.ts \
|
||||
qt/locale/digibyte_sn.ts \
|
||||
qt/locale/digibyte_sq.ts \
|
||||
qt/locale/digibyte_sr.ts \
|
||||
qt/locale/digibyte_sr@latin.ts \
|
||||
qt/locale/digibyte_sv.ts \
|
||||
qt/locale/digibyte_szl.ts \
|
||||
qt/locale/digibyte_ta.ts \
|
||||
qt/locale/digibyte_te.ts \
|
||||
qt/locale/digibyte_th.ts \
|
||||
qt/locale/digibyte_tr.ts \
|
||||
qt/locale/digibyte_uk.ts \
|
||||
qt/locale/digibyte_ur.ts \
|
||||
qt/locale/digibyte_uz@Cyrl.ts \
|
||||
qt/locale/digibyte_uz@Latn.ts \
|
||||
qt/locale/digibyte_vi.ts \
|
||||
qt/locale/digibyte_yo.ts \
|
||||
qt/locale/digibyte_zh-Hans.ts \
|
||||
qt/locale/digibyte_zh.ts \
|
||||
qt/locale/digibyte_zh_CN.ts \
|
||||
qt/locale/digibyte_zh_HK.ts \
|
||||
qt/locale/digibyte_zh_TW.ts \
|
||||
qt/locale/digibyte_zu.ts
|
||||
70
src/Makefile.qttest.include
Normal file
70
src/Makefile.qttest.include
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Copyright (c) 2013-2016 The DigiByte Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
bin_PROGRAMS += qt/test/test_vexta-qt
|
||||
TESTS += qt/test/test_vexta-qt
|
||||
|
||||
TEST_QT_MOC_CPP = \
|
||||
qt/test/moc_apptests.cpp \
|
||||
qt/test/moc_rpcnestedtests.cpp \
|
||||
qt/test/moc_uritests.cpp
|
||||
|
||||
if ENABLE_WALLET
|
||||
TEST_QT_MOC_CPP += \
|
||||
qt/test/moc_addressbooktests.cpp \
|
||||
qt/test/moc_wallettests.cpp
|
||||
endif # ENABLE_WALLET
|
||||
|
||||
TEST_QT_H = \
|
||||
qt/test/addressbooktests.h \
|
||||
qt/test/apptests.h \
|
||||
qt/test/rpcnestedtests.h \
|
||||
qt/test/uritests.h \
|
||||
qt/test/util.h \
|
||||
qt/test/wallettests.h
|
||||
|
||||
qt_test_test_vexta_qt_CPPFLAGS = $(AM_CPPFLAGS) $(DIGIBYTE_INCLUDES) $(DIGIBYTE_QT_INCLUDES) \
|
||||
$(QT_INCLUDES) $(QT_TEST_INCLUDES)
|
||||
|
||||
qt_test_test_vexta_qt_SOURCES = \
|
||||
qt/test/apptests.cpp \
|
||||
qt/test/rpcnestedtests.cpp \
|
||||
qt/test/test_main.cpp \
|
||||
qt/test/uritests.cpp \
|
||||
qt/test/util.cpp \
|
||||
$(TEST_QT_H)
|
||||
if ENABLE_WALLET
|
||||
qt_test_test_vexta_qt_SOURCES += \
|
||||
qt/test/addressbooktests.cpp \
|
||||
qt/test/wallettests.cpp \
|
||||
wallet/test/wallet_test_fixture.cpp
|
||||
endif # ENABLE_WALLET
|
||||
|
||||
nodist_qt_test_test_vexta_qt_SOURCES = $(TEST_QT_MOC_CPP)
|
||||
|
||||
qt_test_test_vexta_qt_LDADD = $(LIBDIGIBYTEQT) $(LIBDIGIBYTE_SERVER) $(LIBTEST_UTIL)
|
||||
if ENABLE_WALLET
|
||||
qt_test_test_vexta_qt_LDADD += $(LIBDIGIBYTE_UTIL) $(LIBDIGIBYTE_WALLET)
|
||||
endif
|
||||
if ENABLE_ZMQ
|
||||
qt_test_test_vexta_qt_LDADD += $(LIBDIGIBYTE_ZMQ) $(ZMQ_LIBS)
|
||||
endif
|
||||
qt_test_test_vexta_qt_LDADD += $(LIBDIGIBYTE_CLI) $(LIBDIGIBYTE_COMMON) $(LIBDIGIBYTE_UTIL) $(LIBDIGIBYTE_CONSENSUS) $(LIBDIGIBYTE_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
|
||||
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
|
||||
$(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
|
||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS)
|
||||
qt_test_test_vexta_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
qt_test_test_vexta_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
|
||||
|
||||
CLEAN_DIGIBYTE_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno
|
||||
|
||||
CLEANFILES += $(CLEAN_DIGIBYTE_QT_TEST)
|
||||
|
||||
test_vexta_qt : qt/test/test_vexta-qt$(EXEEXT)
|
||||
|
||||
test_vexta_qt_check : qt/test/test_vexta-qt$(EXEEXT) FORCE
|
||||
$(MAKE) check-TESTS TESTS=$^
|
||||
|
||||
test_vexta_qt_clean: FORCE
|
||||
rm -f $(CLEAN_DIGIBYTE_QT_TEST) $(qt_test_test_vexta_qt_OBJECTS)
|
||||
376
src/Makefile.test.include
Normal file
376
src/Makefile.test.include
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
# Copyright (c) 2013-2016 The DigiByte Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
if ENABLE_FUZZ_BINARY
|
||||
noinst_PROGRAMS += test/fuzz/fuzz
|
||||
endif
|
||||
|
||||
if !ENABLE_FUZZ
|
||||
bin_PROGRAMS += test/test_digibyte
|
||||
endif
|
||||
|
||||
TEST_SRCDIR = test
|
||||
TEST_BINARY=test/test_digibyte$(EXEEXT)
|
||||
FUZZ_BINARY=test/fuzz/fuzz$(EXEEXT)
|
||||
|
||||
JSON_TEST_FILES = \
|
||||
test/data/script_tests.json \
|
||||
test/data/base58_encode_decode.json \
|
||||
test/data/blockfilters.json \
|
||||
test/data/key_io_valid.json \
|
||||
test/data/key_io_invalid.json \
|
||||
test/data/script_tests.json \
|
||||
test/data/sighash.json \
|
||||
test/data/tx_invalid.json \
|
||||
test/data/tx_valid.json
|
||||
|
||||
RAW_TEST_FILES = \
|
||||
test/data/asmap.raw
|
||||
|
||||
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
|
||||
|
||||
DIGIBYTE_TEST_SUITE = \
|
||||
test/main.cpp \
|
||||
$(TEST_UTIL_H)
|
||||
|
||||
FUZZ_SUITE_LD_COMMON = \
|
||||
$(LIBTEST_UTIL) \
|
||||
$(LIBTEST_FUZZ) \
|
||||
$(LIBDIGIBYTE_SERVER) \
|
||||
$(LIBDIGIBYTE_WALLET) \
|
||||
$(LIBDIGIBYTE_COMMON) \
|
||||
$(LIBDIGIBYTE_UTIL) \
|
||||
$(LIBDIGIBYTE_CONSENSUS) \
|
||||
$(LIBDIGIBYTE_CRYPTO) \
|
||||
$(LIBDIGIBYTE_CLI) \
|
||||
$(LIBUNIVALUE) \
|
||||
$(LIBLEVELDB) \
|
||||
$(LIBLEVELDB_SSE42) \
|
||||
$(BOOST_LIBS) \
|
||||
$(LIBMEMENV) \
|
||||
$(LIBSECP256K1) \
|
||||
$(EVENT_LIBS) \
|
||||
$(EVENT_PTHREADS_LIBS)
|
||||
|
||||
if USE_UPNP
|
||||
FUZZ_SUITE_LD_COMMON += $(MINIUPNPC_LIBS)
|
||||
endif
|
||||
|
||||
if USE_NATPMP
|
||||
FUZZ_SUITE_LD_COMMON += $(NATPMP_LIBS)
|
||||
endif
|
||||
|
||||
# test_digibyte binary #
|
||||
DIGIBYTE_TESTS =\
|
||||
test/arith_uint256_tests.cpp \
|
||||
test/scriptnum10.h \
|
||||
test/addrman_tests.cpp \
|
||||
test/amount_tests.cpp \
|
||||
test/allocator_tests.cpp \
|
||||
test/base32_tests.cpp \
|
||||
test/base58_tests.cpp \
|
||||
test/base64_tests.cpp \
|
||||
test/bech32_tests.cpp \
|
||||
test/bip32_tests.cpp \
|
||||
test/blockchain_tests.cpp \
|
||||
test/blockencodings_tests.cpp \
|
||||
test/blockfilter_tests.cpp \
|
||||
test/blockfilter_index_tests.cpp \
|
||||
test/bloom_tests.cpp \
|
||||
test/bswap_tests.cpp \
|
||||
test/checkqueue_tests.cpp \
|
||||
test/coins_tests.cpp \
|
||||
test/coinstatsindex_tests.cpp \
|
||||
test/compilerbug_tests.cpp \
|
||||
test/compress_tests.cpp \
|
||||
test/crypto_tests.cpp \
|
||||
test/cuckoocache_tests.cpp \
|
||||
test/denialofservice_tests.cpp \
|
||||
test/descriptor_tests.cpp \
|
||||
test/flatfile_tests.cpp \
|
||||
test/fs_tests.cpp \
|
||||
test/getarg_tests.cpp \
|
||||
test/hash_tests.cpp \
|
||||
test/i2p_tests.cpp \
|
||||
test/interfaces_tests.cpp \
|
||||
test/key_io_tests.cpp \
|
||||
test/key_tests.cpp \
|
||||
test/logging_tests.cpp \
|
||||
test/dbwrapper_tests.cpp \
|
||||
test/validation_tests.cpp \
|
||||
test/mempool_tests.cpp \
|
||||
test/merkle_tests.cpp \
|
||||
test/merkleblock_tests.cpp \
|
||||
test/miner_tests.cpp \
|
||||
test/multisig_tests.cpp \
|
||||
test/net_peer_eviction_tests.cpp \
|
||||
test/net_tests.cpp \
|
||||
test/netbase_tests.cpp \
|
||||
test/pmt_tests.cpp \
|
||||
test/policy_fee_tests.cpp \
|
||||
test/policyestimator_tests.cpp \
|
||||
test/pow_tests.cpp \
|
||||
test/prevector_tests.cpp \
|
||||
test/raii_event_tests.cpp \
|
||||
test/random_tests.cpp \
|
||||
test/reverselock_tests.cpp \
|
||||
test/rpc_tests.cpp \
|
||||
test/sanity_tests.cpp \
|
||||
test/scheduler_tests.cpp \
|
||||
test/script_p2sh_tests.cpp \
|
||||
test/script_tests.cpp \
|
||||
test/script_standard_tests.cpp \
|
||||
test/scriptnum_tests.cpp \
|
||||
test/serfloat_tests.cpp \
|
||||
test/serialize_tests.cpp \
|
||||
test/settings_tests.cpp \
|
||||
test/sighash_tests.cpp \
|
||||
test/sigopcount_tests.cpp \
|
||||
test/skiplist_tests.cpp \
|
||||
test/sock_tests.cpp \
|
||||
test/streams_tests.cpp \
|
||||
test/sync_tests.cpp \
|
||||
test/system_tests.cpp \
|
||||
test/util_threadnames_tests.cpp \
|
||||
test/timedata_tests.cpp \
|
||||
test/torcontrol_tests.cpp \
|
||||
test/transaction_tests.cpp \
|
||||
test/txindex_tests.cpp \
|
||||
test/txrequest_tests.cpp \
|
||||
test/txvalidation_tests.cpp \
|
||||
test/txvalidationcache_tests.cpp \
|
||||
test/uint256_tests.cpp \
|
||||
test/util_tests.cpp \
|
||||
test/validation_block_tests.cpp \
|
||||
test/validation_chainstate_tests.cpp \
|
||||
test/validation_chainstatemanager_tests.cpp \
|
||||
test/validation_flush_tests.cpp \
|
||||
test/validationinterface_tests.cpp \
|
||||
test/versionbits_tests.cpp
|
||||
|
||||
if ENABLE_WALLET
|
||||
DIGIBYTE_TESTS += \
|
||||
wallet/test/psbt_wallet_tests.cpp \
|
||||
wallet/test/wallet_tests.cpp \
|
||||
wallet/test/walletdb_tests.cpp \
|
||||
wallet/test/wallet_crypto_tests.cpp \
|
||||
wallet/test/coinselector_tests.cpp \
|
||||
wallet/test/init_tests.cpp \
|
||||
wallet/test/ismine_tests.cpp \
|
||||
wallet/test/scriptpubkeyman_tests.cpp
|
||||
|
||||
FUZZ_SUITE_LD_COMMON +=\
|
||||
$(SQLITE_LIBS) \
|
||||
$(BDB_LIBS)
|
||||
|
||||
if USE_BDB
|
||||
DIGIBYTE_TESTS += wallet/test/db_tests.cpp
|
||||
endif
|
||||
|
||||
|
||||
DIGIBYTE_TEST_SUITE += \
|
||||
wallet/test/wallet_test_fixture.cpp \
|
||||
wallet/test/wallet_test_fixture.h \
|
||||
wallet/test/init_test_fixture.cpp \
|
||||
wallet/test/init_test_fixture.h
|
||||
endif
|
||||
|
||||
test_test_digibyte_SOURCES = $(DIGIBYTE_TEST_SUITE) $(DIGIBYTE_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
||||
test_test_digibyte_CPPFLAGS = $(AM_CPPFLAGS) $(DIGIBYTE_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS)
|
||||
test_test_digibyte_LDADD = $(LIBTEST_UTIL)
|
||||
if ENABLE_WALLET
|
||||
test_test_digibyte_LDADD += $(LIBDIGIBYTE_WALLET)
|
||||
endif
|
||||
|
||||
test_test_digibyte_LDADD += $(LIBDIGIBYTE_SERVER) $(LIBDIGIBYTE_CLI) $(LIBDIGIBYTE_COMMON) $(LIBDIGIBYTE_UTIL) $(LIBDIGIBYTE_CONSENSUS) $(LIBDIGIBYTE_CRYPTO) $(LIBUNIVALUE) \
|
||||
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
|
||||
test_test_digibyte_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
|
||||
test_test_digibyte_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
|
||||
test_test_digibyte_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -static
|
||||
|
||||
if ENABLE_ZMQ
|
||||
test_test_digibyte_LDADD += $(LIBDIGIBYTE_ZMQ) $(ZMQ_LIBS)
|
||||
FUZZ_SUITE_LD_COMMON += $(LIBDIGIBYTE_ZMQ) $(ZMQ_LIBS)
|
||||
endif
|
||||
|
||||
FUZZ_SUITE_LDFLAGS_COMMON = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
|
||||
if ENABLE_FUZZ_BINARY
|
||||
test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(DIGIBYTE_INCLUDES)
|
||||
test_fuzz_fuzz_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
test_fuzz_fuzz_LDADD = $(FUZZ_SUITE_LD_COMMON)
|
||||
test_fuzz_fuzz_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON)
|
||||
test_fuzz_fuzz_SOURCES = \
|
||||
test/fuzz/addition_overflow.cpp \
|
||||
test/fuzz/addrdb.cpp \
|
||||
test/fuzz/addrman.cpp \
|
||||
test/fuzz/asmap.cpp \
|
||||
test/fuzz/asmap_direct.cpp \
|
||||
test/fuzz/autofile.cpp \
|
||||
test/fuzz/banman.cpp \
|
||||
test/fuzz/base_encode_decode.cpp \
|
||||
test/fuzz/bech32.cpp \
|
||||
test/fuzz/block.cpp \
|
||||
test/fuzz/block_header.cpp \
|
||||
test/fuzz/blockfilter.cpp \
|
||||
test/fuzz/bloom_filter.cpp \
|
||||
test/fuzz/buffered_file.cpp \
|
||||
test/fuzz/chain.cpp \
|
||||
test/fuzz/checkqueue.cpp \
|
||||
test/fuzz/coins_view.cpp \
|
||||
test/fuzz/connman.cpp \
|
||||
test/fuzz/crypto.cpp \
|
||||
test/fuzz/crypto_aes256.cpp \
|
||||
test/fuzz/crypto_aes256cbc.cpp \
|
||||
test/fuzz/crypto_chacha20.cpp \
|
||||
test/fuzz/crypto_chacha20_poly1305_aead.cpp \
|
||||
test/fuzz/crypto_common.cpp \
|
||||
test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp \
|
||||
test/fuzz/crypto_poly1305.cpp \
|
||||
test/fuzz/cuckoocache.cpp \
|
||||
test/fuzz/data_stream.cpp \
|
||||
test/fuzz/decode_tx.cpp \
|
||||
test/fuzz/descriptor_parse.cpp \
|
||||
test/fuzz/deserialize.cpp \
|
||||
test/fuzz/eval_script.cpp \
|
||||
test/fuzz/fee_rate.cpp \
|
||||
test/fuzz/fees.cpp \
|
||||
test/fuzz/flatfile.cpp \
|
||||
test/fuzz/float.cpp \
|
||||
test/fuzz/golomb_rice.cpp \
|
||||
test/fuzz/hex.cpp \
|
||||
test/fuzz/http_request.cpp \
|
||||
test/fuzz/i2p.cpp \
|
||||
test/fuzz/integer.cpp \
|
||||
test/fuzz/key.cpp \
|
||||
test/fuzz/key_io.cpp \
|
||||
test/fuzz/kitchen_sink.cpp \
|
||||
test/fuzz/load_external_block_file.cpp \
|
||||
test/fuzz/locale.cpp \
|
||||
test/fuzz/merkleblock.cpp \
|
||||
test/fuzz/message.cpp \
|
||||
test/fuzz/muhash.cpp \
|
||||
test/fuzz/multiplication_overflow.cpp \
|
||||
test/fuzz/net.cpp \
|
||||
test/fuzz/net_permissions.cpp \
|
||||
test/fuzz/netaddress.cpp \
|
||||
test/fuzz/netbase_dns_lookup.cpp \
|
||||
test/fuzz/node_eviction.cpp \
|
||||
test/fuzz/p2p_transport_serialization.cpp \
|
||||
test/fuzz/parse_hd_keypath.cpp \
|
||||
test/fuzz/parse_iso8601.cpp \
|
||||
test/fuzz/parse_numbers.cpp \
|
||||
test/fuzz/parse_script.cpp \
|
||||
test/fuzz/parse_univalue.cpp \
|
||||
test/fuzz/policy_estimator.cpp \
|
||||
test/fuzz/policy_estimator_io.cpp \
|
||||
test/fuzz/pow.cpp \
|
||||
test/fuzz/prevector.cpp \
|
||||
test/fuzz/primitives_transaction.cpp \
|
||||
test/fuzz/process_message.cpp \
|
||||
test/fuzz/process_messages.cpp \
|
||||
test/fuzz/protocol.cpp \
|
||||
test/fuzz/psbt.cpp \
|
||||
test/fuzz/random.cpp \
|
||||
test/fuzz/rbf.cpp \
|
||||
test/fuzz/rolling_bloom_filter.cpp \
|
||||
test/fuzz/rpc.cpp \
|
||||
test/fuzz/script.cpp \
|
||||
test/fuzz/script_assets_test_minimizer.cpp \
|
||||
test/fuzz/script_digibyte_consensus.cpp \
|
||||
test/fuzz/script_descriptor_cache.cpp \
|
||||
test/fuzz/script_flags.cpp \
|
||||
test/fuzz/script_interpreter.cpp \
|
||||
test/fuzz/script_ops.cpp \
|
||||
test/fuzz/script_sigcache.cpp \
|
||||
test/fuzz/script_sign.cpp \
|
||||
test/fuzz/scriptnum_ops.cpp \
|
||||
test/fuzz/secp256k1_ec_seckey_import_export_der.cpp \
|
||||
test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp \
|
||||
test/fuzz/signature_checker.cpp \
|
||||
test/fuzz/signet.cpp \
|
||||
test/fuzz/socks5.cpp \
|
||||
test/fuzz/span.cpp \
|
||||
test/fuzz/spanparsing.cpp \
|
||||
test/fuzz/string.cpp \
|
||||
test/fuzz/strprintf.cpp \
|
||||
test/fuzz/system.cpp \
|
||||
test/fuzz/timedata.cpp \
|
||||
test/fuzz/torcontrol.cpp \
|
||||
test/fuzz/transaction.cpp \
|
||||
test/fuzz/tx_in.cpp \
|
||||
test/fuzz/tx_out.cpp \
|
||||
test/fuzz/tx_pool.cpp \
|
||||
test/fuzz/txrequest.cpp \
|
||||
test/fuzz/utxo_snapshot.cpp \
|
||||
test/fuzz/validation_load_mempool.cpp \
|
||||
test/fuzz/versionbits.cpp
|
||||
endif # ENABLE_FUZZ_BINARY
|
||||
|
||||
nodist_test_test_digibyte_SOURCES = $(GENERATED_TEST_FILES)
|
||||
|
||||
$(DIGIBYTE_TESTS): $(GENERATED_TEST_FILES)
|
||||
|
||||
CLEAN_DIGIBYTE_TEST = test/*.gcda test/*.gcno test/fuzz/*.gcda test/fuzz/*.gcno test/util/*.gcda test/util/*.gcno $(GENERATED_TEST_FILES) $(DIGIBYTE_TESTS:=.log)
|
||||
|
||||
CLEANFILES += $(CLEAN_DIGIBYTE_TEST)
|
||||
|
||||
if TARGET_WINDOWS
|
||||
digibyte_test: $(TEST_BINARY)
|
||||
else
|
||||
if ENABLE_BENCH
|
||||
digibyte_test: $(TEST_BINARY) $(BENCH_BINARY)
|
||||
else
|
||||
digibyte_test: $(TEST_BINARY)
|
||||
endif
|
||||
endif
|
||||
|
||||
digibyte_test_check: $(TEST_BINARY) FORCE
|
||||
$(MAKE) check-TESTS TESTS=$^
|
||||
|
||||
digibyte_test_clean : FORCE
|
||||
rm -f $(CLEAN_DIGIBYTE_TEST) $(test_test_digibyte_OBJECTS) $(TEST_BINARY)
|
||||
|
||||
check-local: $(DIGIBYTE_TESTS:.cpp=.cpp.test)
|
||||
if BUILD_VEXTA_TX
|
||||
@echo "Running test/util/digibyte-util-test.py..."
|
||||
$(PYTHON) $(top_builddir)/test/util/digibyte-util-test.py
|
||||
endif
|
||||
@echo "Running test/util/rpcauth-test.py..."
|
||||
$(PYTHON) $(top_builddir)/test/util/rpcauth-test.py
|
||||
if TARGET_WINDOWS
|
||||
else
|
||||
if ENABLE_BENCH
|
||||
@echo "Running bench/bench_digibyte ..."
|
||||
$(BENCH_BINARY) > /dev/null
|
||||
endif
|
||||
endif
|
||||
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
|
||||
if EMBEDDED_UNIVALUE
|
||||
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
|
||||
endif
|
||||
|
||||
%.cpp.test: %.cpp
|
||||
@echo Running tests: `cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1` from $<
|
||||
$(AM_V_at)$(TEST_BINARY) --catch_system_errors=no -l test_suite -t "`cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1`" -- DEBUG_LOG_OUT > $<.log 2>&1 || (cat $<.log && false)
|
||||
|
||||
%.json.h: %.json
|
||||
@$(MKDIR_P) $(@D)
|
||||
@{ \
|
||||
echo "namespace json_tests{" && \
|
||||
echo "static unsigned const char $(*F)[] = {" && \
|
||||
$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
|
||||
echo "};};"; \
|
||||
} > "$@.new" && mv -f "$@.new" "$@"
|
||||
@echo "Generated $@"
|
||||
|
||||
%.raw.h: %.raw
|
||||
@$(MKDIR_P) $(@D)
|
||||
@{ \
|
||||
echo "static unsigned const char $(*F)_raw[] = {" && \
|
||||
$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
|
||||
echo "};"; \
|
||||
} > "$@.new" && mv -f "$@.new" "$@"
|
||||
@echo "Generated $@"
|
||||
25
src/Makefile.test_fuzz.include
Normal file
25
src/Makefile.test_fuzz.include
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright (c) 2013-2020 The DigiByte Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
LIBTEST_FUZZ=libtest_fuzz.a
|
||||
|
||||
EXTRA_LIBRARIES += \
|
||||
$(LIBTEST_FUZZ)
|
||||
|
||||
TEST_FUZZ_H = \
|
||||
test/fuzz/fuzz.h \
|
||||
test/fuzz/FuzzedDataProvider.h \
|
||||
test/fuzz/util.h
|
||||
|
||||
libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(DIGIBYTE_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
|
||||
libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libtest_fuzz_a_SOURCES = \
|
||||
test/fuzz/fuzz.cpp \
|
||||
test/fuzz/util.cpp \
|
||||
$(TEST_FUZZ_H)
|
||||
|
||||
LIBTEST_FUZZ += $(LIBDIGIBYTE_SERVER)
|
||||
LIBTEST_FUZZ += $(LIBDIGIBYTE_COMMON)
|
||||
LIBTEST_FUZZ += $(LIBDIGIBYTE_UTIL)
|
||||
LIBTEST_FUZZ += $(LIBDIGIBYTE_CRYPTO_BASE)
|
||||
40
src/Makefile.test_util.include
Normal file
40
src/Makefile.test_util.include
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright (c) 2013-2019 The DigiByte Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
LIBTEST_UTIL=libtest_util.a
|
||||
|
||||
EXTRA_LIBRARIES += \
|
||||
$(LIBTEST_UTIL)
|
||||
|
||||
TEST_UTIL_H = \
|
||||
test/util/blockfilter.h \
|
||||
test/util/logging.h \
|
||||
test/util/mining.h \
|
||||
test/util/net.h \
|
||||
test/util/script.h \
|
||||
test/util/setup_common.h \
|
||||
test/util/str.h \
|
||||
test/util/transaction_utils.h \
|
||||
test/util/validation.h \
|
||||
test/util/wallet.h
|
||||
|
||||
libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(DIGIBYTE_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
|
||||
libtest_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
libtest_util_a_SOURCES = \
|
||||
test/util/blockfilter.cpp \
|
||||
test/util/logging.cpp \
|
||||
test/util/mining.cpp \
|
||||
test/util/net.cpp \
|
||||
test/util/script.cpp \
|
||||
test/util/setup_common.cpp \
|
||||
test/util/str.cpp \
|
||||
test/util/transaction_utils.cpp \
|
||||
test/util/validation.cpp \
|
||||
test/util/wallet.cpp \
|
||||
$(TEST_UTIL_H)
|
||||
|
||||
LIBTEST_UTIL += $(LIBDIGIBYTE_SERVER)
|
||||
LIBTEST_UTIL += $(LIBDIGIBYTE_COMMON)
|
||||
LIBTEST_UTIL += $(LIBDIGIBYTE_UTIL)
|
||||
LIBTEST_UTIL += $(LIBDIGIBYTE_CRYPTO_BASE)
|
||||
274
src/addrdb.cpp
Normal file
274
src/addrdb.cpp
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <addrdb.h>
|
||||
|
||||
#include <addrman.h>
|
||||
#include <chainparams.h>
|
||||
#include <clientversion.h>
|
||||
#include <cstdint>
|
||||
#include <hash.h>
|
||||
#include <logging/timer.h>
|
||||
#include <netbase.h>
|
||||
#include <random.h>
|
||||
#include <streams.h>
|
||||
#include <tinyformat.h>
|
||||
#include <univalue.h>
|
||||
#include <util/settings.h>
|
||||
#include <util/system.h>
|
||||
|
||||
CBanEntry::CBanEntry(const UniValue& json)
|
||||
: nVersion(json["version"].get_int()), nCreateTime(json["ban_created"].get_int64()),
|
||||
nBanUntil(json["banned_until"].get_int64())
|
||||
{
|
||||
}
|
||||
|
||||
UniValue CBanEntry::ToJson() const
|
||||
{
|
||||
UniValue json(UniValue::VOBJ);
|
||||
json.pushKV("version", nVersion);
|
||||
json.pushKV("ban_created", nCreateTime);
|
||||
json.pushKV("banned_until", nBanUntil);
|
||||
return json;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
static const char* BANMAN_JSON_ADDR_KEY = "address";
|
||||
|
||||
/**
|
||||
* Convert a `banmap_t` object to a JSON array.
|
||||
* @param[in] bans Bans list to convert.
|
||||
* @return a JSON array, similar to the one returned by the `listbanned` RPC. Suitable for
|
||||
* passing to `BanMapFromJson()`.
|
||||
*/
|
||||
UniValue BanMapToJson(const banmap_t& bans)
|
||||
{
|
||||
UniValue bans_json(UniValue::VARR);
|
||||
for (const auto& it : bans) {
|
||||
const auto& address = it.first;
|
||||
const auto& ban_entry = it.second;
|
||||
UniValue j = ban_entry.ToJson();
|
||||
j.pushKV(BANMAN_JSON_ADDR_KEY, address.ToString());
|
||||
bans_json.push_back(j);
|
||||
}
|
||||
return bans_json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JSON array to a `banmap_t` object.
|
||||
* @param[in] bans_json JSON to convert, must be as returned by `BanMapToJson()`.
|
||||
* @param[out] bans Bans list to create from the JSON.
|
||||
* @throws std::runtime_error if the JSON does not have the expected fields or they contain
|
||||
* unparsable values.
|
||||
*/
|
||||
void BanMapFromJson(const UniValue& bans_json, banmap_t& bans)
|
||||
{
|
||||
for (const auto& ban_entry_json : bans_json.getValues()) {
|
||||
CSubNet subnet;
|
||||
const auto& subnet_str = ban_entry_json[BANMAN_JSON_ADDR_KEY].get_str();
|
||||
if (!LookupSubNet(subnet_str, subnet)) {
|
||||
throw std::runtime_error(
|
||||
strprintf("Cannot parse banned address or subnet: %s", subnet_str));
|
||||
}
|
||||
bans.insert_or_assign(subnet, CBanEntry{ban_entry_json});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream, typename Data>
|
||||
bool SerializeDB(Stream& stream, const Data& data)
|
||||
{
|
||||
// Write and commit header, data
|
||||
try {
|
||||
CHashWriter hasher(stream.GetType(), stream.GetVersion());
|
||||
stream << Params().MessageStart() << data;
|
||||
hasher << Params().MessageStart() << data;
|
||||
stream << hasher.GetHash();
|
||||
} catch (const std::exception& e) {
|
||||
return error("%s: Serialize or I/O error - %s", __func__, e.what());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Data>
|
||||
bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data, int version)
|
||||
{
|
||||
// Generate random temporary filename
|
||||
uint16_t randv = 0;
|
||||
GetRandBytes((unsigned char*)&randv, sizeof(randv));
|
||||
std::string tmpfn = strprintf("%s.%04x", prefix, randv);
|
||||
|
||||
// open temp output file, and associate with CAutoFile
|
||||
fs::path pathTmp = gArgs.GetDataDirNet() / tmpfn;
|
||||
FILE *file = fsbridge::fopen(pathTmp, "wb");
|
||||
CAutoFile fileout(file, SER_DISK, version);
|
||||
if (fileout.IsNull()) {
|
||||
fileout.fclose();
|
||||
remove(pathTmp);
|
||||
return error("%s: Failed to open file %s", __func__, pathTmp.string());
|
||||
}
|
||||
|
||||
// Serialize
|
||||
if (!SerializeDB(fileout, data)) {
|
||||
fileout.fclose();
|
||||
remove(pathTmp);
|
||||
return false;
|
||||
}
|
||||
if (!FileCommit(fileout.Get())) {
|
||||
fileout.fclose();
|
||||
remove(pathTmp);
|
||||
return error("%s: Failed to flush file %s", __func__, pathTmp.string());
|
||||
}
|
||||
fileout.fclose();
|
||||
|
||||
// replace existing file, if any, with new file
|
||||
if (!RenameOver(pathTmp, path)) {
|
||||
remove(pathTmp);
|
||||
return error("%s: Rename-into-place failed", __func__);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Stream, typename Data>
|
||||
bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
|
||||
{
|
||||
try {
|
||||
CHashVerifier<Stream> verifier(&stream);
|
||||
// de-serialize file header (network specific magic number) and ..
|
||||
unsigned char pchMsgTmp[4];
|
||||
verifier >> pchMsgTmp;
|
||||
// ... verify the network matches ours
|
||||
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
|
||||
return error("%s: Invalid network magic number", __func__);
|
||||
|
||||
// de-serialize data
|
||||
verifier >> data;
|
||||
|
||||
// verify checksum
|
||||
if (fCheckSum) {
|
||||
uint256 hashTmp;
|
||||
stream >> hashTmp;
|
||||
if (hashTmp != verifier.GetHash()) {
|
||||
return error("%s: Checksum mismatch, data corrupted", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Data>
|
||||
bool DeserializeFileDB(const fs::path& path, Data& data, int version)
|
||||
{
|
||||
// open input file, and associate with CAutoFile
|
||||
FILE* file = fsbridge::fopen(path, "rb");
|
||||
CAutoFile filein(file, SER_DISK, version);
|
||||
if (filein.IsNull()) {
|
||||
LogPrintf("Missing or invalid file %s\n", path.string());
|
||||
return false;
|
||||
}
|
||||
return DeserializeDB(filein, data);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CBanDB::CBanDB(fs::path ban_list_path)
|
||||
: m_banlist_dat(ban_list_path.string() + ".dat"),
|
||||
m_banlist_json(ban_list_path.string() + ".json")
|
||||
{
|
||||
}
|
||||
|
||||
bool CBanDB::Write(const banmap_t& banSet)
|
||||
{
|
||||
std::vector<std::string> errors;
|
||||
if (util::WriteSettings(m_banlist_json, {{JSON_KEY, BanMapToJson(banSet)}}, errors)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& err : errors) {
|
||||
error("%s", err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBanDB::Read(banmap_t& banSet, bool& dirty)
|
||||
{
|
||||
// If the JSON banlist does not exist, then try to read the non-upgraded banlist.dat.
|
||||
if (!fs::exists(m_banlist_json)) {
|
||||
// If this succeeds then we need to flush to disk in order to create the JSON banlist.
|
||||
dirty = true;
|
||||
return DeserializeFileDB(m_banlist_dat, banSet, CLIENT_VERSION);
|
||||
}
|
||||
|
||||
dirty = false;
|
||||
|
||||
std::map<std::string, util::SettingsValue> settings;
|
||||
std::vector<std::string> errors;
|
||||
|
||||
if (!util::ReadSettings(m_banlist_json, settings, errors)) {
|
||||
for (const auto& err : errors) {
|
||||
LogPrintf("Cannot load banlist %s: %s\n", m_banlist_json.string(), err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
BanMapFromJson(settings[JSON_KEY], banSet);
|
||||
} catch (const std::runtime_error& e) {
|
||||
LogPrintf("Cannot parse banlist %s: %s\n", m_banlist_json.string(), e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CAddrDB::CAddrDB()
|
||||
{
|
||||
pathAddr = gArgs.GetDataDirNet() / "peers.dat";
|
||||
}
|
||||
|
||||
bool CAddrDB::Write(const CAddrMan& addr)
|
||||
{
|
||||
return SerializeFileDB("peers", pathAddr, addr, CLIENT_VERSION);
|
||||
}
|
||||
|
||||
bool CAddrDB::Read(CAddrMan& addr)
|
||||
{
|
||||
return DeserializeFileDB(pathAddr, addr, CLIENT_VERSION);
|
||||
}
|
||||
|
||||
bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
|
||||
{
|
||||
bool ret = DeserializeDB(ssPeers, addr, false);
|
||||
if (!ret) {
|
||||
// Ensure addrman is left in a clean state
|
||||
addr.Clear();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors)
|
||||
{
|
||||
LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size()));
|
||||
SerializeFileDB("anchors", anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT);
|
||||
}
|
||||
|
||||
std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
|
||||
{
|
||||
std::vector<CAddress> anchors;
|
||||
if (DeserializeFileDB(anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT)) {
|
||||
LogPrintf("Loaded %i addresses from %s\n", anchors.size(), anchors_db_path.filename());
|
||||
} else {
|
||||
anchors.clear();
|
||||
}
|
||||
|
||||
fs::remove(anchors_db_path);
|
||||
return anchors;
|
||||
}
|
||||
122
src/addrdb.h
Normal file
122
src/addrdb.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ADDRDB_H
|
||||
#define DIGIBYTE_ADDRDB_H
|
||||
|
||||
#include <fs.h>
|
||||
#include <net_types.h> // For banmap_t
|
||||
#include <serialize.h>
|
||||
#include <univalue.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CAddress;
|
||||
class CAddrMan;
|
||||
class CDataStream;
|
||||
|
||||
class CBanEntry
|
||||
{
|
||||
public:
|
||||
static const int CURRENT_VERSION=1;
|
||||
int nVersion;
|
||||
int64_t nCreateTime;
|
||||
int64_t nBanUntil;
|
||||
|
||||
CBanEntry()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
|
||||
explicit CBanEntry(int64_t nCreateTimeIn)
|
||||
{
|
||||
SetNull();
|
||||
nCreateTime = nCreateTimeIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ban entry from JSON.
|
||||
* @param[in] json A JSON representation of a ban entry, as created by `ToJson()`.
|
||||
* @throw std::runtime_error if the JSON does not have the expected fields.
|
||||
*/
|
||||
explicit CBanEntry(const UniValue& json);
|
||||
|
||||
SERIALIZE_METHODS(CBanEntry, obj)
|
||||
{
|
||||
uint8_t ban_reason = 2; //! For backward compatibility
|
||||
READWRITE(obj.nVersion, obj.nCreateTime, obj.nBanUntil, ban_reason);
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nVersion = CBanEntry::CURRENT_VERSION;
|
||||
nCreateTime = 0;
|
||||
nBanUntil = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a JSON representation of this ban entry.
|
||||
* @return JSON suitable for passing to the `CBanEntry(const UniValue&)` constructor.
|
||||
*/
|
||||
UniValue ToJson() const;
|
||||
};
|
||||
|
||||
/** Access to the (IP) address database (peers.dat) */
|
||||
class CAddrDB
|
||||
{
|
||||
private:
|
||||
fs::path pathAddr;
|
||||
public:
|
||||
CAddrDB();
|
||||
bool Write(const CAddrMan& addr);
|
||||
bool Read(CAddrMan& addr);
|
||||
static bool Read(CAddrMan& addr, CDataStream& ssPeers);
|
||||
};
|
||||
|
||||
/** Access to the banlist databases (banlist.json and banlist.dat) */
|
||||
class CBanDB
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* JSON key under which the data is stored in the json database.
|
||||
*/
|
||||
static constexpr const char* JSON_KEY = "banned_nets";
|
||||
|
||||
const fs::path m_banlist_dat;
|
||||
const fs::path m_banlist_json;
|
||||
public:
|
||||
explicit CBanDB(fs::path ban_list_path);
|
||||
bool Write(const banmap_t& banSet);
|
||||
|
||||
/**
|
||||
* Read the banlist from disk.
|
||||
* @param[out] banSet The loaded list. Set if `true` is returned, otherwise it is left
|
||||
* in an undefined state.
|
||||
* @param[out] dirty Indicates whether the loaded list needs flushing to disk. Set if
|
||||
* `true` is returned, otherwise it is left in an undefined state.
|
||||
* @return true on success
|
||||
*/
|
||||
bool Read(banmap_t& banSet, bool& dirty);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dump the anchor IP address database (anchors.dat)
|
||||
*
|
||||
* Anchors are last known outgoing block-relay-only peers that are
|
||||
* tried to re-connect to on startup.
|
||||
*/
|
||||
void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors);
|
||||
|
||||
/**
|
||||
* Read the anchor IP address database (anchors.dat)
|
||||
*
|
||||
* Deleting anchors.dat is intentional as it avoids renewed peering to anchors after
|
||||
* an unclean shutdown and thus potential exploitation of the anchor peer policy.
|
||||
*/
|
||||
std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path);
|
||||
|
||||
#endif // DIGIBYTE_ADDRDB_H
|
||||
734
src/addrman.cpp
Normal file
734
src/addrman.cpp
Normal file
|
|
@ -0,0 +1,734 @@
|
|||
// Copyright (c) 2012 Pieter Wuille
|
||||
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <addrman.h>
|
||||
|
||||
#include <hash.h>
|
||||
#include <logging.h>
|
||||
#include <netaddress.h>
|
||||
#include <serialize.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asmap) const
|
||||
{
|
||||
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
|
||||
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
|
||||
int tried_bucket = hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
|
||||
uint32_t mapped_as = GetMappedAS(asmap);
|
||||
LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to tried bucket %i\n", ToStringIP(), mapped_as, tried_bucket);
|
||||
return tried_bucket;
|
||||
}
|
||||
|
||||
int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool> &asmap) const
|
||||
{
|
||||
std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
|
||||
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
|
||||
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
|
||||
int new_bucket = hash2 % ADDRMAN_NEW_BUCKET_COUNT;
|
||||
uint32_t mapped_as = GetMappedAS(asmap);
|
||||
LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to new bucket %i\n", ToStringIP(), mapped_as, new_bucket);
|
||||
return new_bucket;
|
||||
}
|
||||
|
||||
int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const
|
||||
{
|
||||
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << nBucket << GetKey()).GetCheapHash();
|
||||
return hash1 % ADDRMAN_BUCKET_SIZE;
|
||||
}
|
||||
|
||||
bool CAddrInfo::IsTerrible(int64_t nNow) const
|
||||
{
|
||||
if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
|
||||
return false;
|
||||
|
||||
if (nTime > nNow + 10 * 60) // came in a flying DeLorean
|
||||
return true;
|
||||
|
||||
if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
|
||||
return true;
|
||||
|
||||
if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
|
||||
return true;
|
||||
|
||||
if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
double CAddrInfo::GetChance(int64_t nNow) const
|
||||
{
|
||||
double fChance = 1.0;
|
||||
int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
|
||||
|
||||
// deprioritize very recent attempts away
|
||||
if (nSinceLastTry < 60 * 10)
|
||||
fChance *= 0.01;
|
||||
|
||||
// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
|
||||
fChance *= pow(0.66, std::min(nAttempts, 8));
|
||||
|
||||
return fChance;
|
||||
}
|
||||
|
||||
void CAddrMan::RemoveInvalid()
|
||||
{
|
||||
for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) {
|
||||
for (size_t i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
|
||||
const auto id = vvNew[bucket][i];
|
||||
if (id != -1 && !mapInfo[id].IsValid()) {
|
||||
ClearNew(bucket, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; ++bucket) {
|
||||
for (size_t i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
|
||||
const auto id = vvTried[bucket][i];
|
||||
if (id == -1) {
|
||||
continue;
|
||||
}
|
||||
const auto& addr_info = mapInfo[id];
|
||||
if (addr_info.IsValid()) {
|
||||
continue;
|
||||
}
|
||||
vvTried[bucket][i] = -1;
|
||||
--nTried;
|
||||
SwapRandom(addr_info.nRandomPos, vRandom.size() - 1);
|
||||
vRandom.pop_back();
|
||||
mapAddr.erase(addr_info);
|
||||
mapInfo.erase(id);
|
||||
m_tried_collisions.erase(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
const auto it = mapAddr.find(addr);
|
||||
if (it == mapAddr.end())
|
||||
return nullptr;
|
||||
if (pnId)
|
||||
*pnId = (*it).second;
|
||||
const auto it2 = mapInfo.find((*it).second);
|
||||
if (it2 != mapInfo.end())
|
||||
return &(*it2).second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
int nId = nIdCount++;
|
||||
mapInfo[nId] = CAddrInfo(addr, addrSource);
|
||||
mapAddr[addr] = nId;
|
||||
mapInfo[nId].nRandomPos = vRandom.size();
|
||||
vRandom.push_back(nId);
|
||||
if (pnId)
|
||||
*pnId = nId;
|
||||
return &mapInfo[nId];
|
||||
}
|
||||
|
||||
void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
if (nRndPos1 == nRndPos2)
|
||||
return;
|
||||
|
||||
assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
|
||||
|
||||
int nId1 = vRandom[nRndPos1];
|
||||
int nId2 = vRandom[nRndPos2];
|
||||
|
||||
assert(mapInfo.count(nId1) == 1);
|
||||
assert(mapInfo.count(nId2) == 1);
|
||||
|
||||
mapInfo[nId1].nRandomPos = nRndPos2;
|
||||
mapInfo[nId2].nRandomPos = nRndPos1;
|
||||
|
||||
vRandom[nRndPos1] = nId2;
|
||||
vRandom[nRndPos2] = nId1;
|
||||
}
|
||||
|
||||
void CAddrMan::Delete(int nId)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
assert(mapInfo.count(nId) != 0);
|
||||
CAddrInfo& info = mapInfo[nId];
|
||||
assert(!info.fInTried);
|
||||
assert(info.nRefCount == 0);
|
||||
|
||||
SwapRandom(info.nRandomPos, vRandom.size() - 1);
|
||||
vRandom.pop_back();
|
||||
mapAddr.erase(info);
|
||||
mapInfo.erase(nId);
|
||||
nNew--;
|
||||
}
|
||||
|
||||
void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
// if there is an entry in the specified bucket, delete it.
|
||||
if (vvNew[nUBucket][nUBucketPos] != -1) {
|
||||
int nIdDelete = vvNew[nUBucket][nUBucketPos];
|
||||
CAddrInfo& infoDelete = mapInfo[nIdDelete];
|
||||
assert(infoDelete.nRefCount > 0);
|
||||
infoDelete.nRefCount--;
|
||||
vvNew[nUBucket][nUBucketPos] = -1;
|
||||
if (infoDelete.nRefCount == 0) {
|
||||
Delete(nIdDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAddrMan::MakeTried(CAddrInfo& info, int nId)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
// remove the entry from all new buckets
|
||||
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
|
||||
int pos = info.GetBucketPosition(nKey, true, bucket);
|
||||
if (vvNew[bucket][pos] == nId) {
|
||||
vvNew[bucket][pos] = -1;
|
||||
info.nRefCount--;
|
||||
}
|
||||
}
|
||||
nNew--;
|
||||
|
||||
assert(info.nRefCount == 0);
|
||||
|
||||
// which tried bucket to move the entry to
|
||||
int nKBucket = info.GetTriedBucket(nKey, m_asmap);
|
||||
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
|
||||
|
||||
// first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
|
||||
if (vvTried[nKBucket][nKBucketPos] != -1) {
|
||||
// find an item to evict
|
||||
int nIdEvict = vvTried[nKBucket][nKBucketPos];
|
||||
assert(mapInfo.count(nIdEvict) == 1);
|
||||
CAddrInfo& infoOld = mapInfo[nIdEvict];
|
||||
|
||||
// Remove the to-be-evicted item from the tried set.
|
||||
infoOld.fInTried = false;
|
||||
vvTried[nKBucket][nKBucketPos] = -1;
|
||||
nTried--;
|
||||
|
||||
// find which new bucket it belongs to
|
||||
int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
|
||||
int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
|
||||
ClearNew(nUBucket, nUBucketPos);
|
||||
assert(vvNew[nUBucket][nUBucketPos] == -1);
|
||||
|
||||
// Enter it into the new set again.
|
||||
infoOld.nRefCount = 1;
|
||||
vvNew[nUBucket][nUBucketPos] = nIdEvict;
|
||||
nNew++;
|
||||
}
|
||||
assert(vvTried[nKBucket][nKBucketPos] == -1);
|
||||
|
||||
vvTried[nKBucket][nKBucketPos] = nId;
|
||||
nTried++;
|
||||
info.fInTried = true;
|
||||
}
|
||||
|
||||
void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
int nId;
|
||||
|
||||
nLastGood = nTime;
|
||||
|
||||
CAddrInfo* pinfo = Find(addr, &nId);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
return;
|
||||
|
||||
// update info
|
||||
info.nLastSuccess = nTime;
|
||||
info.nLastTry = nTime;
|
||||
info.nAttempts = 0;
|
||||
// nTime is not updated here, to avoid leaking information about
|
||||
// currently-connected peers.
|
||||
|
||||
// if it is already in the tried set, don't do anything else
|
||||
if (info.fInTried)
|
||||
return;
|
||||
|
||||
// find a bucket it is in now
|
||||
int nRnd = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
|
||||
int nUBucket = -1;
|
||||
for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
|
||||
int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT;
|
||||
int nBpos = info.GetBucketPosition(nKey, true, nB);
|
||||
if (vvNew[nB][nBpos] == nId) {
|
||||
nUBucket = nB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if no bucket is found, something bad happened;
|
||||
// TODO: maybe re-add the node, but for now, just bail out
|
||||
if (nUBucket == -1)
|
||||
return;
|
||||
|
||||
// which tried bucket to move the entry to
|
||||
int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
|
||||
int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
|
||||
|
||||
// Will moving this address into tried evict another entry?
|
||||
if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
|
||||
// Output the entry we'd be colliding with, for debugging purposes
|
||||
auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
|
||||
LogPrint(BCLog::ADDRMAN, "Collision inserting element into tried table (%s), moving %s to m_tried_collisions=%d\n", colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "", addr.ToString(), m_tried_collisions.size());
|
||||
if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) {
|
||||
m_tried_collisions.insert(nId);
|
||||
}
|
||||
} else {
|
||||
LogPrint(BCLog::ADDRMAN, "Moving %s to tried\n", addr.ToString());
|
||||
|
||||
// move nId to the tried tables
|
||||
MakeTried(info, nId);
|
||||
}
|
||||
}
|
||||
|
||||
bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
if (!addr.IsRoutable())
|
||||
return false;
|
||||
|
||||
bool fNew = false;
|
||||
int nId;
|
||||
CAddrInfo* pinfo = Find(addr, &nId);
|
||||
|
||||
// Do not set a penalty for a source's self-announcement
|
||||
if (addr == source) {
|
||||
nTimePenalty = 0;
|
||||
}
|
||||
|
||||
if (pinfo) {
|
||||
// periodically update nTime
|
||||
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
|
||||
int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
|
||||
if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
|
||||
pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
|
||||
|
||||
// add services
|
||||
pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
|
||||
|
||||
// do not update if no new information is present
|
||||
if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
|
||||
return false;
|
||||
|
||||
// do not update if the entry was already in the "tried" table
|
||||
if (pinfo->fInTried)
|
||||
return false;
|
||||
|
||||
// do not update if the max reference count is reached
|
||||
if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
|
||||
return false;
|
||||
|
||||
// stochastic test: previous nRefCount == N: 2^N times harder to increase it
|
||||
int nFactor = 1;
|
||||
for (int n = 0; n < pinfo->nRefCount; n++)
|
||||
nFactor *= 2;
|
||||
if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
|
||||
return false;
|
||||
} else {
|
||||
pinfo = Create(addr, source, &nId);
|
||||
pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
|
||||
nNew++;
|
||||
fNew = true;
|
||||
}
|
||||
|
||||
int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
|
||||
int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
|
||||
if (vvNew[nUBucket][nUBucketPos] != nId) {
|
||||
bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
|
||||
if (!fInsert) {
|
||||
CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
|
||||
if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
|
||||
// Overwrite the existing new table entry.
|
||||
fInsert = true;
|
||||
}
|
||||
}
|
||||
if (fInsert) {
|
||||
ClearNew(nUBucket, nUBucketPos);
|
||||
pinfo->nRefCount++;
|
||||
vvNew[nUBucket][nUBucketPos] = nId;
|
||||
} else {
|
||||
if (pinfo->nRefCount == 0) {
|
||||
Delete(nId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return fNew;
|
||||
}
|
||||
|
||||
void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
CAddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
return;
|
||||
|
||||
// update info
|
||||
info.nLastTry = nTime;
|
||||
if (fCountFailure && info.nLastCountAttempt < nLastGood) {
|
||||
info.nLastCountAttempt = nTime;
|
||||
info.nAttempts++;
|
||||
}
|
||||
}
|
||||
|
||||
CAddrInfo CAddrMan::Select_(bool newOnly)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
if (vRandom.empty())
|
||||
return CAddrInfo();
|
||||
|
||||
if (newOnly && nNew == 0)
|
||||
return CAddrInfo();
|
||||
|
||||
// Use a 50% chance for choosing between tried and new table entries.
|
||||
if (!newOnly &&
|
||||
(nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
|
||||
// use a tried node
|
||||
double fChanceFactor = 1.0;
|
||||
while (1) {
|
||||
int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
|
||||
int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
|
||||
while (vvTried[nKBucket][nKBucketPos] == -1) {
|
||||
nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT;
|
||||
nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
|
||||
}
|
||||
int nId = vvTried[nKBucket][nKBucketPos];
|
||||
assert(mapInfo.count(nId) == 1);
|
||||
CAddrInfo& info = mapInfo[nId];
|
||||
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
|
||||
return info;
|
||||
fChanceFactor *= 1.2;
|
||||
}
|
||||
} else {
|
||||
// use a new node
|
||||
double fChanceFactor = 1.0;
|
||||
while (1) {
|
||||
int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
|
||||
int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
|
||||
while (vvNew[nUBucket][nUBucketPos] == -1) {
|
||||
nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT;
|
||||
nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
|
||||
}
|
||||
int nId = vvNew[nUBucket][nUBucketPos];
|
||||
assert(mapInfo.count(nId) == 1);
|
||||
CAddrInfo& info = mapInfo[nId];
|
||||
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
|
||||
return info;
|
||||
fChanceFactor *= 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ADDRMAN
|
||||
int CAddrMan::Check_()
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
std::unordered_set<int> setTried;
|
||||
std::unordered_map<int, int> mapNew;
|
||||
|
||||
if (vRandom.size() != (size_t)(nTried + nNew))
|
||||
return -7;
|
||||
|
||||
for (const auto& entry : mapInfo) {
|
||||
int n = entry.first;
|
||||
const CAddrInfo& info = entry.second;
|
||||
if (info.fInTried) {
|
||||
if (!info.nLastSuccess)
|
||||
return -1;
|
||||
if (info.nRefCount)
|
||||
return -2;
|
||||
setTried.insert(n);
|
||||
} else {
|
||||
if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
|
||||
return -3;
|
||||
if (!info.nRefCount)
|
||||
return -4;
|
||||
mapNew[n] = info.nRefCount;
|
||||
}
|
||||
if (mapAddr[info] != n)
|
||||
return -5;
|
||||
if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
|
||||
return -14;
|
||||
if (info.nLastTry < 0)
|
||||
return -6;
|
||||
if (info.nLastSuccess < 0)
|
||||
return -8;
|
||||
}
|
||||
|
||||
if (setTried.size() != (size_t)nTried)
|
||||
return -9;
|
||||
if (mapNew.size() != (size_t)nNew)
|
||||
return -10;
|
||||
|
||||
for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
|
||||
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
|
||||
if (vvTried[n][i] != -1) {
|
||||
if (!setTried.count(vvTried[n][i]))
|
||||
return -11;
|
||||
if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey, m_asmap) != n)
|
||||
return -17;
|
||||
if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)
|
||||
return -18;
|
||||
setTried.erase(vvTried[n][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
|
||||
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
|
||||
if (vvNew[n][i] != -1) {
|
||||
if (!mapNew.count(vvNew[n][i]))
|
||||
return -12;
|
||||
if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)
|
||||
return -19;
|
||||
if (--mapNew[vvNew[n][i]] == 0)
|
||||
mapNew.erase(vvNew[n][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setTried.size())
|
||||
return -13;
|
||||
if (mapNew.size())
|
||||
return -15;
|
||||
if (nKey.IsNull())
|
||||
return -16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
size_t nNodes = vRandom.size();
|
||||
if (max_pct != 0) {
|
||||
nNodes = max_pct * nNodes / 100;
|
||||
}
|
||||
if (max_addresses != 0) {
|
||||
nNodes = std::min(nNodes, max_addresses);
|
||||
}
|
||||
|
||||
// gather a list of random nodes, skipping those of low quality
|
||||
const int64_t now{GetAdjustedTime()};
|
||||
for (unsigned int n = 0; n < vRandom.size(); n++) {
|
||||
if (vAddr.size() >= nNodes)
|
||||
break;
|
||||
|
||||
int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
|
||||
SwapRandom(n, nRndPos);
|
||||
assert(mapInfo.count(vRandom[n]) == 1);
|
||||
|
||||
const CAddrInfo& ai = mapInfo[vRandom[n]];
|
||||
|
||||
// Filter by network (optional)
|
||||
if (network != std::nullopt && ai.GetNetClass() != network) continue;
|
||||
|
||||
// Filter for quality
|
||||
if (ai.IsTerrible(now)) continue;
|
||||
|
||||
vAddr.push_back(ai);
|
||||
}
|
||||
}
|
||||
|
||||
void CAddrMan::Connected_(const CService& addr, int64_t nTime)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
CAddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
return;
|
||||
|
||||
// update info
|
||||
int64_t nUpdateInterval = 20 * 60;
|
||||
if (nTime - info.nTime > nUpdateInterval)
|
||||
info.nTime = nTime;
|
||||
}
|
||||
|
||||
void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
CAddrInfo* pinfo = Find(addr);
|
||||
|
||||
// if not found, bail out
|
||||
if (!pinfo)
|
||||
return;
|
||||
|
||||
CAddrInfo& info = *pinfo;
|
||||
|
||||
// check whether we are talking about the exact same CService (including same port)
|
||||
if (info != addr)
|
||||
return;
|
||||
|
||||
// update info
|
||||
info.nServices = nServices;
|
||||
}
|
||||
|
||||
void CAddrMan::ResolveCollisions_()
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
|
||||
int id_new = *it;
|
||||
|
||||
bool erase_collision = false;
|
||||
|
||||
// If id_new not found in mapInfo remove it from m_tried_collisions
|
||||
if (mapInfo.count(id_new) != 1) {
|
||||
erase_collision = true;
|
||||
} else {
|
||||
CAddrInfo& info_new = mapInfo[id_new];
|
||||
|
||||
// Which tried bucket to move the entry to.
|
||||
int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
|
||||
int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
|
||||
if (!info_new.IsValid()) { // id_new may no longer map to a valid address
|
||||
erase_collision = true;
|
||||
} else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
|
||||
|
||||
// Get the to-be-evicted address that is being tested
|
||||
int id_old = vvTried[tried_bucket][tried_bucket_pos];
|
||||
CAddrInfo& info_old = mapInfo[id_old];
|
||||
|
||||
// Has successfully connected in last X hours
|
||||
if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
|
||||
erase_collision = true;
|
||||
} else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
|
||||
|
||||
// Give address at least 60 seconds to successfully connect
|
||||
if (GetAdjustedTime() - info_old.nLastTry > 60) {
|
||||
LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
|
||||
|
||||
// Replaces an existing address already in the tried table with the new address
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
} else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
|
||||
// If the collision hasn't resolved in some reasonable amount of time,
|
||||
// just evict the old entry -- we must not be able to
|
||||
// connect to it for some reason.
|
||||
LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
} else { // Collision is not actually a collision anymore
|
||||
Good_(info_new, false, GetAdjustedTime());
|
||||
erase_collision = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (erase_collision) {
|
||||
m_tried_collisions.erase(it++);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CAddrInfo CAddrMan::SelectTriedCollision_()
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
|
||||
if (m_tried_collisions.size() == 0) return CAddrInfo();
|
||||
|
||||
std::set<int>::iterator it = m_tried_collisions.begin();
|
||||
|
||||
// Selects a random element from m_tried_collisions
|
||||
std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
|
||||
int id_new = *it;
|
||||
|
||||
// If id_new not found in mapInfo remove it from m_tried_collisions
|
||||
if (mapInfo.count(id_new) != 1) {
|
||||
m_tried_collisions.erase(it);
|
||||
return CAddrInfo();
|
||||
}
|
||||
|
||||
const CAddrInfo& newInfo = mapInfo[id_new];
|
||||
|
||||
// which tried bucket to move the entry to
|
||||
int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
|
||||
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
|
||||
|
||||
int id_old = vvTried[tried_bucket][tried_bucket_pos];
|
||||
|
||||
return mapInfo[id_old];
|
||||
}
|
||||
|
||||
std::vector<bool> CAddrMan::DecodeAsmap(fs::path path)
|
||||
{
|
||||
std::vector<bool> bits;
|
||||
FILE *filestr = fsbridge::fopen(path, "rb");
|
||||
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
|
||||
if (file.IsNull()) {
|
||||
LogPrintf("Failed to open asmap file from disk\n");
|
||||
return bits;
|
||||
}
|
||||
fseek(filestr, 0, SEEK_END);
|
||||
int length = ftell(filestr);
|
||||
LogPrintf("Opened asmap file %s (%d bytes) from disk\n", path, length);
|
||||
fseek(filestr, 0, SEEK_SET);
|
||||
uint8_t cur_byte;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
file >> cur_byte;
|
||||
for (int bit = 0; bit < 8; ++bit) {
|
||||
bits.push_back((cur_byte >> bit) & 1);
|
||||
}
|
||||
}
|
||||
if (!SanityCheckASMap(bits)) {
|
||||
LogPrintf("Sanity check of asmap file %s failed\n", path);
|
||||
return {};
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
780
src/addrman.h
Normal file
780
src/addrman.h
Normal file
|
|
@ -0,0 +1,780 @@
|
|||
// Copyright (c) 2012 Pieter Wuille
|
||||
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ADDRMAN_H
|
||||
#define DIGIBYTE_ADDRMAN_H
|
||||
|
||||
#include <clientversion.h>
|
||||
#include <config/vexta-config.h>
|
||||
#include <fs.h>
|
||||
#include <hash.h>
|
||||
#include <netaddress.h>
|
||||
#include <protocol.h>
|
||||
#include <random.h>
|
||||
#include <streams.h>
|
||||
#include <sync.h>
|
||||
#include <timedata.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Extended statistics about a CAddress
|
||||
*/
|
||||
class CAddrInfo : public CAddress
|
||||
{
|
||||
public:
|
||||
//! last try whatsoever by us (memory only)
|
||||
int64_t nLastTry{0};
|
||||
|
||||
//! last counted attempt (memory only)
|
||||
int64_t nLastCountAttempt{0};
|
||||
|
||||
private:
|
||||
//! where knowledge about this address first came from
|
||||
CNetAddr source;
|
||||
|
||||
//! last successful connection by us
|
||||
int64_t nLastSuccess{0};
|
||||
|
||||
//! connection attempts since last successful attempt
|
||||
int nAttempts{0};
|
||||
|
||||
//! reference count in new sets (memory only)
|
||||
int nRefCount{0};
|
||||
|
||||
//! in tried set? (memory only)
|
||||
bool fInTried{false};
|
||||
|
||||
//! position in vRandom
|
||||
int nRandomPos{-1};
|
||||
|
||||
friend class CAddrMan;
|
||||
|
||||
public:
|
||||
|
||||
SERIALIZE_METHODS(CAddrInfo, obj)
|
||||
{
|
||||
READWRITEAS(CAddress, obj);
|
||||
READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
|
||||
}
|
||||
|
||||
CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
|
||||
{
|
||||
}
|
||||
|
||||
CAddrInfo() : CAddress(), source()
|
||||
{
|
||||
}
|
||||
|
||||
//! Calculate in which "tried" bucket this entry belongs
|
||||
int GetTriedBucket(const uint256 &nKey, const std::vector<bool> &asmap) const;
|
||||
|
||||
//! Calculate in which "new" bucket this entry belongs, given a certain source
|
||||
int GetNewBucket(const uint256 &nKey, const CNetAddr& src, const std::vector<bool> &asmap) const;
|
||||
|
||||
//! Calculate in which "new" bucket this entry belongs, using its default source
|
||||
int GetNewBucket(const uint256 &nKey, const std::vector<bool> &asmap) const
|
||||
{
|
||||
return GetNewBucket(nKey, source, asmap);
|
||||
}
|
||||
|
||||
//! Calculate in which position of a bucket to store this entry.
|
||||
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
|
||||
|
||||
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
|
||||
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
|
||||
|
||||
//! Calculate the relative chance this entry should be given when selecting nodes to connect to
|
||||
double GetChance(int64_t nNow = GetAdjustedTime()) const;
|
||||
};
|
||||
|
||||
/** Stochastic address manager
|
||||
*
|
||||
* Design goals:
|
||||
* * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat.
|
||||
* * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
|
||||
*
|
||||
* To that end:
|
||||
* * Addresses are organized into buckets.
|
||||
* * Addresses that have not yet been tried go into 1024 "new" buckets.
|
||||
* * Based on the address range (/16 for IPv4) of the source of information, 64 buckets are selected at random.
|
||||
* * The actual bucket is chosen from one of these, based on the range in which the address itself is located.
|
||||
* * One single address can occur in up to 8 different buckets to increase selection chances for addresses that
|
||||
* are seen frequently. The chance for increasing this multiplicity decreases exponentially.
|
||||
* * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
|
||||
* ones) is removed from it first.
|
||||
* * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
|
||||
* * Each address range selects at random 8 of these buckets.
|
||||
* * The actual bucket is chosen from one of these, based on the full address.
|
||||
* * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
|
||||
* tried ones) is evicted from it, back to the "new" buckets.
|
||||
* * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
|
||||
* be observable by adversaries.
|
||||
* * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
|
||||
* consistency checks for the entire data structure.
|
||||
*/
|
||||
|
||||
//! total number of buckets for tried addresses
|
||||
#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8
|
||||
|
||||
//! total number of buckets for new addresses
|
||||
#define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10
|
||||
|
||||
//! maximum allowed number of entries in buckets for new and tried addresses
|
||||
#define ADDRMAN_BUCKET_SIZE_LOG2 6
|
||||
|
||||
//! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
|
||||
#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
|
||||
|
||||
//! over how many buckets entries with new addresses originating from a single group are spread
|
||||
#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64
|
||||
|
||||
//! in how many buckets for entries with new addresses a single address may occur
|
||||
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8
|
||||
|
||||
//! how old addresses can maximally be
|
||||
#define ADDRMAN_HORIZON_DAYS 30
|
||||
|
||||
//! after how many failed attempts we give up on a new node
|
||||
#define ADDRMAN_RETRIES 3
|
||||
|
||||
//! how many successive failures are allowed ...
|
||||
#define ADDRMAN_MAX_FAILURES 10
|
||||
|
||||
//! ... in at least this many days
|
||||
#define ADDRMAN_MIN_FAIL_DAYS 7
|
||||
|
||||
//! how recent a successful connection should be before we allow an address to be evicted from tried
|
||||
#define ADDRMAN_REPLACEMENT_HOURS 4
|
||||
|
||||
//! Convenience
|
||||
#define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
|
||||
#define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)
|
||||
#define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)
|
||||
|
||||
//! the maximum number of tried addr collisions to store
|
||||
#define ADDRMAN_SET_TRIED_COLLISION_SIZE 10
|
||||
|
||||
//! the maximum time we'll spend trying to resolve a tried table collision, in seconds
|
||||
static const int64_t ADDRMAN_TEST_WINDOW = 40*60; // 40 minutes
|
||||
|
||||
/**
|
||||
* Stochastical (IP) address manager
|
||||
*/
|
||||
class CAddrMan
|
||||
{
|
||||
public:
|
||||
// Compressed IP->ASN mapping, loaded from a file when a node starts.
|
||||
// Should be always empty if no file was provided.
|
||||
// This mapping is then used for bucketing nodes in Addrman.
|
||||
//
|
||||
// If asmap is provided, nodes will be bucketed by
|
||||
// AS they belong to, in order to make impossible for a node
|
||||
// to connect to several nodes hosted in a single AS.
|
||||
// This is done in response to Erebus attack, but also to generally
|
||||
// diversify the connections every node creates,
|
||||
// especially useful when a large fraction of nodes
|
||||
// operate under a couple of cloud providers.
|
||||
//
|
||||
// If a new asmap was provided, the existing records
|
||||
// would be re-bucketed accordingly.
|
||||
std::vector<bool> m_asmap;
|
||||
|
||||
// Read asmap from provided binary file
|
||||
static std::vector<bool> DecodeAsmap(fs::path path);
|
||||
|
||||
/**
|
||||
* Serialized format.
|
||||
* * format version byte (@see `Format`)
|
||||
* * lowest compatible format version byte. This is used to help old software decide
|
||||
* whether to parse the file. For example:
|
||||
* * Vexta Core version N knows how to parse up to format=3. If a new format=4 is
|
||||
* introduced in version N+1 that is compatible with format=3 and it is known that
|
||||
* version N will be able to parse it, then version N+1 will write
|
||||
* (format=4, lowest_compatible=3) in the first two bytes of the file, and so
|
||||
* version N will still try to parse it.
|
||||
* * Vexta Core version N+2 introduces a new incompatible format=5. It will write
|
||||
* (format=5, lowest_compatible=5) and so any versions that do not know how to parse
|
||||
* format=5 will not try to read the file.
|
||||
* * nKey
|
||||
* * nNew
|
||||
* * nTried
|
||||
* * number of "new" buckets XOR 2**30
|
||||
* * all new addresses (total count: nNew)
|
||||
* * all tried addresses (total count: nTried)
|
||||
* * for each new bucket:
|
||||
* * number of elements
|
||||
* * for each element: index in the serialized "all new addresses"
|
||||
* * asmap checksum
|
||||
*
|
||||
* 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
|
||||
* as incompatible. This is necessary because it did not check the version number on
|
||||
* deserialization.
|
||||
*
|
||||
* vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly;
|
||||
* they are instead reconstructed from the other information.
|
||||
*
|
||||
* This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
|
||||
* changes to the ADDRMAN_ parameters without breaking the on-disk structure.
|
||||
*
|
||||
* We don't use SERIALIZE_METHODS since the serialization and deserialization code has
|
||||
* very little in common.
|
||||
*/
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& s_) const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
// Always serialize in the latest version (FILE_FORMAT).
|
||||
|
||||
OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
|
||||
|
||||
s << static_cast<uint8_t>(FILE_FORMAT);
|
||||
|
||||
// Increment `lowest_compatible` iff a newly introduced format is incompatible with
|
||||
// the previous one.
|
||||
static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
|
||||
s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
|
||||
|
||||
s << nKey;
|
||||
s << nNew;
|
||||
s << nTried;
|
||||
|
||||
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
|
||||
s << nUBuckets;
|
||||
std::unordered_map<int, int> mapUnkIds;
|
||||
int nIds = 0;
|
||||
for (const auto& entry : mapInfo) {
|
||||
mapUnkIds[entry.first] = nIds;
|
||||
const CAddrInfo &info = entry.second;
|
||||
if (info.nRefCount) {
|
||||
assert(nIds != nNew); // this means nNew was wrong, oh ow
|
||||
s << info;
|
||||
nIds++;
|
||||
}
|
||||
}
|
||||
nIds = 0;
|
||||
for (const auto& entry : mapInfo) {
|
||||
const CAddrInfo &info = entry.second;
|
||||
if (info.fInTried) {
|
||||
assert(nIds != nTried); // this means nTried was wrong, oh ow
|
||||
s << info;
|
||||
nIds++;
|
||||
}
|
||||
}
|
||||
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
|
||||
int nSize = 0;
|
||||
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
|
||||
if (vvNew[bucket][i] != -1)
|
||||
nSize++;
|
||||
}
|
||||
s << nSize;
|
||||
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
|
||||
if (vvNew[bucket][i] != -1) {
|
||||
int nIndex = mapUnkIds[vvNew[bucket][i]];
|
||||
s << nIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Store asmap checksum after bucket entries so that it
|
||||
// can be ignored by older clients for backward compatibility.
|
||||
uint256 asmap_checksum;
|
||||
if (m_asmap.size() != 0) {
|
||||
asmap_checksum = SerializeHash(m_asmap);
|
||||
}
|
||||
s << asmap_checksum;
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s_)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
assert(vRandom.empty());
|
||||
|
||||
Format format;
|
||||
s_ >> Using<CustomUintFormatter<1>>(format);
|
||||
|
||||
int stream_version = s_.GetVersion();
|
||||
if (format >= Format::V3_BIP155) {
|
||||
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
|
||||
// unserialize methods know that an address in addrv2 format is coming.
|
||||
stream_version |= ADDRV2_FORMAT;
|
||||
}
|
||||
|
||||
OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
|
||||
|
||||
uint8_t compat;
|
||||
s >> compat;
|
||||
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
|
||||
if (lowest_compatible > FILE_FORMAT) {
|
||||
throw std::ios_base::failure(strprintf(
|
||||
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
|
||||
"but the maximum supported by this version of %s is %u.",
|
||||
format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT)));
|
||||
}
|
||||
|
||||
s >> nKey;
|
||||
s >> nNew;
|
||||
s >> nTried;
|
||||
int nUBuckets = 0;
|
||||
s >> nUBuckets;
|
||||
if (format >= Format::V1_DETERMINISTIC) {
|
||||
nUBuckets ^= (1 << 30);
|
||||
}
|
||||
|
||||
if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
|
||||
throw std::ios_base::failure(
|
||||
strprintf("Corrupt CAddrMan serialization: nNew=%d, should be in [0, %u]",
|
||||
nNew,
|
||||
ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
||||
}
|
||||
|
||||
if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
|
||||
throw std::ios_base::failure(
|
||||
strprintf("Corrupt CAddrMan serialization: nTried=%d, should be in [0, %u]",
|
||||
nTried,
|
||||
ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
||||
}
|
||||
|
||||
// Deserialize entries from the new table.
|
||||
for (int n = 0; n < nNew; n++) {
|
||||
CAddrInfo &info = mapInfo[n];
|
||||
s >> info;
|
||||
mapAddr[info] = n;
|
||||
info.nRandomPos = vRandom.size();
|
||||
vRandom.push_back(n);
|
||||
}
|
||||
nIdCount = nNew;
|
||||
|
||||
// Deserialize entries from the tried table.
|
||||
int nLost = 0;
|
||||
for (int n = 0; n < nTried; n++) {
|
||||
CAddrInfo info;
|
||||
s >> info;
|
||||
int nKBucket = info.GetTriedBucket(nKey, m_asmap);
|
||||
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
|
||||
if (vvTried[nKBucket][nKBucketPos] == -1) {
|
||||
info.nRandomPos = vRandom.size();
|
||||
info.fInTried = true;
|
||||
vRandom.push_back(nIdCount);
|
||||
mapInfo[nIdCount] = info;
|
||||
mapAddr[info] = nIdCount;
|
||||
vvTried[nKBucket][nKBucketPos] = nIdCount;
|
||||
nIdCount++;
|
||||
} else {
|
||||
nLost++;
|
||||
}
|
||||
}
|
||||
nTried -= nLost;
|
||||
|
||||
// Store positions in the new table buckets to apply later (if possible).
|
||||
// An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
|
||||
// so we store all bucket-entry_index pairs to iterate through later.
|
||||
std::vector<std::pair<int, int>> bucket_entries;
|
||||
|
||||
for (int bucket = 0; bucket < nUBuckets; ++bucket) {
|
||||
int num_entries{0};
|
||||
s >> num_entries;
|
||||
for (int n = 0; n < num_entries; ++n) {
|
||||
int entry_index{0};
|
||||
s >> entry_index;
|
||||
if (entry_index >= 0 && entry_index < nNew) {
|
||||
bucket_entries.emplace_back(bucket, entry_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the bucket count and asmap checksum haven't changed, then attempt
|
||||
// to restore the entries to the buckets/positions they were in before
|
||||
// serialization.
|
||||
uint256 supplied_asmap_checksum;
|
||||
if (m_asmap.size() != 0) {
|
||||
supplied_asmap_checksum = SerializeHash(m_asmap);
|
||||
}
|
||||
uint256 serialized_asmap_checksum;
|
||||
if (format >= Format::V2_ASMAP) {
|
||||
s >> serialized_asmap_checksum;
|
||||
}
|
||||
const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
|
||||
serialized_asmap_checksum == supplied_asmap_checksum};
|
||||
|
||||
if (!restore_bucketing) {
|
||||
LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
|
||||
}
|
||||
|
||||
for (auto bucket_entry : bucket_entries) {
|
||||
int bucket{bucket_entry.first};
|
||||
const int entry_index{bucket_entry.second};
|
||||
CAddrInfo& info = mapInfo[entry_index];
|
||||
|
||||
// The entry shouldn't appear in more than
|
||||
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
|
||||
// this bucket_entry.
|
||||
if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
|
||||
|
||||
int bucket_position = info.GetBucketPosition(nKey, true, bucket);
|
||||
if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
|
||||
// Bucketing has not changed, using existing bucket positions for the new table
|
||||
vvNew[bucket][bucket_position] = entry_index;
|
||||
++info.nRefCount;
|
||||
} else {
|
||||
// In case the new table data cannot be used (bucket count wrong or new asmap),
|
||||
// try to give them a reference based on their primary source address.
|
||||
bucket = info.GetNewBucket(nKey, m_asmap);
|
||||
bucket_position = info.GetBucketPosition(nKey, true, bucket);
|
||||
if (vvNew[bucket][bucket_position] == -1) {
|
||||
vvNew[bucket][bucket_position] = entry_index;
|
||||
++info.nRefCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prune new entries with refcount 0 (as a result of collisions).
|
||||
int nLostUnk = 0;
|
||||
for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
|
||||
if (it->second.fInTried == false && it->second.nRefCount == 0) {
|
||||
const auto itCopy = it++;
|
||||
Delete(itCopy->first);
|
||||
++nLostUnk;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (nLost + nLostUnk > 0) {
|
||||
LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
|
||||
}
|
||||
|
||||
RemoveInvalid();
|
||||
|
||||
Check();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
std::vector<int>().swap(vRandom);
|
||||
nKey = insecure_rand.rand256();
|
||||
for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
|
||||
for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
|
||||
vvNew[bucket][entry] = -1;
|
||||
}
|
||||
}
|
||||
for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) {
|
||||
for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) {
|
||||
vvTried[bucket][entry] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
nIdCount = 0;
|
||||
nTried = 0;
|
||||
nNew = 0;
|
||||
nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
|
||||
mapInfo.clear();
|
||||
mapAddr.clear();
|
||||
}
|
||||
|
||||
CAddrMan()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
~CAddrMan()
|
||||
{
|
||||
nKey.SetNull();
|
||||
}
|
||||
|
||||
//! Return the number of (unique) addresses in all tables.
|
||||
size_t size() const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
|
||||
return vRandom.size();
|
||||
}
|
||||
|
||||
//! Add a single address.
|
||||
bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
bool fRet = false;
|
||||
Check();
|
||||
fRet |= Add_(addr, source, nTimePenalty);
|
||||
Check();
|
||||
if (fRet) {
|
||||
LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
|
||||
}
|
||||
return fRet;
|
||||
}
|
||||
|
||||
//! Add multiple addresses.
|
||||
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
int nAdd = 0;
|
||||
Check();
|
||||
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
|
||||
nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
|
||||
Check();
|
||||
if (nAdd) {
|
||||
LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
|
||||
}
|
||||
return nAdd > 0;
|
||||
}
|
||||
|
||||
//! Mark an entry as accessible.
|
||||
void Good(const CService &addr, bool test_before_evict = true, int64_t nTime = GetAdjustedTime())
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Good_(addr, test_before_evict, nTime);
|
||||
Check();
|
||||
}
|
||||
|
||||
//! Mark an entry as connection attempted to.
|
||||
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Attempt_(addr, fCountFailure, nTime);
|
||||
Check();
|
||||
}
|
||||
|
||||
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
|
||||
void ResolveCollisions()
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
ResolveCollisions_();
|
||||
Check();
|
||||
}
|
||||
|
||||
//! Randomly select an address in tried that another address is attempting to evict.
|
||||
CAddrInfo SelectTriedCollision()
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
const CAddrInfo ret = SelectTriedCollision_();
|
||||
Check();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose an address to connect to.
|
||||
*/
|
||||
CAddrInfo Select(bool newOnly = false)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
const CAddrInfo addrRet = Select_(newOnly);
|
||||
Check();
|
||||
return addrRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all or many randomly selected addresses, optionally by network.
|
||||
*
|
||||
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
|
||||
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
|
||||
* @param[in] network Select only addresses of this network (nullopt = all).
|
||||
*/
|
||||
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
std::vector<CAddress> vAddr;
|
||||
GetAddr_(vAddr, max_addresses, max_pct, network);
|
||||
Check();
|
||||
return vAddr;
|
||||
}
|
||||
|
||||
//! Outer function for Connected_()
|
||||
void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
Connected_(addr, nTime);
|
||||
Check();
|
||||
}
|
||||
|
||||
void SetServices(const CService &addr, ServiceFlags nServices)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
Check();
|
||||
SetServices_(addr, nServices);
|
||||
Check();
|
||||
}
|
||||
|
||||
protected:
|
||||
//! secret key to randomize bucket select with
|
||||
uint256 nKey;
|
||||
|
||||
//! Source of random numbers for randomization in inner loops
|
||||
FastRandomContext insecure_rand;
|
||||
|
||||
private:
|
||||
//! A mutex to protect the inner data structures.
|
||||
mutable Mutex cs;
|
||||
|
||||
//! Serialization versions.
|
||||
enum Format : uint8_t {
|
||||
V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88
|
||||
V1_DETERMINISTIC = 1, //!< for pre-asmap files
|
||||
V2_ASMAP = 2, //!< for files including asmap version
|
||||
V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format
|
||||
};
|
||||
|
||||
//! The maximum format this software knows it can unserialize. Also, we always serialize
|
||||
//! in this format.
|
||||
//! The format (first byte in the serialized stream) can be higher than this and
|
||||
//! still this software may be able to unserialize the file - if the second byte
|
||||
//! (see `lowest_compatible` in `Unserialize()`) is less or equal to this.
|
||||
static constexpr Format FILE_FORMAT = Format::V3_BIP155;
|
||||
|
||||
//! The initial value of a field that is incremented every time an incompatible format
|
||||
//! change is made (such that old software versions would not be able to parse and
|
||||
//! understand the new file format). This is 32 because we overtook the "key size"
|
||||
//! field which was 32 historically.
|
||||
//! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead.
|
||||
static constexpr uint8_t INCOMPATIBILITY_BASE = 32;
|
||||
|
||||
//! last used nId
|
||||
int nIdCount GUARDED_BY(cs);
|
||||
|
||||
//! table with information about all nIds
|
||||
std::unordered_map<int, CAddrInfo> mapInfo GUARDED_BY(cs);
|
||||
|
||||
//! find an nId based on its network address
|
||||
std::unordered_map<CNetAddr, int, CNetAddrHash> mapAddr GUARDED_BY(cs);
|
||||
|
||||
//! randomly-ordered vector of all nIds
|
||||
std::vector<int> vRandom GUARDED_BY(cs);
|
||||
|
||||
// number of "tried" entries
|
||||
int nTried GUARDED_BY(cs);
|
||||
|
||||
//! list of "tried" buckets
|
||||
int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
|
||||
|
||||
//! number of (unique) "new" entries
|
||||
int nNew GUARDED_BY(cs);
|
||||
|
||||
//! list of "new" buckets
|
||||
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
|
||||
|
||||
//! last time Good was called (memory only)
|
||||
int64_t nLastGood GUARDED_BY(cs);
|
||||
|
||||
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
|
||||
std::set<int> m_tried_collisions;
|
||||
|
||||
//! Find an entry.
|
||||
CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! find an entry, creating it if necessary.
|
||||
//! nTime and nServices of the found node are updated, if necessary.
|
||||
CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Swap two elements in vRandom.
|
||||
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Move an entry from the "new" table(s) to the "tried" table
|
||||
void MakeTried(CAddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Delete an entry. It must not be in tried, and have refcount 0.
|
||||
void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Clear a position in a "new" table. This is the only place where entries are actually deleted.
|
||||
void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Mark an entry "good", possibly moving it from "new" to "tried".
|
||||
void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Add an entry to the "new" table.
|
||||
bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Mark an entry as attempted to connect.
|
||||
void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
|
||||
CAddrInfo Select_(bool newOnly) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
|
||||
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Return a random to-be-evicted tried table address.
|
||||
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Consistency check
|
||||
void Check()
|
||||
EXCLUSIVE_LOCKS_REQUIRED(cs)
|
||||
{
|
||||
#ifdef DEBUG_ADDRMAN
|
||||
AssertLockHeld(cs);
|
||||
const int err = Check_();
|
||||
if (err) {
|
||||
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ADDRMAN
|
||||
//! Perform consistency check. Returns an error code or zero.
|
||||
int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return all or many randomly selected addresses, optionally by network.
|
||||
*
|
||||
* @param[out] vAddr Vector of randomly selected addresses from vRandom.
|
||||
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
|
||||
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
|
||||
* @param[in] network Select only addresses of this network (nullopt = all).
|
||||
*/
|
||||
void GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
/** We have successfully connected to this peer. Calling this function
|
||||
* updates the CAddress's nTime, which is used in our IsTerrible()
|
||||
* decisions and gossiped to peers. Callers should be careful that updating
|
||||
* this information doesn't leak topology information to network spies.
|
||||
*
|
||||
* net_processing calls this function when it *disconnects* from a peer to
|
||||
* not leak information about currently connected peers.
|
||||
*
|
||||
* @param[in] addr The address of the peer we were connected to
|
||||
* @param[in] nTime The time that we were last connected to this peer
|
||||
*/
|
||||
void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Update an entry's service bits.
|
||||
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
//! Remove invalid addresses.
|
||||
void RemoveInvalid() EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
friend class CAddrManTest;
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_ADDRMAN_H
|
||||
29
src/amount.h
Normal file
29
src/amount.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2018 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2018 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_AMOUNT_H
|
||||
#define DIGIBYTE_AMOUNT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Amount in satoshis (Can be negative) */
|
||||
typedef int64_t CAmount;
|
||||
|
||||
static const CAmount COIN = 100000000;
|
||||
|
||||
/** No amount larger than this (in satoshi) is valid.
|
||||
*
|
||||
* Note that this constant is *not* the total money supply, which in DigiByte
|
||||
* currently happens to be less than 21,000,000 VTX for various reasons, but
|
||||
* rather a sanity check. As this sanity check is used by consensus-critical
|
||||
* validation code, the exact value of the MAX_MONEY constant is consensus
|
||||
* critical; in unusual circumstances like a(nother) overflow bug that allowed
|
||||
* for the creation of coins out of thin air modification could lead to a fork.
|
||||
* */
|
||||
static const CAmount MAX_MONEY = 21000000000 * COIN;
|
||||
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
|
||||
|
||||
#endif // DIGIBYTE_AMOUNT_H
|
||||
304
src/arith_uint256.cpp
Normal file
304
src/arith_uint256.cpp
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <arith_uint256.h>
|
||||
|
||||
#include <uint256.h>
|
||||
#include <crypto/common.h>
|
||||
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>::base_uint(const std::string& str)
|
||||
{
|
||||
static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
|
||||
|
||||
SetHex(str);
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator<<=(unsigned int shift)
|
||||
{
|
||||
base_uint<BITS> a(*this);
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = 0;
|
||||
int k = shift / 32;
|
||||
shift = shift % 32;
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
if (i + k + 1 < WIDTH && shift != 0)
|
||||
pn[i + k + 1] |= (a.pn[i] >> (32 - shift));
|
||||
if (i + k < WIDTH)
|
||||
pn[i + k] |= (a.pn[i] << shift);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator>>=(unsigned int shift)
|
||||
{
|
||||
base_uint<BITS> a(*this);
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = 0;
|
||||
int k = shift / 32;
|
||||
shift = shift % 32;
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
if (i - k - 1 >= 0 && shift != 0)
|
||||
pn[i - k - 1] |= (a.pn[i] << (32 - shift));
|
||||
if (i - k >= 0)
|
||||
pn[i - k] |= (a.pn[i] >> shift);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator*=(uint32_t b32)
|
||||
{
|
||||
uint64_t carry = 0;
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
uint64_t n = carry + (uint64_t)b32 * pn[i];
|
||||
pn[i] = n & 0xffffffff;
|
||||
carry = n >> 32;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator*=(const base_uint& b)
|
||||
{
|
||||
base_uint<BITS> a;
|
||||
for (int j = 0; j < WIDTH; j++) {
|
||||
uint64_t carry = 0;
|
||||
for (int i = 0; i + j < WIDTH; i++) {
|
||||
uint64_t n = carry + a.pn[i + j] + (uint64_t)pn[j] * b.pn[i];
|
||||
a.pn[i + j] = n & 0xffffffff;
|
||||
carry = n >> 32;
|
||||
}
|
||||
}
|
||||
*this = a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator/=(uint32_t b32)
|
||||
{
|
||||
if (b32 == 0)
|
||||
throw uint_error("Division by zero");
|
||||
uint64_t remainder = 0;
|
||||
for (int i = WIDTH-1; i >= 0; i--)
|
||||
{
|
||||
remainder <<= 32;
|
||||
remainder += pn[i];
|
||||
pn[i] = remainder / b32;
|
||||
remainder = remainder % b32;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS>& base_uint<BITS>::operator/=(const base_uint& b)
|
||||
{
|
||||
base_uint<BITS> div = b; // make a copy, so we can shift.
|
||||
base_uint<BITS> num = *this; // make a copy, so we can subtract.
|
||||
*this = 0; // the quotient.
|
||||
int num_bits = num.bits();
|
||||
int div_bits = div.bits();
|
||||
if (div_bits == 0)
|
||||
throw uint_error("Division by zero");
|
||||
if (div_bits > num_bits) // the result is certainly 0.
|
||||
return *this;
|
||||
int shift = num_bits - div_bits;
|
||||
div <<= shift; // shift so that div and num align.
|
||||
while (shift >= 0) {
|
||||
if (num >= div) {
|
||||
num -= div;
|
||||
pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result.
|
||||
}
|
||||
div >>= 1; // shift back.
|
||||
shift--;
|
||||
}
|
||||
// num now contains the remainder of the division.
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
int base_uint<BITS>::CompareTo(const base_uint<BITS>& b) const
|
||||
{
|
||||
for (int i = WIDTH - 1; i >= 0; i--) {
|
||||
if (pn[i] < b.pn[i])
|
||||
return -1;
|
||||
if (pn[i] > b.pn[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
bool base_uint<BITS>::EqualTo(uint64_t b) const
|
||||
{
|
||||
for (int i = WIDTH - 1; i >= 2; i--) {
|
||||
if (pn[i])
|
||||
return false;
|
||||
}
|
||||
if (pn[1] != (b >> 32))
|
||||
return false;
|
||||
if (pn[0] != (b & 0xfffffffful))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
double base_uint<BITS>::getdouble() const
|
||||
{
|
||||
double ret = 0.0;
|
||||
double fact = 1.0;
|
||||
for (int i = 0; i < WIDTH; i++) {
|
||||
ret += fact * pn[i];
|
||||
fact *= 4294967296.0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
std::string base_uint<BITS>::GetHex() const
|
||||
{
|
||||
return ArithToUint256(*this).GetHex();
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
void base_uint<BITS>::SetHex(const char* psz)
|
||||
{
|
||||
*this = UintToArith256(uint256S(psz));
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
void base_uint<BITS>::SetHex(const std::string& str)
|
||||
{
|
||||
SetHex(str.c_str());
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
std::string base_uint<BITS>::ToString() const
|
||||
{
|
||||
return (GetHex());
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
unsigned int base_uint<BITS>::bits() const
|
||||
{
|
||||
for (int pos = WIDTH - 1; pos >= 0; pos--) {
|
||||
if (pn[pos]) {
|
||||
for (int nbits = 31; nbits > 0; nbits--) {
|
||||
if (pn[pos] & 1U << nbits)
|
||||
return 32 * pos + nbits + 1;
|
||||
}
|
||||
return 32 * pos + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_uint<BITS> base_uint<BITS>::ApproxNthRoot(int n) const
|
||||
{
|
||||
assert(1 < n && n < 64);
|
||||
int nLength = bits();
|
||||
int nShifts = std::max(0, ((nLength-1)/n)+1-(64/n));
|
||||
|
||||
base_uint<BITS> shifted = *this >> (n * nShifts);
|
||||
uint64_t nHead = shifted.GetLow64();
|
||||
|
||||
// Just binary search the answer
|
||||
uint64_t nRoot = 0;
|
||||
for (int i = 64/n - 1; i >= 0; i--)
|
||||
{
|
||||
uint64_t nNext = nRoot | ((uint64_t)1 << i);
|
||||
uint64_t nPower = nNext;
|
||||
for (int j = 1; j < n; j++)
|
||||
nPower *= nNext;
|
||||
if (nPower <= nHead)
|
||||
nRoot = nNext;
|
||||
}
|
||||
base_uint<BITS> res(nRoot);
|
||||
res <<= nShifts;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Explicit instantiations for base_uint<256>
|
||||
template base_uint<256>::base_uint(const std::string&);
|
||||
template base_uint<256>& base_uint<256>::operator<<=(unsigned int);
|
||||
template base_uint<256>& base_uint<256>::operator>>=(unsigned int);
|
||||
template base_uint<256>& base_uint<256>::operator*=(uint32_t b32);
|
||||
template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b);
|
||||
template base_uint<256>& base_uint<256>::operator/=(uint32_t b32);
|
||||
template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b);
|
||||
template int base_uint<256>::CompareTo(const base_uint<256>&) const;
|
||||
template bool base_uint<256>::EqualTo(uint64_t) const;
|
||||
template double base_uint<256>::getdouble() const;
|
||||
template std::string base_uint<256>::GetHex() const;
|
||||
template std::string base_uint<256>::ToString() const;
|
||||
template void base_uint<256>::SetHex(const char*);
|
||||
template void base_uint<256>::SetHex(const std::string&);
|
||||
template unsigned int base_uint<256>::bits() const;
|
||||
template base_uint<256> base_uint<256>::ApproxNthRoot(int n) const;
|
||||
|
||||
// This implementation directly uses shifts instead of going
|
||||
// through an intermediate MPI representation.
|
||||
arith_uint256& arith_uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bool* pfOverflow)
|
||||
{
|
||||
int nSize = nCompact >> 24;
|
||||
uint32_t nWord = nCompact & 0x007fffff;
|
||||
if (nSize <= 3) {
|
||||
nWord >>= 8 * (3 - nSize);
|
||||
*this = nWord;
|
||||
} else {
|
||||
*this = nWord;
|
||||
*this <<= 8 * (nSize - 3);
|
||||
}
|
||||
if (pfNegative)
|
||||
*pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0;
|
||||
if (pfOverflow)
|
||||
*pfOverflow = nWord != 0 && ((nSize > 34) ||
|
||||
(nWord > 0xff && nSize > 33) ||
|
||||
(nWord > 0xffff && nSize > 32));
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32_t arith_uint256::GetCompact(bool fNegative) const
|
||||
{
|
||||
int nSize = (bits() + 7) / 8;
|
||||
uint32_t nCompact = 0;
|
||||
if (nSize <= 3) {
|
||||
nCompact = GetLow64() << 8 * (3 - nSize);
|
||||
} else {
|
||||
arith_uint256 bn = *this >> 8 * (nSize - 3);
|
||||
nCompact = bn.GetLow64();
|
||||
}
|
||||
// The 0x00800000 bit denotes the sign.
|
||||
// Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
|
||||
if (nCompact & 0x00800000) {
|
||||
nCompact >>= 8;
|
||||
nSize++;
|
||||
}
|
||||
assert((nCompact & ~0x007fffff) == 0);
|
||||
assert(nSize < 256);
|
||||
nCompact |= nSize << 24;
|
||||
nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0);
|
||||
return nCompact;
|
||||
}
|
||||
|
||||
uint256 ArithToUint256(const arith_uint256 &a)
|
||||
{
|
||||
uint256 b;
|
||||
for(int x=0; x<a.WIDTH; ++x)
|
||||
WriteLE32(b.begin() + x*4, a.pn[x]);
|
||||
return b;
|
||||
}
|
||||
arith_uint256 UintToArith256(const uint256 &a)
|
||||
{
|
||||
arith_uint256 b;
|
||||
for(int x=0; x<b.WIDTH; ++x)
|
||||
b.pn[x] = ReadLE32(a.begin() + x*4);
|
||||
return b;
|
||||
}
|
||||
292
src/arith_uint256.h
Normal file
292
src/arith_uint256.h
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ARITH_UINT256_H
|
||||
#define DIGIBYTE_ARITH_UINT256_H
|
||||
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
class uint256;
|
||||
|
||||
class uint_error : public std::runtime_error {
|
||||
public:
|
||||
explicit uint_error(const std::string& str) : std::runtime_error(str) {}
|
||||
};
|
||||
|
||||
/** Template base class for unsigned big integers. */
|
||||
template<unsigned int BITS>
|
||||
class base_uint
|
||||
{
|
||||
protected:
|
||||
static constexpr int WIDTH = BITS / 32;
|
||||
uint32_t pn[WIDTH];
|
||||
public:
|
||||
|
||||
base_uint()
|
||||
{
|
||||
static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
|
||||
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = 0;
|
||||
}
|
||||
|
||||
base_uint(const base_uint& b)
|
||||
{
|
||||
static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
|
||||
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = b.pn[i];
|
||||
}
|
||||
|
||||
base_uint& operator=(const base_uint& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = b.pn[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint(uint64_t b)
|
||||
{
|
||||
static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
|
||||
|
||||
pn[0] = (unsigned int)b;
|
||||
pn[1] = (unsigned int)(b >> 32);
|
||||
for (int i = 2; i < WIDTH; i++)
|
||||
pn[i] = 0;
|
||||
}
|
||||
|
||||
explicit base_uint(const std::string& str);
|
||||
|
||||
const base_uint operator~() const
|
||||
{
|
||||
base_uint ret;
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
ret.pn[i] = ~pn[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
const base_uint operator-() const
|
||||
{
|
||||
base_uint ret;
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
ret.pn[i] = ~pn[i];
|
||||
++ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
double getdouble() const;
|
||||
|
||||
base_uint& operator=(uint64_t b)
|
||||
{
|
||||
pn[0] = (unsigned int)b;
|
||||
pn[1] = (unsigned int)(b >> 32);
|
||||
for (int i = 2; i < WIDTH; i++)
|
||||
pn[i] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator^=(const base_uint& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] ^= b.pn[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator&=(const base_uint& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] &= b.pn[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator|=(const base_uint& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] |= b.pn[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator^=(uint64_t b)
|
||||
{
|
||||
pn[0] ^= (unsigned int)b;
|
||||
pn[1] ^= (unsigned int)(b >> 32);
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator|=(uint64_t b)
|
||||
{
|
||||
pn[0] |= (unsigned int)b;
|
||||
pn[1] |= (unsigned int)(b >> 32);
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator<<=(unsigned int shift);
|
||||
base_uint& operator>>=(unsigned int shift);
|
||||
|
||||
base_uint& operator+=(const base_uint& b)
|
||||
{
|
||||
uint64_t carry = 0;
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
{
|
||||
uint64_t n = carry + pn[i] + b.pn[i];
|
||||
pn[i] = n & 0xffffffff;
|
||||
carry = n >> 32;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator-=(const base_uint& b)
|
||||
{
|
||||
*this += -b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator+=(uint64_t b64)
|
||||
{
|
||||
base_uint b;
|
||||
b = b64;
|
||||
*this += b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator-=(uint64_t b64)
|
||||
{
|
||||
base_uint b;
|
||||
b = b64;
|
||||
*this += -b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint& operator*=(uint32_t b32);
|
||||
base_uint& operator*=(const base_uint& b);
|
||||
base_uint& operator/=(uint32_t b32);
|
||||
base_uint& operator/=(const base_uint& b);
|
||||
|
||||
base_uint& operator++()
|
||||
{
|
||||
// prefix operator
|
||||
int i = 0;
|
||||
while (i < WIDTH && ++pn[i] == 0)
|
||||
i++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const base_uint operator++(int)
|
||||
{
|
||||
// postfix operator
|
||||
const base_uint ret = *this;
|
||||
++(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
base_uint& operator--()
|
||||
{
|
||||
// prefix operator
|
||||
int i = 0;
|
||||
while (i < WIDTH && --pn[i] == std::numeric_limits<uint32_t>::max())
|
||||
i++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const base_uint operator--(int)
|
||||
{
|
||||
// postfix operator
|
||||
const base_uint ret = *this;
|
||||
--(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CompareTo(const base_uint& b) const;
|
||||
bool EqualTo(uint64_t b) const;
|
||||
|
||||
friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; }
|
||||
friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; }
|
||||
friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; }
|
||||
friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; }
|
||||
friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; }
|
||||
friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; }
|
||||
friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; }
|
||||
friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; }
|
||||
friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; }
|
||||
friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; }
|
||||
friend inline const base_uint operator/(const base_uint& a, uint32_t b) { return base_uint(a) /= b; }
|
||||
friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; }
|
||||
friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; }
|
||||
friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; }
|
||||
friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; }
|
||||
friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; }
|
||||
friend inline bool operator<=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) <= 0; }
|
||||
friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); }
|
||||
friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); }
|
||||
|
||||
std::string GetHex() const;
|
||||
void SetHex(const char* psz);
|
||||
void SetHex(const std::string& str);
|
||||
std::string ToString() const;
|
||||
|
||||
unsigned int size() const
|
||||
{
|
||||
return sizeof(pn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the highest bit set plus one, or zero if the
|
||||
* value is zero.
|
||||
*/
|
||||
unsigned int bits() const;
|
||||
|
||||
base_uint ApproxNthRoot(int n) const;
|
||||
|
||||
uint64_t GetLow64() const
|
||||
{
|
||||
static_assert(WIDTH >= 2, "Assertion WIDTH >= 2 failed (WIDTH = BITS / 32). BITS is a template parameter.");
|
||||
return pn[0] | (uint64_t)pn[1] << 32;
|
||||
}
|
||||
};
|
||||
|
||||
/** 256-bit unsigned big integer. */
|
||||
class arith_uint256 : public base_uint<256> {
|
||||
public:
|
||||
arith_uint256() {}
|
||||
arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {}
|
||||
arith_uint256(uint64_t b) : base_uint<256>(b) {}
|
||||
explicit arith_uint256(const std::string& str) : base_uint<256>(str) {}
|
||||
|
||||
/**
|
||||
* The "compact" format is a representation of a whole
|
||||
* number N using an unsigned 32bit number similar to a
|
||||
* floating point format.
|
||||
* The most significant 8 bits are the unsigned exponent of base 256.
|
||||
* This exponent can be thought of as "number of bytes of N".
|
||||
* The lower 23 bits are the mantissa.
|
||||
* Bit number 24 (0x800000) represents the sign of N.
|
||||
* N = (-1^sign) * mantissa * 256^(exponent-3)
|
||||
*
|
||||
* Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn().
|
||||
* MPI uses the most significant bit of the first byte as sign.
|
||||
* Thus 0x1234560000 is compact (0x05123456)
|
||||
* and 0xc0de000000 is compact (0x0600c0de)
|
||||
*
|
||||
* DigiByte only uses this "compact" format for encoding difficulty
|
||||
* targets, which are unsigned 256bit quantities. Thus, all the
|
||||
* complexities of the sign bit and using base 256 are probably an
|
||||
* implementation accident.
|
||||
*/
|
||||
arith_uint256& SetCompact(uint32_t nCompact, bool *pfNegative = nullptr, bool *pfOverflow = nullptr);
|
||||
uint32_t GetCompact(bool fNegative = false) const;
|
||||
|
||||
friend uint256 ArithToUint256(const arith_uint256 &);
|
||||
friend arith_uint256 UintToArith256(const uint256 &);
|
||||
};
|
||||
|
||||
uint256 ArithToUint256(const arith_uint256 &);
|
||||
arith_uint256 UintToArith256(const uint256 &);
|
||||
|
||||
#endif // DIGIBYTE_ARITH_UINT256_H
|
||||
19
src/attributes.h
Normal file
19
src/attributes.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ATTRIBUTES_H
|
||||
#define DIGIBYTE_ATTRIBUTES_H
|
||||
|
||||
#if defined(__clang__)
|
||||
# if __has_attribute(lifetimebound)
|
||||
# define LIFETIMEBOUND [[clang::lifetimebound]]
|
||||
# else
|
||||
# define LIFETIMEBOUND
|
||||
# endif
|
||||
#else
|
||||
# define LIFETIMEBOUND
|
||||
#endif
|
||||
|
||||
#endif // DIGIBYTE_ATTRIBUTES_H
|
||||
203
src/banman.cpp
Normal file
203
src/banman.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <banman.h>
|
||||
|
||||
#include <netaddress.h>
|
||||
#include <node/ui_interface.h>
|
||||
#include <util/system.h>
|
||||
#include <util/time.h>
|
||||
#include <util/translation.h>
|
||||
|
||||
|
||||
BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
|
||||
: m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
|
||||
{
|
||||
if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated);
|
||||
|
||||
int64_t n_start = GetTimeMillis();
|
||||
if (m_ban_db.Read(m_banned, m_is_dirty)) {
|
||||
SweepBanned(); // sweep out unused entries
|
||||
|
||||
LogPrint(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(),
|
||||
GetTimeMillis() - n_start);
|
||||
} else {
|
||||
LogPrintf("Recreating the banlist database\n");
|
||||
m_banned = {};
|
||||
m_is_dirty = true;
|
||||
}
|
||||
|
||||
DumpBanlist();
|
||||
}
|
||||
|
||||
BanMan::~BanMan()
|
||||
{
|
||||
DumpBanlist();
|
||||
}
|
||||
|
||||
void BanMan::DumpBanlist()
|
||||
{
|
||||
SweepBanned(); // clean unused entries (if bantime has expired)
|
||||
|
||||
if (!BannedSetIsDirty()) return;
|
||||
|
||||
int64_t n_start = GetTimeMillis();
|
||||
|
||||
banmap_t banmap;
|
||||
GetBanned(banmap);
|
||||
if (m_ban_db.Write(banmap)) {
|
||||
SetBannedSetDirty(false);
|
||||
}
|
||||
|
||||
LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(),
|
||||
GetTimeMillis() - n_start);
|
||||
}
|
||||
|
||||
void BanMan::ClearBanned()
|
||||
{
|
||||
{
|
||||
LOCK(m_cs_banned);
|
||||
m_banned.clear();
|
||||
m_is_dirty = true;
|
||||
}
|
||||
DumpBanlist(); //store banlist to disk
|
||||
if (m_client_interface) m_client_interface->BannedListChanged();
|
||||
}
|
||||
|
||||
bool BanMan::IsDiscouraged(const CNetAddr& net_addr)
|
||||
{
|
||||
LOCK(m_cs_banned);
|
||||
return m_discouraged.contains(net_addr.GetAddrBytes());
|
||||
}
|
||||
|
||||
bool BanMan::IsBanned(const CNetAddr& net_addr)
|
||||
{
|
||||
auto current_time = GetTime();
|
||||
LOCK(m_cs_banned);
|
||||
for (const auto& it : m_banned) {
|
||||
CSubNet sub_net = it.first;
|
||||
CBanEntry ban_entry = it.second;
|
||||
|
||||
if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BanMan::IsBanned(const CSubNet& sub_net)
|
||||
{
|
||||
auto current_time = GetTime();
|
||||
LOCK(m_cs_banned);
|
||||
banmap_t::iterator i = m_banned.find(sub_net);
|
||||
if (i != m_banned.end()) {
|
||||
CBanEntry ban_entry = (*i).second;
|
||||
if (current_time < ban_entry.nBanUntil) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BanMan::Ban(const CNetAddr& net_addr, int64_t ban_time_offset, bool since_unix_epoch)
|
||||
{
|
||||
CSubNet sub_net(net_addr);
|
||||
Ban(sub_net, ban_time_offset, since_unix_epoch);
|
||||
}
|
||||
|
||||
void BanMan::Discourage(const CNetAddr& net_addr)
|
||||
{
|
||||
LOCK(m_cs_banned);
|
||||
m_discouraged.insert(net_addr.GetAddrBytes());
|
||||
}
|
||||
|
||||
void BanMan::Ban(const CSubNet& sub_net, int64_t ban_time_offset, bool since_unix_epoch)
|
||||
{
|
||||
CBanEntry ban_entry(GetTime());
|
||||
|
||||
int64_t normalized_ban_time_offset = ban_time_offset;
|
||||
bool normalized_since_unix_epoch = since_unix_epoch;
|
||||
if (ban_time_offset <= 0) {
|
||||
normalized_ban_time_offset = m_default_ban_time;
|
||||
normalized_since_unix_epoch = false;
|
||||
}
|
||||
ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;
|
||||
|
||||
{
|
||||
LOCK(m_cs_banned);
|
||||
if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
|
||||
m_banned[sub_net] = ban_entry;
|
||||
m_is_dirty = true;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
if (m_client_interface) m_client_interface->BannedListChanged();
|
||||
|
||||
//store banlist to disk immediately
|
||||
DumpBanlist();
|
||||
}
|
||||
|
||||
bool BanMan::Unban(const CNetAddr& net_addr)
|
||||
{
|
||||
CSubNet sub_net(net_addr);
|
||||
return Unban(sub_net);
|
||||
}
|
||||
|
||||
bool BanMan::Unban(const CSubNet& sub_net)
|
||||
{
|
||||
{
|
||||
LOCK(m_cs_banned);
|
||||
if (m_banned.erase(sub_net) == 0) return false;
|
||||
m_is_dirty = true;
|
||||
}
|
||||
if (m_client_interface) m_client_interface->BannedListChanged();
|
||||
DumpBanlist(); //store banlist to disk immediately
|
||||
return true;
|
||||
}
|
||||
|
||||
void BanMan::GetBanned(banmap_t& banmap)
|
||||
{
|
||||
LOCK(m_cs_banned);
|
||||
// Sweep the banlist so expired bans are not returned
|
||||
SweepBanned();
|
||||
banmap = m_banned; //create a thread safe copy
|
||||
}
|
||||
|
||||
void BanMan::SweepBanned()
|
||||
{
|
||||
int64_t now = GetTime();
|
||||
bool notify_ui = false;
|
||||
{
|
||||
LOCK(m_cs_banned);
|
||||
banmap_t::iterator it = m_banned.begin();
|
||||
while (it != m_banned.end()) {
|
||||
CSubNet sub_net = (*it).first;
|
||||
CBanEntry ban_entry = (*it).second;
|
||||
if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {
|
||||
m_banned.erase(it++);
|
||||
m_is_dirty = true;
|
||||
notify_ui = true;
|
||||
LogPrint(BCLog::NET, "Removed banned node address/subnet: %s\n", sub_net.ToString());
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// update UI
|
||||
if (notify_ui && m_client_interface) {
|
||||
m_client_interface->BannedListChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool BanMan::BannedSetIsDirty()
|
||||
{
|
||||
LOCK(m_cs_banned);
|
||||
return m_is_dirty;
|
||||
}
|
||||
|
||||
void BanMan::SetBannedSetDirty(bool dirty)
|
||||
{
|
||||
LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
|
||||
m_is_dirty = dirty;
|
||||
}
|
||||
98
src/banman.h
Normal file
98
src/banman.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef DIGIBYTE_BANMAN_H
|
||||
#define DIGIBYTE_BANMAN_H
|
||||
|
||||
#include <addrdb.h>
|
||||
#include <bloom.h>
|
||||
#include <fs.h>
|
||||
#include <net_types.h> // For banmap_t
|
||||
#include <sync.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
|
||||
static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
|
||||
|
||||
/// How often to dump banned addresses/subnets to disk.
|
||||
static constexpr std::chrono::minutes DUMP_BANS_INTERVAL{15};
|
||||
|
||||
class CClientUIInterface;
|
||||
class CNetAddr;
|
||||
class CSubNet;
|
||||
|
||||
// Banman manages two related but distinct concepts:
|
||||
//
|
||||
// 1. Banning. This is configured manually by the user, through the setban RPC.
|
||||
// If an address or subnet is banned, we never accept incoming connections from
|
||||
// it and never create outgoing connections to it. We won't gossip its address
|
||||
// to other peers in addr messages. Banned addresses and subnets are stored to
|
||||
// disk on shutdown and reloaded on startup. Banning can be used to
|
||||
// prevent connections with spy nodes or other griefers.
|
||||
//
|
||||
// 2. Discouragement. If a peer misbehaves enough (see Misbehaving() in
|
||||
// net_processing.cpp), we'll mark that address as discouraged. We still allow
|
||||
// incoming connections from them, but they're preferred for eviction when
|
||||
// we receive new incoming connections. We never make outgoing connections to
|
||||
// them, and do not gossip their address to other peers. This is implemented as
|
||||
// a bloom filter. We can (probabilistically) test for membership, but can't
|
||||
// list all discouraged addresses or unmark them as discouraged. Discouragement
|
||||
// can prevent our limited connection slots being used up by incompatible
|
||||
// or broken peers.
|
||||
//
|
||||
// Neither banning nor discouragement are protections against denial-of-service
|
||||
// attacks, since if an attacker has a way to waste our resources and we
|
||||
// disconnect from them and ban that address, it's trivial for them to
|
||||
// reconnect from another IP address.
|
||||
//
|
||||
// Attempting to automatically disconnect or ban any class of peer carries the
|
||||
// risk of splitting the network. For example, if we banned/disconnected for a
|
||||
// transaction that fails a policy check and a future version changes the
|
||||
// policy check so the transaction is accepted, then that transaction could
|
||||
// cause the network to split between old nodes and new nodes.
|
||||
|
||||
class BanMan
|
||||
{
|
||||
public:
|
||||
~BanMan();
|
||||
BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time);
|
||||
void Ban(const CNetAddr& net_addr, int64_t ban_time_offset = 0, bool since_unix_epoch = false);
|
||||
void Ban(const CSubNet& sub_net, int64_t ban_time_offset = 0, bool since_unix_epoch = false);
|
||||
void Discourage(const CNetAddr& net_addr);
|
||||
void ClearBanned();
|
||||
|
||||
//! Return whether net_addr is banned
|
||||
bool IsBanned(const CNetAddr& net_addr);
|
||||
|
||||
//! Return whether sub_net is exactly banned
|
||||
bool IsBanned(const CSubNet& sub_net);
|
||||
|
||||
//! Return whether net_addr is discouraged.
|
||||
bool IsDiscouraged(const CNetAddr& net_addr);
|
||||
|
||||
bool Unban(const CNetAddr& net_addr);
|
||||
bool Unban(const CSubNet& sub_net);
|
||||
void GetBanned(banmap_t& banmap);
|
||||
void DumpBanlist();
|
||||
|
||||
private:
|
||||
bool BannedSetIsDirty();
|
||||
//!set the "dirty" flag for the banlist
|
||||
void SetBannedSetDirty(bool dirty = true);
|
||||
//!clean unused entries (if bantime has expired)
|
||||
void SweepBanned();
|
||||
|
||||
RecursiveMutex m_cs_banned;
|
||||
banmap_t m_banned GUARDED_BY(m_cs_banned);
|
||||
bool m_is_dirty GUARDED_BY(m_cs_banned);
|
||||
CClientUIInterface* m_client_interface = nullptr;
|
||||
CBanDB m_ban_db;
|
||||
const int64_t m_default_ban_time;
|
||||
CRollingBloomFilter m_discouraged GUARDED_BY(m_cs_banned) {50000, 0.000001};
|
||||
};
|
||||
|
||||
#endif
|
||||
168
src/base58.cpp
Normal file
168
src/base58.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright (c) 2014-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <base58.h>
|
||||
|
||||
#include <hash.h>
|
||||
#include <uint256.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
/** All alphanumeric characters except for "0", "I", "O", and "l" */
|
||||
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
static const int8_t mapBase58[256] = {
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
|
||||
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
|
||||
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
|
||||
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
|
||||
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
};
|
||||
|
||||
[[nodiscard]] static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len)
|
||||
{
|
||||
// Skip leading spaces.
|
||||
while (*psz && IsSpace(*psz))
|
||||
psz++;
|
||||
// Skip and count leading '1's.
|
||||
int zeroes = 0;
|
||||
int length = 0;
|
||||
while (*psz == '1') {
|
||||
zeroes++;
|
||||
if (zeroes > max_ret_len) return false;
|
||||
psz++;
|
||||
}
|
||||
// Allocate enough space in big-endian base256 representation.
|
||||
int size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up.
|
||||
std::vector<unsigned char> b256(size);
|
||||
// Process the characters.
|
||||
static_assert(std::size(mapBase58) == 256, "mapBase58.size() should be 256"); // guarantee not out of range
|
||||
while (*psz && !IsSpace(*psz)) {
|
||||
// Decode base58 character
|
||||
int carry = mapBase58[(uint8_t)*psz];
|
||||
if (carry == -1) // Invalid b58 character
|
||||
return false;
|
||||
int i = 0;
|
||||
for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
|
||||
carry += 58 * (*it);
|
||||
*it = carry % 256;
|
||||
carry /= 256;
|
||||
}
|
||||
assert(carry == 0);
|
||||
length = i;
|
||||
if (length + zeroes > max_ret_len) return false;
|
||||
psz++;
|
||||
}
|
||||
// Skip trailing spaces.
|
||||
while (IsSpace(*psz))
|
||||
psz++;
|
||||
if (*psz != 0)
|
||||
return false;
|
||||
// Skip leading zeroes in b256.
|
||||
std::vector<unsigned char>::iterator it = b256.begin() + (size - length);
|
||||
// Copy result into output vector.
|
||||
vch.reserve(zeroes + (b256.end() - it));
|
||||
vch.assign(zeroes, 0x00);
|
||||
while (it != b256.end())
|
||||
vch.push_back(*(it++));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string EncodeBase58(Span<const unsigned char> input)
|
||||
{
|
||||
// Skip & count leading zeroes.
|
||||
int zeroes = 0;
|
||||
int length = 0;
|
||||
while (input.size() > 0 && input[0] == 0) {
|
||||
input = input.subspan(1);
|
||||
zeroes++;
|
||||
}
|
||||
// Allocate enough space in big-endian base58 representation.
|
||||
int size = input.size() * 138 / 100 + 1; // log(256) / log(58), rounded up.
|
||||
std::vector<unsigned char> b58(size);
|
||||
// Process the bytes.
|
||||
while (input.size() > 0) {
|
||||
int carry = input[0];
|
||||
int i = 0;
|
||||
// Apply "b58 = b58 * 256 + ch".
|
||||
for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) {
|
||||
carry += 256 * (*it);
|
||||
*it = carry % 58;
|
||||
carry /= 58;
|
||||
}
|
||||
|
||||
assert(carry == 0);
|
||||
length = i;
|
||||
input = input.subspan(1);
|
||||
}
|
||||
// Skip leading zeroes in base58 result.
|
||||
std::vector<unsigned char>::iterator it = b58.begin() + (size - length);
|
||||
while (it != b58.end() && *it == 0)
|
||||
it++;
|
||||
// Translate the result into a string.
|
||||
std::string str;
|
||||
str.reserve(zeroes + (b58.end() - it));
|
||||
str.assign(zeroes, '1');
|
||||
while (it != b58.end())
|
||||
str += pszBase58[*(it++)];
|
||||
return str;
|
||||
}
|
||||
|
||||
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len)
|
||||
{
|
||||
if (!ValidAsCString(str)) {
|
||||
return false;
|
||||
}
|
||||
return DecodeBase58(str.c_str(), vchRet, max_ret_len);
|
||||
}
|
||||
|
||||
std::string EncodeBase58Check(Span<const unsigned char> input)
|
||||
{
|
||||
// add 4-byte hash check to the end
|
||||
std::vector<unsigned char> vch(input.begin(), input.end());
|
||||
uint256 hash = Hash(vch);
|
||||
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
|
||||
return EncodeBase58(vch);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len)
|
||||
{
|
||||
if (!DecodeBase58(psz, vchRet, max_ret_len > std::numeric_limits<int>::max() - 4 ? std::numeric_limits<int>::max() : max_ret_len + 4) ||
|
||||
(vchRet.size() < 4)) {
|
||||
vchRet.clear();
|
||||
return false;
|
||||
}
|
||||
// re-calculate the checksum, ensure it matches the included 4-byte checksum
|
||||
uint256 hash = Hash(MakeSpan(vchRet).first(vchRet.size() - 4));
|
||||
if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {
|
||||
vchRet.clear();
|
||||
return false;
|
||||
}
|
||||
vchRet.resize(vchRet.size() - 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret)
|
||||
{
|
||||
if (!ValidAsCString(str)) {
|
||||
return false;
|
||||
}
|
||||
return DecodeBase58Check(str.c_str(), vchRet, max_ret);
|
||||
}
|
||||
46
src/base58.h
Normal file
46
src/base58.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
/**
|
||||
* Why base-58 instead of standard base-64 encoding?
|
||||
* - Don't want 0OIl characters that look the same in some fonts and
|
||||
* could be used to create visually identical looking data.
|
||||
* - A string with non-alphanumeric characters is not as easily accepted as input.
|
||||
* - E-mail usually won't line-break if there's no punctuation to break at.
|
||||
* - Double-clicking selects the whole string as one word if it's all alphanumeric.
|
||||
*/
|
||||
#ifndef DIGIBYTE_BASE58_H
|
||||
#define DIGIBYTE_BASE58_H
|
||||
|
||||
#include <attributes.h>
|
||||
#include <span.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Encode a byte span as a base58-encoded string
|
||||
*/
|
||||
std::string EncodeBase58(Span<const unsigned char> input);
|
||||
|
||||
/**
|
||||
* Decode a base58-encoded string (str) into a byte vector (vchRet).
|
||||
* return true if decoding is successful.
|
||||
*/
|
||||
[[nodiscard]] bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len);
|
||||
|
||||
/**
|
||||
* Encode a byte span into a base58-encoded string, including checksum
|
||||
*/
|
||||
std::string EncodeBase58Check(Span<const unsigned char> input);
|
||||
|
||||
/**
|
||||
* Decode a base58-encoded string (str) that includes a checksum into a byte
|
||||
* vector (vchRet), return true if decoding is successful
|
||||
*/
|
||||
[[nodiscard]] bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len);
|
||||
|
||||
#endif // DIGIBYTE_BASE58_H
|
||||
200
src/bech32.cpp
Normal file
200
src/bech32.cpp
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
// Copyright (c) 2017, 2021 Pieter Wuille
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bech32.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace bech32
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
typedef std::vector<uint8_t> data;
|
||||
|
||||
/** The Bech32 and Bech32m character set for encoding. */
|
||||
const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||
|
||||
/** The Bech32 and Bech32m character set for decoding. */
|
||||
const int8_t CHARSET_REV[128] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
|
||||
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
||||
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
|
||||
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
||||
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
/* Determine the final constant to use for the specified encoding. */
|
||||
uint32_t EncodingConstant(Encoding encoding) {
|
||||
assert(encoding == Encoding::BECH32 || encoding == Encoding::BECH32M);
|
||||
return encoding == Encoding::BECH32 ? 1 : 0x2bc830a3;
|
||||
}
|
||||
|
||||
/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
|
||||
* make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
|
||||
* bits correspond to earlier values. */
|
||||
uint32_t PolyMod(const data& v)
|
||||
{
|
||||
// The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an
|
||||
// implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) =
|
||||
// 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that
|
||||
// [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...].
|
||||
|
||||
// The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of
|
||||
// v(x) mod g(x), where g(x) is the Bech32 generator,
|
||||
// x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way
|
||||
// that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a
|
||||
// window of 1023 characters. Among the various possible BCH codes, one was selected to in
|
||||
// fact guarantee detection of up to 4 errors within a window of 89 characters.
|
||||
|
||||
// Note that the coefficients are elements of GF(32), here represented as decimal numbers
|
||||
// between {}. In this finite field, addition is just XOR of the corresponding numbers. For
|
||||
// example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires
|
||||
// treating the bits of values themselves as coefficients of a polynomial over a smaller field,
|
||||
// GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} =
|
||||
// (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a
|
||||
// = a^3 + 1 (mod a^5 + a^3 + 1) = {9}.
|
||||
|
||||
// During the course of the loop below, `c` contains the bitpacked coefficients of the
|
||||
// polynomial constructed from just the values of v that were processed so far, mod g(x). In
|
||||
// the above example, `c` initially corresponds to 1 mod g(x), and after processing 2 inputs of
|
||||
// v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value
|
||||
// for `c`.
|
||||
uint32_t c = 1;
|
||||
for (const auto v_i : v) {
|
||||
// We want to update `c` to correspond to a polynomial with one extra term. If the initial
|
||||
// value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to
|
||||
// correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to
|
||||
// process. Simplifying:
|
||||
// c'(x) = (f(x) * x + v_i) mod g(x)
|
||||
// ((f(x) mod g(x)) * x + v_i) mod g(x)
|
||||
// (c(x) * x + v_i) mod g(x)
|
||||
// If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute
|
||||
// c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x)
|
||||
// = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x)
|
||||
// = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i
|
||||
// If we call (x^6 mod g(x)) = k(x), this can be written as
|
||||
// c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x)
|
||||
|
||||
// First, determine the value of c0:
|
||||
uint8_t c0 = c >> 25;
|
||||
|
||||
// Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i:
|
||||
c = ((c & 0x1ffffff) << 5) ^ v_i;
|
||||
|
||||
// Finally, for each set bit n in c0, conditionally add {2^n}k(x):
|
||||
if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}
|
||||
if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13}
|
||||
if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26}
|
||||
if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29}
|
||||
if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/** Convert to lower case. */
|
||||
inline unsigned char LowerCase(unsigned char c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
|
||||
}
|
||||
|
||||
/** Expand a HRP for use in checksum computation. */
|
||||
data ExpandHRP(const std::string& hrp)
|
||||
{
|
||||
data ret;
|
||||
ret.reserve(hrp.size() + 90);
|
||||
ret.resize(hrp.size() * 2 + 1);
|
||||
for (size_t i = 0; i < hrp.size(); ++i) {
|
||||
unsigned char c = hrp[i];
|
||||
ret[i] = c >> 5;
|
||||
ret[i + hrp.size() + 1] = c & 0x1f;
|
||||
}
|
||||
ret[hrp.size()] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Verify a checksum. */
|
||||
Encoding VerifyChecksum(const std::string& hrp, const data& values)
|
||||
{
|
||||
// PolyMod computes what value to xor into the final values to make the checksum 0. However,
|
||||
// if we required that the checksum was 0, it would be the case that appending a 0 to a valid
|
||||
// list of values would result in a new valid list. For that reason, Bech32 requires the
|
||||
// resulting checksum to be 1 instead. In Bech32m, this constant was amended.
|
||||
const uint32_t check = PolyMod(Cat(ExpandHRP(hrp), values));
|
||||
if (check == EncodingConstant(Encoding::BECH32)) return Encoding::BECH32;
|
||||
if (check == EncodingConstant(Encoding::BECH32M)) return Encoding::BECH32M;
|
||||
return Encoding::INVALID;
|
||||
}
|
||||
|
||||
/** Create a checksum. */
|
||||
data CreateChecksum(Encoding encoding, const std::string& hrp, const data& values)
|
||||
{
|
||||
data enc = Cat(ExpandHRP(hrp), values);
|
||||
enc.resize(enc.size() + 6); // Append 6 zeroes
|
||||
uint32_t mod = PolyMod(enc) ^ EncodingConstant(encoding); // Determine what to XOR into those 6 zeroes.
|
||||
data ret(6);
|
||||
for (size_t i = 0; i < 6; ++i) {
|
||||
// Convert the 5-bit groups in mod to checksum values.
|
||||
ret[i] = (mod >> (5 * (5 - i))) & 31;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/** Encode a Bech32 or Bech32m string. */
|
||||
std::string Encode(Encoding encoding, const std::string& hrp, const data& values) {
|
||||
// First ensure that the HRP is all lowercase. BIP-173 and BIP350 require an encoder
|
||||
// to return a lowercase Bech32/Bech32m string, but if given an uppercase HRP, the
|
||||
// result will always be invalid.
|
||||
for (const char& c : hrp) assert(c < 'A' || c > 'Z');
|
||||
data checksum = CreateChecksum(encoding, hrp, values);
|
||||
data combined = Cat(values, checksum);
|
||||
std::string ret = hrp + '1';
|
||||
ret.reserve(ret.size() + combined.size());
|
||||
for (const auto c : combined) {
|
||||
ret += CHARSET[c];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Decode a Bech32 or Bech32m string. */
|
||||
DecodeResult Decode(const std::string& str) {
|
||||
bool lower = false, upper = false;
|
||||
for (size_t i = 0; i < str.size(); ++i) {
|
||||
unsigned char c = str[i];
|
||||
if (c >= 'a' && c <= 'z') lower = true;
|
||||
else if (c >= 'A' && c <= 'Z') upper = true;
|
||||
else if (c < 33 || c > 126) return {};
|
||||
}
|
||||
if (lower && upper) return {};
|
||||
size_t pos = str.rfind('1');
|
||||
if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
|
||||
return {};
|
||||
}
|
||||
data values(str.size() - 1 - pos);
|
||||
for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
|
||||
unsigned char c = str[i + pos + 1];
|
||||
int8_t rev = CHARSET_REV[c];
|
||||
|
||||
if (rev == -1) {
|
||||
return {};
|
||||
}
|
||||
values[i] = rev;
|
||||
}
|
||||
std::string hrp;
|
||||
for (size_t i = 0; i < pos; ++i) {
|
||||
hrp += LowerCase(str[i]);
|
||||
}
|
||||
Encoding result = VerifyChecksum(hrp, values);
|
||||
if (result == Encoding::INVALID) return {};
|
||||
return {result, std::move(hrp), data(values.begin(), values.end() - 6)};
|
||||
}
|
||||
|
||||
} // namespace bech32
|
||||
49
src/bech32.h
Normal file
49
src/bech32.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) 2017, 2021 Pieter Wuille
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
// Bech32 and Bech32m are string encoding formats used in newer
|
||||
// address types. The outputs consist of a human-readable part
|
||||
// (alphanumeric), a separator character (1), and a base32 data
|
||||
// section, the last 6 characters of which are a checksum. The
|
||||
// module is namespaced under bech32 for historical reasons.
|
||||
//
|
||||
// For more information, see BIP 173 and BIP 350.
|
||||
|
||||
#ifndef DIGIBYTE_BECH32_H
|
||||
#define DIGIBYTE_BECH32_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace bech32
|
||||
{
|
||||
|
||||
enum class Encoding {
|
||||
INVALID, //!< Failed decoding
|
||||
|
||||
BECH32, //!< Bech32 encoding as defined in BIP173
|
||||
BECH32M, //!< Bech32m encoding as defined in BIP350
|
||||
};
|
||||
|
||||
/** Encode a Bech32 or Bech32m string. If hrp contains uppercase characters, this will cause an
|
||||
* assertion error. Encoding must be one of BECH32 or BECH32M. */
|
||||
std::string Encode(Encoding encoding, const std::string& hrp, const std::vector<uint8_t>& values);
|
||||
|
||||
struct DecodeResult
|
||||
{
|
||||
Encoding encoding; //!< What encoding was detected in the result; Encoding::INVALID if failed.
|
||||
std::string hrp; //!< The human readable part
|
||||
std::vector<uint8_t> data; //!< The payload (excluding checksum)
|
||||
|
||||
DecodeResult() : encoding(Encoding::INVALID) {}
|
||||
DecodeResult(Encoding enc, std::string&& h, std::vector<uint8_t>&& d) : encoding(enc), hrp(std::move(h)), data(std::move(d)) {}
|
||||
};
|
||||
|
||||
/** Decode a Bech32 or Bech32m string. */
|
||||
DecodeResult Decode(const std::string& str);
|
||||
|
||||
} // namespace bech32
|
||||
|
||||
#endif // DIGIBYTE_BECH32_H
|
||||
1
src/bench/.gitignore
vendored
Normal file
1
src/bench/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
bench_digibyte
|
||||
141
src/bench/addrman.cpp
Normal file
141
src/bench/addrman.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright (c) 2020-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <addrman.h>
|
||||
#include <bench/bench.h>
|
||||
#include <random.h>
|
||||
#include <util/time.h>
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
/* A "source" is a source address from which we have received a bunch of other addresses. */
|
||||
|
||||
static constexpr size_t NUM_SOURCES = 64;
|
||||
static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
|
||||
|
||||
static std::vector<CAddress> g_sources;
|
||||
static std::vector<std::vector<CAddress>> g_addresses;
|
||||
|
||||
static void CreateAddresses()
|
||||
{
|
||||
if (g_sources.size() > 0) { // already created
|
||||
return;
|
||||
}
|
||||
|
||||
FastRandomContext rng(uint256(std::vector<unsigned char>(32, 123)));
|
||||
|
||||
auto randAddr = [&rng]() {
|
||||
in6_addr addr;
|
||||
memcpy(&addr, rng.randbytes(sizeof(addr)).data(), sizeof(addr));
|
||||
|
||||
uint16_t port;
|
||||
memcpy(&port, rng.randbytes(sizeof(port)).data(), sizeof(port));
|
||||
if (port == 0) {
|
||||
port = 1;
|
||||
}
|
||||
|
||||
CAddress ret(CService(addr, port), NODE_NETWORK);
|
||||
|
||||
ret.nTime = GetAdjustedTime();
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
|
||||
g_sources.emplace_back(randAddr());
|
||||
g_addresses.emplace_back();
|
||||
for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
|
||||
g_addresses[source_i].emplace_back(randAddr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void AddAddressesToAddrMan(CAddrMan& addrman)
|
||||
{
|
||||
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
|
||||
addrman.Add(g_addresses[source_i], g_sources[source_i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void FillAddrMan(CAddrMan& addrman)
|
||||
{
|
||||
CreateAddresses();
|
||||
|
||||
AddAddressesToAddrMan(addrman);
|
||||
}
|
||||
|
||||
/* Benchmarks */
|
||||
|
||||
static void AddrManAdd(benchmark::Bench& bench)
|
||||
{
|
||||
CreateAddresses();
|
||||
|
||||
CAddrMan addrman;
|
||||
|
||||
bench.run([&] {
|
||||
AddAddressesToAddrMan(addrman);
|
||||
addrman.Clear();
|
||||
});
|
||||
}
|
||||
|
||||
static void AddrManSelect(benchmark::Bench& bench)
|
||||
{
|
||||
CAddrMan addrman;
|
||||
|
||||
FillAddrMan(addrman);
|
||||
|
||||
bench.run([&] {
|
||||
const auto& address = addrman.Select();
|
||||
assert(address.GetPort() > 0);
|
||||
});
|
||||
}
|
||||
|
||||
static void AddrManGetAddr(benchmark::Bench& bench)
|
||||
{
|
||||
CAddrMan addrman;
|
||||
|
||||
FillAddrMan(addrman);
|
||||
|
||||
bench.run([&] {
|
||||
const auto& addresses = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt);
|
||||
assert(addresses.size() > 0);
|
||||
});
|
||||
}
|
||||
|
||||
static void AddrManGood(benchmark::Bench& bench)
|
||||
{
|
||||
/* Create many CAddrMan objects - one to be modified at each loop iteration.
|
||||
* This is necessary because the CAddrMan::Good() method modifies the
|
||||
* object, affecting the timing of subsequent calls to the same method and
|
||||
* we want to do the same amount of work in every loop iteration. */
|
||||
|
||||
bench.epochs(5).epochIterations(1);
|
||||
|
||||
std::vector<CAddrMan> addrmans(bench.epochs() * bench.epochIterations());
|
||||
for (auto& addrman : addrmans) {
|
||||
FillAddrMan(addrman);
|
||||
}
|
||||
|
||||
auto markSomeAsGood = [](CAddrMan& addrman) {
|
||||
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
|
||||
for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
|
||||
if (addr_i % 32 == 0) {
|
||||
addrman.Good(g_addresses[source_i][addr_i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uint64_t i = 0;
|
||||
bench.run([&] {
|
||||
markSomeAsGood(addrmans.at(i));
|
||||
++i;
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(AddrManAdd);
|
||||
BENCHMARK(AddrManSelect);
|
||||
BENCHMARK(AddrManGetAddr);
|
||||
BENCHMARK(AddrManGood);
|
||||
56
src/bench/base58.cpp
Normal file
56
src/bench/base58.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <base58.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
|
||||
static void Base58Encode(benchmark::Bench& bench)
|
||||
{
|
||||
static const std::array<unsigned char, 32> buff = {
|
||||
{
|
||||
17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
|
||||
227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
|
||||
200, 24
|
||||
}
|
||||
};
|
||||
bench.batch(buff.size()).unit("byte").run([&] {
|
||||
EncodeBase58(buff);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static void Base58CheckEncode(benchmark::Bench& bench)
|
||||
{
|
||||
static const std::array<unsigned char, 32> buff = {
|
||||
{
|
||||
17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
|
||||
227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
|
||||
200, 24
|
||||
}
|
||||
};
|
||||
bench.batch(buff.size()).unit("byte").run([&] {
|
||||
EncodeBase58Check(buff);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static void Base58Decode(benchmark::Bench& bench)
|
||||
{
|
||||
const char* addr = "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem";
|
||||
std::vector<unsigned char> vch;
|
||||
bench.batch(strlen(addr)).unit("byte").run([&] {
|
||||
(void) DecodeBase58(addr, vch, 64);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK(Base58Encode);
|
||||
BENCHMARK(Base58CheckEncode);
|
||||
BENCHMARK(Base58Decode);
|
||||
38
src/bench/bech32.cpp
Normal file
38
src/bench/bech32.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) 2018-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2018-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bench/nanobench.h>
|
||||
|
||||
#include <bech32.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
static void Bech32Encode(benchmark::Bench& bench)
|
||||
{
|
||||
std::vector<uint8_t> v = ParseHex("c97f5a67ec381b760aeaf67573bc164845ff39a3bb26a1cee401ac67243b48db");
|
||||
std::vector<unsigned char> tmp = {0};
|
||||
tmp.reserve(1 + 32 * 8 / 5);
|
||||
ConvertBits<8, 5, true>([&](unsigned char c) { tmp.push_back(c); }, v.begin(), v.end());
|
||||
bench.batch(v.size()).unit("byte").run([&] {
|
||||
bech32::Encode(bech32::Encoding::BECH32, "bc", tmp);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static void Bech32Decode(benchmark::Bench& bench)
|
||||
{
|
||||
std::string addr = "bc1qkallence7tjawwvy0dwt4twc62qjgaw8f4vlhyd006d99f09";
|
||||
bench.batch(addr.size()).unit("byte").run([&] {
|
||||
bech32::Decode(addr);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK(Bech32Encode);
|
||||
BENCHMARK(Bech32Decode);
|
||||
84
src/bench/bench.cpp
Normal file
84
src/bench/bench.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <regex>
|
||||
|
||||
const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
|
||||
|
||||
namespace {
|
||||
|
||||
void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const std::string& filename, const char* tpl)
|
||||
{
|
||||
if (benchmarkResults.empty() || filename.empty()) {
|
||||
// nothing to write, bail out
|
||||
return;
|
||||
}
|
||||
std::ofstream fout(filename);
|
||||
if (fout.is_open()) {
|
||||
ankerl::nanobench::render(tpl, benchmarkResults, fout);
|
||||
} else {
|
||||
std::cout << "Could write to file '" << filename << "'" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Created '" << filename << "'" << std::endl;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
benchmark::BenchRunner::BenchmarkMap& benchmark::BenchRunner::benchmarks()
|
||||
{
|
||||
static std::map<std::string, BenchFunction> benchmarks_map;
|
||||
return benchmarks_map;
|
||||
}
|
||||
|
||||
benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
|
||||
{
|
||||
benchmarks().insert(std::make_pair(name, func));
|
||||
}
|
||||
|
||||
void benchmark::BenchRunner::RunAll(const Args& args)
|
||||
{
|
||||
std::regex reFilter(args.regex_filter);
|
||||
std::smatch baseMatch;
|
||||
|
||||
std::vector<ankerl::nanobench::Result> benchmarkResults;
|
||||
for (const auto& p : benchmarks()) {
|
||||
if (!std::regex_match(p.first, baseMatch, reFilter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args.is_list_only) {
|
||||
std::cout << p.first << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
Bench bench;
|
||||
bench.name(p.first);
|
||||
if (args.asymptote.empty()) {
|
||||
p.second(bench);
|
||||
} else {
|
||||
for (auto n : args.asymptote) {
|
||||
bench.complexityN(n);
|
||||
p.second(bench);
|
||||
}
|
||||
std::cout << bench.complexityBigO() << std::endl;
|
||||
}
|
||||
|
||||
if (!bench.results().empty()) {
|
||||
benchmarkResults.push_back(bench.results().back());
|
||||
}
|
||||
}
|
||||
|
||||
GenerateTemplateResults(benchmarkResults, args.output_csv, "# Benchmark, evals, iterations, total, min, max, median\n"
|
||||
"{{#result}}{{name}}, {{epochs}}, {{average(iterations)}}, {{sumProduct(iterations, elapsed)}}, {{minimum(elapsed)}}, {{maximum(elapsed)}}, {{median(elapsed)}}\n"
|
||||
"{{/result}}");
|
||||
GenerateTemplateResults(benchmarkResults, args.output_json, ankerl::nanobench::templates::json());
|
||||
}
|
||||
68
src/bench/bench.h
Normal file
68
src/bench/bench.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_BENCH_BENCH_H
|
||||
#define DIGIBYTE_BENCH_BENCH_H
|
||||
|
||||
#include <util/macros.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <bench/nanobench.h>
|
||||
|
||||
/*
|
||||
* Usage:
|
||||
|
||||
static void NameOfYourBenchmarkFunction(benchmark::Bench& bench)
|
||||
{
|
||||
...do any setup needed...
|
||||
|
||||
bench.run([&] {
|
||||
...do stuff you want to time; refer to src/bench/nanobench.h
|
||||
for more information and the options that can be passed here...
|
||||
});
|
||||
|
||||
...do any cleanup needed...
|
||||
}
|
||||
|
||||
BENCHMARK(NameOfYourBenchmarkFunction);
|
||||
|
||||
*/
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
using ankerl::nanobench::Bench;
|
||||
|
||||
typedef std::function<void(Bench&)> BenchFunction;
|
||||
|
||||
struct Args {
|
||||
std::string regex_filter;
|
||||
bool is_list_only;
|
||||
std::vector<double> asymptote;
|
||||
std::string output_csv;
|
||||
std::string output_json;
|
||||
};
|
||||
|
||||
class BenchRunner
|
||||
{
|
||||
typedef std::map<std::string, BenchFunction> BenchmarkMap;
|
||||
static BenchmarkMap& benchmarks();
|
||||
|
||||
public:
|
||||
BenchRunner(std::string name, BenchFunction func);
|
||||
|
||||
static void RunAll(const Args& args);
|
||||
};
|
||||
} // namespace benchmark
|
||||
|
||||
// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo);
|
||||
#define BENCHMARK(n) \
|
||||
benchmark::BenchRunner PASTE2(bench_, PASTE2(__LINE__, n))(STRINGIZE(n), n);
|
||||
|
||||
#endif // DIGIBYTE_BENCH_BENCH_H
|
||||
67
src/bench/bench_digibyte.cpp
Normal file
67
src/bench/bench_digibyte.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2021 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <crypto/sha256.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
static const char* DEFAULT_BENCH_FILTER = ".*";
|
||||
|
||||
static void SetupBenchArgs(ArgsManager& argsman)
|
||||
{
|
||||
SetupHelpOptions(argsman);
|
||||
|
||||
argsman.AddArg("-list", "List benchmarks without executing them", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-filter=<regex>", strprintf("Regular expression filter to select benchmark by name (default: %s)", DEFAULT_BENCH_FILTER), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-asymptote=n1,n2,n3,...", strprintf("Test asymptotic growth of the runtime of an algorithm, if supported by the benchmark"), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-output_csv=<output.csv>", "Generate CSV file with the most important benchmark results.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-output_json=<output.json>", "Generate JSON file with all benchmark results.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
}
|
||||
|
||||
// parses a comma separated list like "10,20,30,50"
|
||||
static std::vector<double> parseAsymptote(const std::string& str) {
|
||||
std::stringstream ss(str);
|
||||
std::vector<double> numbers;
|
||||
double d;
|
||||
char c;
|
||||
while (ss >> d) {
|
||||
numbers.push_back(d);
|
||||
ss >> c;
|
||||
}
|
||||
return numbers;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
ArgsManager argsman;
|
||||
SetupBenchArgs(argsman);
|
||||
SHA256AutoDetect();
|
||||
std::string error;
|
||||
if (!argsman.ParseParameters(argc, argv, error)) {
|
||||
tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (HelpRequested(argsman)) {
|
||||
std::cout << argsman.GetHelpMessage();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
benchmark::Args args;
|
||||
args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER);
|
||||
args.is_list_only = argsman.GetBoolArg("-list", false);
|
||||
args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", ""));
|
||||
args.output_csv = argsman.GetArg("-output_csv", "");
|
||||
args.output_json = argsman.GetArg("-output_json", "");
|
||||
|
||||
benchmark::BenchRunner::RunAll(args);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
51
src/bench/block_assemble.cpp
Normal file
51
src/bench/block_assemble.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 2011-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <crypto/sha256.h>
|
||||
#include <test/util/mining.h>
|
||||
#include <test/util/script.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/wallet.h>
|
||||
#include <txmempool.h>
|
||||
#include <validation.h>
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
static void AssembleBlock(benchmark::Bench& bench)
|
||||
{
|
||||
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
CScriptWitness witness;
|
||||
witness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE);
|
||||
|
||||
// Collect some loose transactions that spend the coinbases of our mined blocks
|
||||
constexpr size_t NUM_BLOCKS{130};
|
||||
std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY_2 + 1> txs;
|
||||
for (size_t b{0}; b < NUM_BLOCKS; ++b) {
|
||||
CMutableTransaction tx;
|
||||
tx.vin.push_back(MineBlock(test_setup->m_node, P2WSH_OP_TRUE));
|
||||
tx.vin.back().scriptWitness = witness;
|
||||
tx.vout.emplace_back(1337, P2WSH_OP_TRUE);
|
||||
if (NUM_BLOCKS - b >= COINBASE_MATURITY)
|
||||
txs.at(b) = MakeTransactionRef(tx);
|
||||
}
|
||||
{
|
||||
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
|
||||
|
||||
for (const auto& txr : txs) {
|
||||
const MempoolAcceptResult res = ::AcceptToMemoryPool(test_setup->m_node.chainman->ActiveChainstate(), *test_setup->m_node.mempool, txr, false /* bypass_limits */);
|
||||
assert(res.m_result_type == MempoolAcceptResult::ResultType::VALID);
|
||||
}
|
||||
}
|
||||
|
||||
bench.run([&] {
|
||||
PrepareBlock(test_setup->m_node, P2WSH_OP_TRUE);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(AssembleBlock);
|
||||
55
src/bench/ccoins_caching.cpp
Normal file
55
src/bench/ccoins_caching.cpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <coins.h>
|
||||
#include <policy/policy.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <test/util/transaction_utils.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Microbenchmark for simple accesses to a CCoinsViewCache database. Note from
|
||||
// laanwj, "replicating the actual usage patterns of the client is hard though,
|
||||
// many times micro-benchmarks of the database showed completely different
|
||||
// characteristics than e.g. reindex timings. But that's not a requirement of
|
||||
// every benchmark."
|
||||
// (https://github.com/digibyte/digibyte/issues/7883#issuecomment-224807484)
|
||||
static void CCoinsCaching(benchmark::Bench& bench)
|
||||
{
|
||||
const ECCVerifyHandle verify_handle;
|
||||
ECC_Start();
|
||||
|
||||
FillableSigningProvider keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
std::vector<CMutableTransaction> dummyTransactions =
|
||||
SetupDummyInputs(keystore, coins, {11 * COIN, 50 * COIN, 21 * COIN, 22 * COIN});
|
||||
|
||||
CMutableTransaction t1;
|
||||
t1.vin.resize(3);
|
||||
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
|
||||
t1.vin[0].prevout.n = 1;
|
||||
t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
|
||||
t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
|
||||
t1.vin[1].prevout.n = 0;
|
||||
t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
|
||||
t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
|
||||
t1.vin[2].prevout.n = 1;
|
||||
t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
|
||||
t1.vout.resize(2);
|
||||
t1.vout[0].nValue = 90 * COIN;
|
||||
t1.vout[0].scriptPubKey << OP_1;
|
||||
|
||||
// Benchmark.
|
||||
const CTransaction tx_1(t1);
|
||||
bench.run([&] {
|
||||
bool success = AreInputsStandard(tx_1, coins, false);
|
||||
assert(success);
|
||||
});
|
||||
ECC_Stop();
|
||||
}
|
||||
|
||||
BENCHMARK(CCoinsCaching);
|
||||
44
src/bench/chacha20.cpp
Normal file
44
src/bench/chacha20.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/chacha20.h>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static const uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static const uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static const uint64_t BUFFER_SIZE_LARGE = 1024*1024;
|
||||
|
||||
static void CHACHA20(benchmark::Bench& bench, size_t buffersize)
|
||||
{
|
||||
std::vector<uint8_t> key(32,0);
|
||||
ChaCha20 ctx(key.data(), key.size());
|
||||
ctx.SetIV(0);
|
||||
ctx.Seek(0);
|
||||
std::vector<uint8_t> in(buffersize,0);
|
||||
std::vector<uint8_t> out(buffersize,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
ctx.Crypt(in.data(), out.data(), in.size());
|
||||
});
|
||||
}
|
||||
|
||||
static void CHACHA20_64BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20(bench, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void CHACHA20_256BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20(bench, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void CHACHA20_1MB(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20(bench, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
BENCHMARK(CHACHA20_64BYTES);
|
||||
BENCHMARK(CHACHA20_256BYTES);
|
||||
BENCHMARK(CHACHA20_1MB);
|
||||
126
src/bench/chacha_poly_aead.cpp
Normal file
126
src/bench/chacha_poly_aead.cpp
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/chacha_poly_aead.h>
|
||||
#include <crypto/poly1305.h> // for the POLY1305_TAGLEN constant
|
||||
#include <hash.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static constexpr uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static constexpr uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static constexpr uint64_t BUFFER_SIZE_LARGE = 1024 * 1024;
|
||||
|
||||
static const unsigned char k1[32] = {0};
|
||||
static const unsigned char k2[32] = {0};
|
||||
|
||||
static ChaCha20Poly1305AEAD aead(k1, 32, k2, 32);
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD(benchmark::Bench& bench, size_t buffersize, bool include_decryption)
|
||||
{
|
||||
std::vector<unsigned char> in(buffersize + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
|
||||
std::vector<unsigned char> out(buffersize + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
|
||||
uint64_t seqnr_payload = 0;
|
||||
uint64_t seqnr_aad = 0;
|
||||
int aad_pos = 0;
|
||||
uint32_t len = 0;
|
||||
bench.batch(buffersize).unit("byte").run([&] {
|
||||
// encrypt or decrypt the buffer with a static key
|
||||
const bool crypt_ok_1 = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true);
|
||||
assert(crypt_ok_1);
|
||||
|
||||
if (include_decryption) {
|
||||
// if we decrypt, include the GetLength
|
||||
const bool get_length_ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data());
|
||||
assert(get_length_ok);
|
||||
const bool crypt_ok_2 = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true);
|
||||
assert(crypt_ok_2);
|
||||
}
|
||||
|
||||
// increase main sequence number
|
||||
seqnr_payload++;
|
||||
// increase aad position (position in AAD keystream)
|
||||
aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
|
||||
if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
|
||||
aad_pos = 0;
|
||||
seqnr_aad++;
|
||||
}
|
||||
if (seqnr_payload + 1 == std::numeric_limits<uint64_t>::max()) {
|
||||
// reuse of nonce+key is okay while benchmarking.
|
||||
seqnr_payload = 0;
|
||||
seqnr_aad = 0;
|
||||
aad_pos = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_TINY, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_SMALL, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_LARGE, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_TINY, true);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_SMALL, true);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_LARGE, true);
|
||||
}
|
||||
|
||||
// Add Hash() (dbl-sha256) bench for comparison
|
||||
|
||||
static void HASH(benchmark::Bench& bench, size_t buffersize)
|
||||
{
|
||||
uint8_t hash[CHash256::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(buffersize,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CHash256().Write(in).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void HASH_64BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
HASH(bench, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void HASH_256BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
HASH(bench, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void HASH_1MB(benchmark::Bench& bench)
|
||||
{
|
||||
HASH(bench, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT);
|
||||
BENCHMARK(HASH_64BYTES);
|
||||
BENCHMARK(HASH_256BYTES);
|
||||
BENCHMARK(HASH_1MB);
|
||||
54
src/bench/checkblock.cpp
Normal file
54
src/bench/checkblock.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bench/data.h>
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <streams.h>
|
||||
#include <validation.h>
|
||||
|
||||
// These are the two major time-sinks which happen after we have fully received
|
||||
// a block off the wire, but before we can relay the block on to peers using
|
||||
// compact block relay.
|
||||
|
||||
static void DeserializeBlockTest(benchmark::Bench& bench)
|
||||
{
|
||||
CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
|
||||
char a = '\0';
|
||||
stream.write(&a, 1); // Prevent compaction
|
||||
|
||||
bench.unit("block").run([&] {
|
||||
CBlock block;
|
||||
stream >> block;
|
||||
bool rewound = stream.Rewind(benchmark::data::block413567.size());
|
||||
assert(rewound);
|
||||
});
|
||||
}
|
||||
|
||||
static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
|
||||
{
|
||||
CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
|
||||
char a = '\0';
|
||||
stream.write(&a, 1); // Prevent compaction
|
||||
|
||||
ArgsManager bench_args;
|
||||
const auto chainParams = CreateChainParams(bench_args, CBaseChainParams::MAIN);
|
||||
|
||||
bench.unit("block").run([&] {
|
||||
CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here
|
||||
stream >> block;
|
||||
bool rewound = stream.Rewind(benchmark::data::block413567.size());
|
||||
assert(rewound);
|
||||
|
||||
BlockValidationState validationState;
|
||||
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus());
|
||||
assert(checked);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(DeserializeBlockTest);
|
||||
BENCHMARK(DeserializeAndCheckBlockTest);
|
||||
72
src/bench/checkqueue.cpp
Normal file
72
src/bench/checkqueue.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <checkqueue.h>
|
||||
#include <key.h>
|
||||
#include <prevector.h>
|
||||
#include <pubkey.h>
|
||||
#include <random.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
static const size_t BATCHES = 101;
|
||||
static const size_t BATCH_SIZE = 30;
|
||||
static const int PREVECTOR_SIZE = 28;
|
||||
static const unsigned int QUEUE_BATCH_SIZE = 128;
|
||||
|
||||
// This Benchmark tests the CheckQueue with a slightly realistic workload,
|
||||
// where checks all contain a prevector that is indirect 50% of the time
|
||||
// and there is a little bit of work done between calls to Add.
|
||||
static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
|
||||
{
|
||||
// We shouldn't ever be running with the checkqueue on a single core machine.
|
||||
if (GetNumCores() <= 1) return;
|
||||
|
||||
const ECCVerifyHandle verify_handle;
|
||||
ECC_Start();
|
||||
|
||||
struct PrevectorJob {
|
||||
prevector<PREVECTOR_SIZE, uint8_t> p;
|
||||
PrevectorJob(){
|
||||
}
|
||||
explicit PrevectorJob(FastRandomContext& insecure_rand){
|
||||
p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));
|
||||
}
|
||||
bool operator()()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
void swap(PrevectorJob& x){p.swap(x.p);};
|
||||
};
|
||||
CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE};
|
||||
// The main thread should be counted to prevent thread oversubscription, and
|
||||
// to decrease the variance of benchmark results.
|
||||
queue.StartWorkerThreads(GetNumCores() - 1);
|
||||
|
||||
// create all the data once, then submit copies in the benchmark.
|
||||
FastRandomContext insecure_rand(true);
|
||||
std::vector<std::vector<PrevectorJob>> vBatches(BATCHES);
|
||||
for (auto& vChecks : vBatches) {
|
||||
vChecks.reserve(BATCH_SIZE);
|
||||
for (size_t x = 0; x < BATCH_SIZE; ++x)
|
||||
vChecks.emplace_back(insecure_rand);
|
||||
}
|
||||
|
||||
bench.minEpochIterations(10).batch(BATCH_SIZE * BATCHES).unit("job").run([&] {
|
||||
// Make insecure_rand here so that each iteration is identical.
|
||||
CCheckQueueControl<PrevectorJob> control(&queue);
|
||||
for (auto vChecks : vBatches) {
|
||||
control.Add(vChecks);
|
||||
}
|
||||
// control waits for completion by RAII, but
|
||||
// it is done explicitly here for clarity
|
||||
control.Wait();
|
||||
});
|
||||
queue.StopWorkerThreads();
|
||||
ECC_Stop();
|
||||
}
|
||||
BENCHMARK(CCheckQueueSpeedPrevectorJob);
|
||||
117
src/bench/coin_selection.cpp
Normal file
117
src/bench/coin_selection.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <node/context.h>
|
||||
#include <wallet/coinselection.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<std::unique_ptr<CWalletTx>>& wtxs)
|
||||
{
|
||||
static int nextLockTime = 0;
|
||||
CMutableTransaction tx;
|
||||
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = nValue;
|
||||
wtxs.push_back(std::make_unique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx))));
|
||||
}
|
||||
|
||||
// Simple benchmark for wallet coin selection. Note that it maybe be necessary
|
||||
// to build up more complicated scenarios in order to get meaningful
|
||||
// measurements of performance. From laanwj, "Wallet coin selection is probably
|
||||
// the hardest, as you need a wider selection of scenarios, just testing the
|
||||
// same one over and over isn't too useful. Generating random isn't useful
|
||||
// either for measurements."
|
||||
// (https://github.com/digibyte/digibyte/issues/7883#issuecomment-224807484)
|
||||
static void CoinSelection(benchmark::Bench& bench)
|
||||
{
|
||||
NodeContext node;
|
||||
auto chain = interfaces::MakeChain(node);
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
wallet.SetupLegacyScriptPubKeyMan();
|
||||
std::vector<std::unique_ptr<CWalletTx>> wtxs;
|
||||
LOCK(wallet.cs_wallet);
|
||||
|
||||
// Add coins.
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
addCoin(1000 * COIN, wallet, wtxs);
|
||||
}
|
||||
addCoin(3 * COIN, wallet, wtxs);
|
||||
|
||||
// Create coins
|
||||
std::vector<COutput> coins;
|
||||
for (const auto& wtx : wtxs) {
|
||||
coins.emplace_back(wtx.get(), 0 /* iIn */, 6 * 24 /* nDepthIn */, true /* spendable */, true /* solvable */, true /* safe */);
|
||||
}
|
||||
|
||||
const CoinEligibilityFilter filter_standard(1, 6, 0);
|
||||
const CoinSelectionParams coin_selection_params(/* change_output_size= */ 34,
|
||||
/* change_spend_size= */ 148, /* effective_feerate= */ CFeeRate(0),
|
||||
/* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
|
||||
/* tx_no_inputs_size= */ 0, /* avoid_partial= */ false);
|
||||
bench.run([&] {
|
||||
std::set<CInputCoin> setCoinsRet;
|
||||
CAmount nValueRet;
|
||||
bool success = wallet.AttemptSelection(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params);
|
||||
assert(success);
|
||||
assert(nValueRet == 1003 * COIN);
|
||||
assert(setCoinsRet.size() == 2);
|
||||
});
|
||||
}
|
||||
|
||||
typedef std::set<CInputCoin> CoinSet;
|
||||
static NodeContext testNode;
|
||||
static auto testChain = interfaces::MakeChain(testNode);
|
||||
static CWallet testWallet(testChain.get(), "", CreateDummyWalletDatabase());
|
||||
std::vector<std::unique_ptr<CWalletTx>> wtxn;
|
||||
|
||||
// Copied from src/wallet/test/coinselector_tests.cpp
|
||||
static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>& set)
|
||||
{
|
||||
CMutableTransaction tx;
|
||||
tx.vout.resize(nInput + 1);
|
||||
tx.vout[nInput].nValue = nValue;
|
||||
std::unique_ptr<CWalletTx> wtx = std::make_unique<CWalletTx>(&testWallet, MakeTransactionRef(std::move(tx)));
|
||||
set.emplace_back();
|
||||
set.back().Insert(COutput(wtx.get(), nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0, false);
|
||||
wtxn.emplace_back(std::move(wtx));
|
||||
}
|
||||
// Copied from src/wallet/test/coinselector_tests.cpp
|
||||
static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool)
|
||||
{
|
||||
utxo_pool.clear();
|
||||
CAmount target = 0;
|
||||
for (int i = 0; i < utxos; ++i) {
|
||||
target += (CAmount)1 << (utxos+i);
|
||||
add_coin((CAmount)1 << (utxos+i), 2*i, utxo_pool);
|
||||
add_coin(((CAmount)1 << (utxos+i)) + ((CAmount)1 << (utxos-1-i)), 2*i + 1, utxo_pool);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
static void BnBExhaustion(benchmark::Bench& bench)
|
||||
{
|
||||
// Setup
|
||||
testWallet.SetupLegacyScriptPubKeyMan();
|
||||
std::vector<OutputGroup> utxo_pool;
|
||||
CoinSet selection;
|
||||
CAmount value_ret = 0;
|
||||
|
||||
bench.run([&] {
|
||||
// Benchmark
|
||||
CAmount target = make_hard_case(17, utxo_pool);
|
||||
SelectCoinsBnB(utxo_pool, target, 0, selection, value_ret); // Should exhaust
|
||||
|
||||
// Cleanup
|
||||
utxo_pool.clear();
|
||||
selection.clear();
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(CoinSelection);
|
||||
BENCHMARK(BnBExhaustion);
|
||||
173
src/bench/crypto_hash.cpp
Normal file
173
src/bench/crypto_hash.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/muhash.h>
|
||||
#include <crypto/ripemd160.h>
|
||||
#include <crypto/sha1.h>
|
||||
#include <crypto/sha256.h>
|
||||
#include <crypto/sha3.h>
|
||||
#include <crypto/sha512.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <hash.h>
|
||||
#include <random.h>
|
||||
#include <uint256.h>
|
||||
|
||||
/* Number of bytes to hash per iteration */
|
||||
static const uint64_t BUFFER_SIZE = 1000*1000;
|
||||
|
||||
static void RIPEMD160(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[CRIPEMD160::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CRIPEMD160().Write(in.data(), in.size()).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA1(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[CSHA1::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CSHA1().Write(in.data(), in.size()).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA256(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[CSHA256::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CSHA256().Write(in.data(), in.size()).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA3_256_1M(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[SHA3_256::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
SHA3_256().Write(in).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA256_32b(benchmark::Bench& bench)
|
||||
{
|
||||
std::vector<uint8_t> in(32,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CSHA256()
|
||||
.Write(in.data(), in.size())
|
||||
.Finalize(in.data());
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA256D64_1024(benchmark::Bench& bench)
|
||||
{
|
||||
std::vector<uint8_t> in(64 * 1024, 0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
SHA256D64(in.data(), in.data(), 1024);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA512(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[CSHA512::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CSHA512().Write(in.data(), in.size()).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SipHash_32b(benchmark::Bench& bench)
|
||||
{
|
||||
uint256 x;
|
||||
uint64_t k1 = 0;
|
||||
bench.run([&] {
|
||||
*((uint64_t*)x.begin()) = SipHashUint256(0, ++k1, x);
|
||||
});
|
||||
}
|
||||
|
||||
static void FastRandom_32bit(benchmark::Bench& bench)
|
||||
{
|
||||
FastRandomContext rng(true);
|
||||
bench.run([&] {
|
||||
rng.rand32();
|
||||
});
|
||||
}
|
||||
|
||||
static void FastRandom_1bit(benchmark::Bench& bench)
|
||||
{
|
||||
FastRandomContext rng(true);
|
||||
bench.run([&] {
|
||||
rng.randbool();
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHash(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
unsigned char key[32] = {0};
|
||||
int i = 0;
|
||||
bench.run([&] {
|
||||
key[0] = ++i;
|
||||
acc *= MuHash3072(key);
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashMul(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
MuHash3072 muhash{rng.randbytes(32)};
|
||||
|
||||
bench.run([&] {
|
||||
acc *= muhash;
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashDiv(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
MuHash3072 muhash{rng.randbytes(32)};
|
||||
|
||||
for (size_t i = 0; i < bench.epochIterations(); ++i) {
|
||||
acc *= muhash;
|
||||
}
|
||||
|
||||
bench.run([&] {
|
||||
acc /= muhash;
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashPrecompute(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
std::vector<unsigned char> key{rng.randbytes(32)};
|
||||
|
||||
bench.run([&] {
|
||||
MuHash3072{key};
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(RIPEMD160);
|
||||
BENCHMARK(SHA1);
|
||||
BENCHMARK(SHA256);
|
||||
BENCHMARK(SHA512);
|
||||
BENCHMARK(SHA3_256_1M);
|
||||
|
||||
BENCHMARK(SHA256_32b);
|
||||
BENCHMARK(SipHash_32b);
|
||||
BENCHMARK(SHA256D64_1024);
|
||||
BENCHMARK(FastRandom_32bit);
|
||||
BENCHMARK(FastRandom_1bit);
|
||||
|
||||
BENCHMARK(MuHash);
|
||||
BENCHMARK(MuHashMul);
|
||||
BENCHMARK(MuHashDiv);
|
||||
BENCHMARK(MuHashPrecompute);
|
||||
14
src/bench/data.cpp
Normal file
14
src/bench/data.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/data.h>
|
||||
|
||||
namespace benchmark {
|
||||
namespace data {
|
||||
|
||||
#include <bench/data/block413567.raw.h>
|
||||
const std::vector<uint8_t> block413567{std::begin(block413567_raw), std::end(block413567_raw)};
|
||||
|
||||
} // namespace data
|
||||
} // namespace benchmark
|
||||
19
src/bench/data.h
Normal file
19
src/bench/data.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_BENCH_DATA_H
|
||||
#define DIGIBYTE_BENCH_DATA_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace benchmark {
|
||||
namespace data {
|
||||
|
||||
extern const std::vector<uint8_t> block413567;
|
||||
|
||||
} // namespace data
|
||||
} // namespace benchmark
|
||||
|
||||
#endif // DIGIBYTE_BENCH_DATA_H
|
||||
BIN
src/bench/data/block413567.raw
Normal file
BIN
src/bench/data/block413567.raw
Normal file
Binary file not shown.
65
src/bench/duplicate_inputs.cpp
Normal file
65
src/bench/duplicate_inputs.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2011-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <chainparams.h>
|
||||
#include <consensus/merkle.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <pow.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <txmempool.h>
|
||||
#include <validation.h>
|
||||
|
||||
|
||||
static void DuplicateInputs(benchmark::Bench& bench)
|
||||
{
|
||||
const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
const CScript SCRIPT_PUB{CScript(OP_TRUE)};
|
||||
|
||||
const CChainParams& chainparams = Params();
|
||||
|
||||
CBlock block{};
|
||||
CMutableTransaction coinbaseTx{};
|
||||
CMutableTransaction naughtyTx{};
|
||||
|
||||
LOCK(cs_main);
|
||||
CBlockIndex* pindexPrev = testing_setup->m_node.chainman->ActiveChain().Tip();
|
||||
assert(pindexPrev != nullptr);
|
||||
block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus());
|
||||
block.nNonce = 0;
|
||||
auto nHeight = pindexPrev->nHeight + 1;
|
||||
|
||||
// Make a coinbase TX
|
||||
coinbaseTx.vin.resize(1);
|
||||
coinbaseTx.vin[0].prevout.SetNull();
|
||||
coinbaseTx.vout.resize(1);
|
||||
coinbaseTx.vout[0].scriptPubKey = SCRIPT_PUB;
|
||||
coinbaseTx.vout[0].nValue = GetBlockSubsidy(nHeight, chainparams.GetConsensus());
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
|
||||
|
||||
naughtyTx.vout.resize(1);
|
||||
naughtyTx.vout[0].nValue = 0;
|
||||
naughtyTx.vout[0].scriptPubKey = SCRIPT_PUB;
|
||||
|
||||
uint64_t n_inputs = (((MAX_BLOCK_SERIALIZED_SIZE / WITNESS_SCALE_FACTOR) - (CTransaction(coinbaseTx).GetTotalSize() + CTransaction(naughtyTx).GetTotalSize())) / 41) - 100;
|
||||
for (uint64_t x = 0; x < (n_inputs - 1); ++x) {
|
||||
naughtyTx.vin.emplace_back(GetRandHash(), 0, CScript(), 0);
|
||||
}
|
||||
naughtyTx.vin.emplace_back(naughtyTx.vin.back());
|
||||
|
||||
block.vtx.push_back(MakeTransactionRef(std::move(coinbaseTx)));
|
||||
block.vtx.push_back(MakeTransactionRef(std::move(naughtyTx)));
|
||||
|
||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||
|
||||
bench.run([&] {
|
||||
BlockValidationState cvstate{};
|
||||
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
|
||||
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(DuplicateInputs);
|
||||
22
src/bench/examples.cpp
Normal file
22
src/bench/examples.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
// Extremely fast-running benchmark:
|
||||
#include <math.h>
|
||||
|
||||
volatile double sum = 0.0; // volatile, global so not optimized away
|
||||
|
||||
static void Trig(benchmark::Bench& bench)
|
||||
{
|
||||
double d = 0.01;
|
||||
bench.run([&] {
|
||||
sum += sin(d);
|
||||
d += 0.000001;
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(Trig);
|
||||
43
src/bench/gcs_filter.cpp
Normal file
43
src/bench/gcs_filter.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2018-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <blockfilter.h>
|
||||
|
||||
static void ConstructGCSFilter(benchmark::Bench& bench)
|
||||
{
|
||||
GCSFilter::ElementSet elements;
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
GCSFilter::Element element(32);
|
||||
element[0] = static_cast<unsigned char>(i);
|
||||
element[1] = static_cast<unsigned char>(i >> 8);
|
||||
elements.insert(std::move(element));
|
||||
}
|
||||
|
||||
uint64_t siphash_k0 = 0;
|
||||
bench.batch(elements.size()).unit("elem").run([&] {
|
||||
GCSFilter filter({siphash_k0, 0, 20, 1 << 20}, elements);
|
||||
|
||||
siphash_k0++;
|
||||
});
|
||||
}
|
||||
|
||||
static void MatchGCSFilter(benchmark::Bench& bench)
|
||||
{
|
||||
GCSFilter::ElementSet elements;
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
GCSFilter::Element element(32);
|
||||
element[0] = static_cast<unsigned char>(i);
|
||||
element[1] = static_cast<unsigned char>(i >> 8);
|
||||
elements.insert(std::move(element));
|
||||
}
|
||||
GCSFilter filter({0, 0, 20, 1 << 20}, elements);
|
||||
|
||||
bench.unit("elem").run([&] {
|
||||
filter.Match(GCSFilter::Element());
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(ConstructGCSFilter);
|
||||
BENCHMARK(MatchGCSFilter);
|
||||
47
src/bench/hashpadding.cpp
Normal file
47
src/bench/hashpadding.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <hash.h>
|
||||
#include <random.h>
|
||||
#include <uint256.h>
|
||||
|
||||
|
||||
static void PrePadded(benchmark::Bench& bench)
|
||||
{
|
||||
|
||||
CSHA256 hasher;
|
||||
|
||||
// Setup the salted hasher
|
||||
uint256 nonce = GetRandHash();
|
||||
hasher.Write(nonce.begin(), 32);
|
||||
hasher.Write(nonce.begin(), 32);
|
||||
uint256 data = GetRandHash();
|
||||
bench.run([&] {
|
||||
unsigned char out[32];
|
||||
CSHA256 h = hasher;
|
||||
h.Write(data.begin(), 32);
|
||||
h.Finalize(out);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(PrePadded);
|
||||
|
||||
static void RegularPadded(benchmark::Bench& bench)
|
||||
{
|
||||
CSHA256 hasher;
|
||||
|
||||
// Setup the salted hasher
|
||||
uint256 nonce = GetRandHash();
|
||||
uint256 data = GetRandHash();
|
||||
bench.run([&] {
|
||||
unsigned char out[32];
|
||||
CSHA256 h = hasher;
|
||||
h.Write(nonce.begin(), 32);
|
||||
h.Write(data.begin(), 32);
|
||||
h.Finalize(out);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(RegularPadded);
|
||||
43
src/bench/lockedpool.cpp
Normal file
43
src/bench/lockedpool.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <support/lockedpool.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define ASIZE 2048
|
||||
#define MSIZE 2048
|
||||
|
||||
static void BenchLockedPool(benchmark::Bench& bench)
|
||||
{
|
||||
void *synth_base = reinterpret_cast<void*>(0x08000000);
|
||||
const size_t synth_size = 1024*1024;
|
||||
Arena b(synth_base, synth_size, 16);
|
||||
|
||||
std::vector<void*> addr;
|
||||
for (int x=0; x<ASIZE; ++x)
|
||||
addr.push_back(nullptr);
|
||||
uint32_t s = 0x12345678;
|
||||
bench.run([&] {
|
||||
int idx = s & (addr.size() - 1);
|
||||
if (s & 0x80000000) {
|
||||
b.free(addr[idx]);
|
||||
addr[idx] = nullptr;
|
||||
} else if (!addr[idx]) {
|
||||
addr[idx] = b.alloc((s >> 16) & (MSIZE - 1));
|
||||
}
|
||||
bool lsb = s & 1;
|
||||
s >>= 1;
|
||||
if (lsb)
|
||||
s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0
|
||||
});
|
||||
for (void *ptr: addr)
|
||||
b.free(ptr);
|
||||
addr.clear();
|
||||
}
|
||||
|
||||
BENCHMARK(BenchLockedPool);
|
||||
136
src/bench/mempool_eviction.cpp
Normal file
136
src/bench/mempool_eviction.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright (c) 2011-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <policy/policy.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <txmempool.h>
|
||||
|
||||
|
||||
static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
||||
{
|
||||
int64_t nTime = 0;
|
||||
unsigned int nHeight = 1;
|
||||
bool spendsCoinbase = false;
|
||||
unsigned int sigOpCost = 4;
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(CTxMemPoolEntry(
|
||||
tx, nFee, nTime, nHeight,
|
||||
spendsCoinbase, sigOpCost, lp));
|
||||
}
|
||||
|
||||
// Right now this is only testing eviction performance in an extremely small
|
||||
// mempool. Code needs to be written to generate a much wider variety of
|
||||
// unique transactions for a more meaningful performance measurement.
|
||||
static void MempoolEviction(benchmark::Bench& bench)
|
||||
{
|
||||
const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
CMutableTransaction tx1 = CMutableTransaction();
|
||||
tx1.vin.resize(1);
|
||||
tx1.vin[0].scriptSig = CScript() << OP_1;
|
||||
tx1.vin[0].scriptWitness.stack.push_back({1});
|
||||
tx1.vout.resize(1);
|
||||
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
|
||||
tx1.vout[0].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx2 = CMutableTransaction();
|
||||
tx2.vin.resize(1);
|
||||
tx2.vin[0].scriptSig = CScript() << OP_2;
|
||||
tx2.vin[0].scriptWitness.stack.push_back({2});
|
||||
tx2.vout.resize(1);
|
||||
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
|
||||
tx2.vout[0].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx3 = CMutableTransaction();
|
||||
tx3.vin.resize(1);
|
||||
tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
|
||||
tx3.vin[0].scriptSig = CScript() << OP_2;
|
||||
tx3.vin[0].scriptWitness.stack.push_back({3});
|
||||
tx3.vout.resize(1);
|
||||
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
|
||||
tx3.vout[0].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx4 = CMutableTransaction();
|
||||
tx4.vin.resize(2);
|
||||
tx4.vin[0].prevout.SetNull();
|
||||
tx4.vin[0].scriptSig = CScript() << OP_4;
|
||||
tx4.vin[0].scriptWitness.stack.push_back({4});
|
||||
tx4.vin[1].prevout.SetNull();
|
||||
tx4.vin[1].scriptSig = CScript() << OP_4;
|
||||
tx4.vin[1].scriptWitness.stack.push_back({4});
|
||||
tx4.vout.resize(2);
|
||||
tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
|
||||
tx4.vout[0].nValue = 10 * COIN;
|
||||
tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
|
||||
tx4.vout[1].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx5 = CMutableTransaction();
|
||||
tx5.vin.resize(2);
|
||||
tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
|
||||
tx5.vin[0].scriptSig = CScript() << OP_4;
|
||||
tx5.vin[0].scriptWitness.stack.push_back({4});
|
||||
tx5.vin[1].prevout.SetNull();
|
||||
tx5.vin[1].scriptSig = CScript() << OP_5;
|
||||
tx5.vin[1].scriptWitness.stack.push_back({5});
|
||||
tx5.vout.resize(2);
|
||||
tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
|
||||
tx5.vout[0].nValue = 10 * COIN;
|
||||
tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
|
||||
tx5.vout[1].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx6 = CMutableTransaction();
|
||||
tx6.vin.resize(2);
|
||||
tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
|
||||
tx6.vin[0].scriptSig = CScript() << OP_4;
|
||||
tx6.vin[0].scriptWitness.stack.push_back({4});
|
||||
tx6.vin[1].prevout.SetNull();
|
||||
tx6.vin[1].scriptSig = CScript() << OP_6;
|
||||
tx6.vin[1].scriptWitness.stack.push_back({6});
|
||||
tx6.vout.resize(2);
|
||||
tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
|
||||
tx6.vout[0].nValue = 10 * COIN;
|
||||
tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
|
||||
tx6.vout[1].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx7 = CMutableTransaction();
|
||||
tx7.vin.resize(2);
|
||||
tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
|
||||
tx7.vin[0].scriptSig = CScript() << OP_5;
|
||||
tx7.vin[0].scriptWitness.stack.push_back({5});
|
||||
tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
|
||||
tx7.vin[1].scriptSig = CScript() << OP_6;
|
||||
tx7.vin[1].scriptWitness.stack.push_back({6});
|
||||
tx7.vout.resize(2);
|
||||
tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
|
||||
tx7.vout[0].nValue = 10 * COIN;
|
||||
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
|
||||
tx7.vout[1].nValue = 10 * COIN;
|
||||
|
||||
CTxMemPool pool;
|
||||
LOCK2(cs_main, pool.cs);
|
||||
// Create transaction references outside the "hot loop"
|
||||
const CTransactionRef tx1_r{MakeTransactionRef(tx1)};
|
||||
const CTransactionRef tx2_r{MakeTransactionRef(tx2)};
|
||||
const CTransactionRef tx3_r{MakeTransactionRef(tx3)};
|
||||
const CTransactionRef tx4_r{MakeTransactionRef(tx4)};
|
||||
const CTransactionRef tx5_r{MakeTransactionRef(tx5)};
|
||||
const CTransactionRef tx6_r{MakeTransactionRef(tx6)};
|
||||
const CTransactionRef tx7_r{MakeTransactionRef(tx7)};
|
||||
|
||||
bench.run([&]() NO_THREAD_SAFETY_ANALYSIS {
|
||||
AddTx(tx1_r, 10000LL, pool);
|
||||
AddTx(tx2_r, 5000LL, pool);
|
||||
AddTx(tx3_r, 20000LL, pool);
|
||||
AddTx(tx4_r, 7000LL, pool);
|
||||
AddTx(tx5_r, 1000LL, pool);
|
||||
AddTx(tx6_r, 1100LL, pool);
|
||||
AddTx(tx7_r, 9000LL, pool);
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
|
||||
pool.TrimToSize(GetVirtualTransactionSize(*tx1_r));
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(MempoolEviction);
|
||||
94
src/bench/mempool_stress.cpp
Normal file
94
src/bench/mempool_stress.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) 2011-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <policy/policy.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <txmempool.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
static void AddTx(const CTransactionRef& tx, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
||||
{
|
||||
int64_t nTime = 0;
|
||||
unsigned int nHeight = 1;
|
||||
bool spendsCoinbase = false;
|
||||
unsigned int sigOpCost = 4;
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(CTxMemPoolEntry(tx, 1000, nTime, nHeight, spendsCoinbase, sigOpCost, lp));
|
||||
}
|
||||
|
||||
struct Available {
|
||||
CTransactionRef ref;
|
||||
size_t vin_left{0};
|
||||
size_t tx_count;
|
||||
Available(CTransactionRef& ref, size_t tx_count) : ref(ref), tx_count(tx_count){}
|
||||
};
|
||||
|
||||
static void ComplexMemPool(benchmark::Bench& bench)
|
||||
{
|
||||
int childTxs = 800;
|
||||
if (bench.complexityN() > 1) {
|
||||
childTxs = static_cast<int>(bench.complexityN());
|
||||
}
|
||||
|
||||
FastRandomContext det_rand{true};
|
||||
std::vector<Available> available_coins;
|
||||
std::vector<CTransactionRef> ordered_coins;
|
||||
// Create some base transactions
|
||||
size_t tx_counter = 1;
|
||||
for (auto x = 0; x < 100; ++x) {
|
||||
CMutableTransaction tx = CMutableTransaction();
|
||||
tx.vin.resize(1);
|
||||
tx.vin[0].scriptSig = CScript() << CScriptNum(tx_counter);
|
||||
tx.vin[0].scriptWitness.stack.push_back(CScriptNum(x).getvch());
|
||||
tx.vout.resize(det_rand.randrange(10)+2);
|
||||
for (auto& out : tx.vout) {
|
||||
out.scriptPubKey = CScript() << CScriptNum(tx_counter) << OP_EQUAL;
|
||||
out.nValue = 10 * COIN;
|
||||
}
|
||||
ordered_coins.emplace_back(MakeTransactionRef(tx));
|
||||
available_coins.emplace_back(ordered_coins.back(), tx_counter++);
|
||||
}
|
||||
for (auto x = 0; x < childTxs && !available_coins.empty(); ++x) {
|
||||
CMutableTransaction tx = CMutableTransaction();
|
||||
size_t n_ancestors = det_rand.randrange(10)+1;
|
||||
for (size_t ancestor = 0; ancestor < n_ancestors && !available_coins.empty(); ++ancestor){
|
||||
size_t idx = det_rand.randrange(available_coins.size());
|
||||
Available coin = available_coins[idx];
|
||||
uint256 hash = coin.ref->GetHash();
|
||||
// biased towards taking just one ancestor, but maybe more
|
||||
size_t n_to_take = det_rand.randrange(2) == 0 ? 1 : 1+det_rand.randrange(coin.ref->vout.size() - coin.vin_left);
|
||||
for (size_t i = 0; i < n_to_take; ++i) {
|
||||
tx.vin.emplace_back();
|
||||
tx.vin.back().prevout = COutPoint(hash, coin.vin_left++);
|
||||
tx.vin.back().scriptSig = CScript() << coin.tx_count;
|
||||
tx.vin.back().scriptWitness.stack.push_back(CScriptNum(coin.tx_count).getvch());
|
||||
}
|
||||
if (coin.vin_left == coin.ref->vin.size()) {
|
||||
coin = available_coins.back();
|
||||
available_coins.pop_back();
|
||||
}
|
||||
tx.vout.resize(det_rand.randrange(10)+2);
|
||||
for (auto& out : tx.vout) {
|
||||
out.scriptPubKey = CScript() << CScriptNum(tx_counter) << OP_EQUAL;
|
||||
out.nValue = 10 * COIN;
|
||||
}
|
||||
}
|
||||
ordered_coins.emplace_back(MakeTransactionRef(tx));
|
||||
available_coins.emplace_back(ordered_coins.back(), tx_counter++);
|
||||
}
|
||||
const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN);
|
||||
CTxMemPool pool;
|
||||
LOCK2(cs_main, pool.cs);
|
||||
bench.run([&]() NO_THREAD_SAFETY_ANALYSIS {
|
||||
for (auto& tx : ordered_coins) {
|
||||
AddTx(tx, pool);
|
||||
}
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
|
||||
pool.TrimToSize(GetVirtualTransactionSize(*ordered_coins.front()));
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(ComplexMemPool);
|
||||
27
src/bench/merkle_root.cpp
Normal file
27
src/bench/merkle_root.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <consensus/merkle.h>
|
||||
#include <random.h>
|
||||
#include <uint256.h>
|
||||
|
||||
static void MerkleRoot(benchmark::Bench& bench)
|
||||
{
|
||||
FastRandomContext rng(true);
|
||||
std::vector<uint256> leaves;
|
||||
leaves.resize(9001);
|
||||
for (auto& item : leaves) {
|
||||
item = rng.rand256();
|
||||
}
|
||||
bench.batch(leaves.size()).unit("leaf").run([&] {
|
||||
bool mutation = false;
|
||||
uint256 hash = ComputeMerkleRoot(std::vector<uint256>(leaves), &mutation);
|
||||
leaves[mutation] = hash;
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(MerkleRoot);
|
||||
6
src/bench/nanobench.cpp
Normal file
6
src/bench/nanobench.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#define ANKERL_NANOBENCH_IMPLEMENT
|
||||
#include <bench/nanobench.h>
|
||||
3360
src/bench/nanobench.h
Normal file
3360
src/bench/nanobench.h
Normal file
File diff suppressed because it is too large
Load diff
157
src/bench/peer_eviction.cpp
Normal file
157
src/bench/peer_eviction.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright (c) 2021 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <net.h>
|
||||
#include <netaddress.h>
|
||||
#include <random.h>
|
||||
#include <test/util/net.h>
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
static void EvictionProtectionCommon(
|
||||
benchmark::Bench& bench,
|
||||
int num_candidates,
|
||||
std::function<void(NodeEvictionCandidate&)> candidate_setup_fn)
|
||||
{
|
||||
using Candidates = std::vector<NodeEvictionCandidate>;
|
||||
FastRandomContext random_context{true};
|
||||
bench.warmup(100).epochIterations(1100);
|
||||
|
||||
Candidates candidates{GetRandomNodeEvictionCandidates(num_candidates, random_context)};
|
||||
for (auto& c : candidates) {
|
||||
candidate_setup_fn(c);
|
||||
}
|
||||
|
||||
std::vector<Candidates> copies{
|
||||
static_cast<size_t>(bench.epochs() * bench.epochIterations()), candidates};
|
||||
size_t i{0};
|
||||
bench.run([&] {
|
||||
ProtectEvictionCandidatesByRatio(copies.at(i));
|
||||
++i;
|
||||
});
|
||||
}
|
||||
|
||||
/* Benchmarks */
|
||||
|
||||
static void EvictionProtection0Networks250Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
250 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_network = NET_IPV4;
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection1Networks250Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
250 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = false;
|
||||
if (c.id >= 130 && c.id < 240) { // 110 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection2Networks250Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
250 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = false;
|
||||
if (c.id >= 90 && c.id < 160) { // 70 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else if (c.id >= 170 && c.id < 250) { // 80 I2P
|
||||
c.m_network = NET_I2P;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection3Networks050Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
50 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id == 28 || c.id == 47); // 2 localhost
|
||||
if (c.id >= 30 && c.id < 47) { // 17 I2P
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id >= 24 && c.id < 28) { // 4 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection3Networks100Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
100 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id >= 55 && c.id < 60); // 5 localhost
|
||||
if (c.id >= 70 && c.id < 80) { // 10 I2P
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id >= 80 && c.id < 96) { // 16 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
250 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id >= 140 && c.id < 160); // 20 localhost
|
||||
if (c.id >= 170 && c.id < 180) { // 10 I2P
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id >= 190 && c.id < 240) { // 50 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Candidate numbers used for the benchmarks:
|
||||
// - 50 candidates simulates a possible use of -maxconnections
|
||||
// - 100 candidates approximates an average node with default settings
|
||||
// - 250 candidates is the number of peers reported by operators of busy nodes
|
||||
|
||||
// No disadvantaged networks, with 250 eviction candidates.
|
||||
BENCHMARK(EvictionProtection0Networks250Candidates);
|
||||
|
||||
// 1 disadvantaged network (Tor) with 250 eviction candidates.
|
||||
BENCHMARK(EvictionProtection1Networks250Candidates);
|
||||
|
||||
// 2 disadvantaged networks (I2P, Tor) with 250 eviction candidates.
|
||||
BENCHMARK(EvictionProtection2Networks250Candidates);
|
||||
|
||||
// 3 disadvantaged networks (I2P/localhost/Tor) with 50/100/250 eviction candidates.
|
||||
BENCHMARK(EvictionProtection3Networks050Candidates);
|
||||
BENCHMARK(EvictionProtection3Networks100Candidates);
|
||||
BENCHMARK(EvictionProtection3Networks250Candidates);
|
||||
53
src/bench/perf.cpp
Normal file
53
src/bench/perf.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2016-2017 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/perf.h>
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
||||
/* These architectures support querying the cycle counter
|
||||
* from user space, no need for any syscall overhead.
|
||||
*/
|
||||
void perf_init(void) { }
|
||||
void perf_fini(void) { }
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
static int fd = -1;
|
||||
static struct perf_event_attr attr;
|
||||
|
||||
void perf_init(void)
|
||||
{
|
||||
attr.type = PERF_TYPE_HARDWARE;
|
||||
attr.config = PERF_COUNT_HW_CPU_CYCLES;
|
||||
fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
|
||||
}
|
||||
|
||||
void perf_fini(void)
|
||||
{
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t perf_cpucycles(void)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
if (fd == -1 || read(fd, &result, sizeof(result)) < (ssize_t)sizeof(result)) {
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else /* Unhandled platform */
|
||||
|
||||
void perf_init(void) { }
|
||||
void perf_fini(void) { }
|
||||
uint64_t perf_cpucycles(void) { return 0; }
|
||||
|
||||
#endif
|
||||
37
src/bench/perf.h
Normal file
37
src/bench/perf.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2016 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
/** Functions for measurement of CPU cycles */
|
||||
#ifndef H_PERF
|
||||
#define H_PERF
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
static inline uint64_t perf_cpucycles(void)
|
||||
{
|
||||
uint64_t x;
|
||||
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
|
||||
return x;
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
static inline uint64_t perf_cpucycles(void)
|
||||
{
|
||||
uint32_t hi, lo;
|
||||
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((uint64_t)lo)|(((uint64_t)hi)<<32);
|
||||
}
|
||||
#else
|
||||
|
||||
uint64_t perf_cpucycles(void);
|
||||
|
||||
#endif
|
||||
|
||||
void perf_init(void);
|
||||
void perf_fini(void);
|
||||
|
||||
#endif // H_PERF
|
||||
41
src/bench/poly1305.cpp
Normal file
41
src/bench/poly1305.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/poly1305.h>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static constexpr uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static constexpr uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static constexpr uint64_t BUFFER_SIZE_LARGE = 1024*1024;
|
||||
|
||||
static void POLY1305(benchmark::Bench& bench, size_t buffersize)
|
||||
{
|
||||
std::vector<unsigned char> tag(POLY1305_TAGLEN, 0);
|
||||
std::vector<unsigned char> key(POLY1305_KEYLEN, 0);
|
||||
std::vector<unsigned char> in(buffersize, 0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
poly1305_auth(tag.data(), in.data(), in.size(), key.data());
|
||||
});
|
||||
}
|
||||
|
||||
static void POLY1305_64BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
POLY1305(bench, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void POLY1305_256BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
POLY1305(bench, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void POLY1305_1MB(benchmark::Bench& bench)
|
||||
{
|
||||
POLY1305(bench, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
BENCHMARK(POLY1305_64BYTES);
|
||||
BENCHMARK(POLY1305_256BYTES);
|
||||
BENCHMARK(POLY1305_1MB);
|
||||
99
src/bench/prevector.cpp
Normal file
99
src/bench/prevector.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <prevector.h>
|
||||
#include <serialize.h>
|
||||
#include <streams.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
struct nontrivial_t {
|
||||
int x;
|
||||
nontrivial_t() :x(-1) {}
|
||||
SERIALIZE_METHODS(nontrivial_t, obj) { READWRITE(obj.x); }
|
||||
};
|
||||
static_assert(!std::is_trivially_default_constructible<nontrivial_t>::value,
|
||||
"expected nontrivial_t to not be trivially constructible");
|
||||
|
||||
typedef unsigned char trivial_t;
|
||||
static_assert(std::is_trivially_default_constructible<trivial_t>::value,
|
||||
"expected trivial_t to be trivially constructible");
|
||||
|
||||
template <typename T>
|
||||
static void PrevectorDestructor(benchmark::Bench& bench)
|
||||
{
|
||||
bench.batch(2).run([&] {
|
||||
prevector<28, T> t0;
|
||||
prevector<28, T> t1;
|
||||
t0.resize(28);
|
||||
t1.resize(29);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void PrevectorClear(benchmark::Bench& bench)
|
||||
{
|
||||
prevector<28, T> t0;
|
||||
prevector<28, T> t1;
|
||||
bench.batch(2).run([&] {
|
||||
t0.resize(28);
|
||||
t0.clear();
|
||||
t1.resize(29);
|
||||
t1.clear();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void PrevectorResize(benchmark::Bench& bench)
|
||||
{
|
||||
prevector<28, T> t0;
|
||||
prevector<28, T> t1;
|
||||
bench.batch(4).run([&] {
|
||||
t0.resize(28);
|
||||
t0.resize(0);
|
||||
t1.resize(29);
|
||||
t1.resize(0);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void PrevectorDeserialize(benchmark::Bench& bench)
|
||||
{
|
||||
CDataStream s0(SER_NETWORK, 0);
|
||||
prevector<28, T> t0;
|
||||
t0.resize(28);
|
||||
for (auto x = 0; x < 900; ++x) {
|
||||
s0 << t0;
|
||||
}
|
||||
t0.resize(100);
|
||||
for (auto x = 0; x < 101; ++x) {
|
||||
s0 << t0;
|
||||
}
|
||||
bench.batch(1000).run([&] {
|
||||
prevector<28, T> t1;
|
||||
for (auto x = 0; x < 1000; ++x) {
|
||||
s0 >> t1;
|
||||
}
|
||||
s0.Rewind();
|
||||
});
|
||||
}
|
||||
|
||||
#define PREVECTOR_TEST(name) \
|
||||
static void Prevector##name##Nontrivial(benchmark::Bench& bench) \
|
||||
{ \
|
||||
Prevector##name<nontrivial_t>(bench); \
|
||||
} \
|
||||
BENCHMARK(Prevector##name##Nontrivial); \
|
||||
static void Prevector##name##Trivial(benchmark::Bench& bench) \
|
||||
{ \
|
||||
Prevector##name<trivial_t>(bench); \
|
||||
} \
|
||||
BENCHMARK(Prevector##name##Trivial);
|
||||
|
||||
PREVECTOR_TEST(Clear)
|
||||
PREVECTOR_TEST(Destructor)
|
||||
PREVECTOR_TEST(Resize)
|
||||
PREVECTOR_TEST(Deserialize)
|
||||
40
src/bench/rollingbloom.cpp
Normal file
40
src/bench/rollingbloom.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bloom.h>
|
||||
|
||||
static void RollingBloom(benchmark::Bench& bench)
|
||||
{
|
||||
CRollingBloomFilter filter(120000, 0.000001);
|
||||
std::vector<unsigned char> data(32);
|
||||
uint32_t count = 0;
|
||||
bench.run([&] {
|
||||
count++;
|
||||
data[0] = count;
|
||||
data[1] = count >> 8;
|
||||
data[2] = count >> 16;
|
||||
data[3] = count >> 24;
|
||||
filter.insert(data);
|
||||
|
||||
data[0] = count >> 24;
|
||||
data[1] = count >> 16;
|
||||
data[2] = count >> 8;
|
||||
data[3] = count;
|
||||
filter.contains(data);
|
||||
});
|
||||
}
|
||||
|
||||
static void RollingBloomReset(benchmark::Bench& bench)
|
||||
{
|
||||
CRollingBloomFilter filter(120000, 0.000001);
|
||||
bench.run([&] {
|
||||
filter.reset();
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(RollingBloom);
|
||||
BENCHMARK(RollingBloomReset);
|
||||
60
src/bench/rpc_blockchain.cpp
Normal file
60
src/bench/rpc_blockchain.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bench/data.h>
|
||||
|
||||
#include <rpc/blockchain.h>
|
||||
#include <streams.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestBlockAndIndex {
|
||||
const std::unique_ptr<const TestingSetup> testing_setup{MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN)};
|
||||
CBlock block{};
|
||||
uint256 blockHash{};
|
||||
CBlockIndex blockindex{};
|
||||
|
||||
TestBlockAndIndex()
|
||||
{
|
||||
CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
|
||||
char a = '\0';
|
||||
stream.write(&a, 1); // Prevent compaction
|
||||
|
||||
stream >> block;
|
||||
|
||||
blockHash = block.GetHash();
|
||||
blockindex.phashBlock = &blockHash;
|
||||
blockindex.nBits = 403014710;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static void BlockToJsonVerbose(benchmark::Bench& bench)
|
||||
{
|
||||
TestBlockAndIndex data;
|
||||
bench.run([&] {
|
||||
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, /*verbose*/ true);
|
||||
ankerl::nanobench::doNotOptimizeAway(univalue);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(BlockToJsonVerbose);
|
||||
|
||||
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
|
||||
{
|
||||
TestBlockAndIndex data;
|
||||
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, /*verbose*/ true);
|
||||
bench.run([&] {
|
||||
auto str = univalue.write();
|
||||
ankerl::nanobench::doNotOptimizeAway(str);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(BlockToJsonVerboseWrite);
|
||||
40
src/bench/rpc_mempool.cpp
Normal file
40
src/bench/rpc_mempool.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2011-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <rpc/blockchain.h>
|
||||
#include <txmempool.h>
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
|
||||
static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
||||
{
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(CTxMemPoolEntry(tx, fee, /* time */ 0, /* height */ 1, /* spendsCoinbase */ false, /* sigOpCost */ 4, lp));
|
||||
}
|
||||
|
||||
static void RpcMempool(benchmark::Bench& bench)
|
||||
{
|
||||
CTxMemPool pool;
|
||||
LOCK2(cs_main, pool.cs);
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
CMutableTransaction tx = CMutableTransaction();
|
||||
tx.vin.resize(1);
|
||||
tx.vin[0].scriptSig = CScript() << OP_1;
|
||||
tx.vin[0].scriptWitness.stack.push_back({1});
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
|
||||
tx.vout[0].nValue = i;
|
||||
const CTransactionRef tx_r{MakeTransactionRef(tx)};
|
||||
AddTx(tx_r, /* fee */ i, pool);
|
||||
}
|
||||
|
||||
bench.run([&] {
|
||||
(void)MempoolToJSON(pool, /*verbose*/ true);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(RpcMempool);
|
||||
42
src/bench/util_time.cpp
Normal file
42
src/bench/util_time.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <util/time.h>
|
||||
|
||||
static void BenchTimeDeprecated(benchmark::Bench& bench)
|
||||
{
|
||||
bench.run([&] {
|
||||
(void)GetTime();
|
||||
});
|
||||
}
|
||||
|
||||
static void BenchTimeMock(benchmark::Bench& bench)
|
||||
{
|
||||
SetMockTime(111);
|
||||
bench.run([&] {
|
||||
(void)GetTime<std::chrono::seconds>();
|
||||
});
|
||||
SetMockTime(0);
|
||||
}
|
||||
|
||||
static void BenchTimeMillis(benchmark::Bench& bench)
|
||||
{
|
||||
bench.run([&] {
|
||||
(void)GetTime<std::chrono::milliseconds>();
|
||||
});
|
||||
}
|
||||
|
||||
static void BenchTimeMillisSys(benchmark::Bench& bench)
|
||||
{
|
||||
bench.run([&] {
|
||||
(void)GetTimeMillis();
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(BenchTimeDeprecated);
|
||||
BENCHMARK(BenchTimeMillis);
|
||||
BENCHMARK(BenchTimeMillisSys);
|
||||
BENCHMARK(BenchTimeMock);
|
||||
101
src/bench/verify_script.cpp
Normal file
101
src/bench/verify_script.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <key.h>
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
#include <script/vextaconsensus.h>
|
||||
#endif
|
||||
#include <script/script.h>
|
||||
#include <script/standard.h>
|
||||
#include <streams.h>
|
||||
#include <test/util/transaction_utils.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
// Microbenchmark for verification of a basic P2WPKH script. Can be easily
|
||||
// modified to measure performance of other types of scripts.
|
||||
static void VerifyScriptBench(benchmark::Bench& bench)
|
||||
{
|
||||
const ECCVerifyHandle verify_handle;
|
||||
ECC_Start();
|
||||
|
||||
const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH;
|
||||
const int witnessversion = 0;
|
||||
|
||||
// Key pair.
|
||||
CKey key;
|
||||
static const std::array<unsigned char, 32> vchKey = {
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
||||
}
|
||||
};
|
||||
key.Set(vchKey.begin(), vchKey.end(), false);
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
uint160 pubkeyHash;
|
||||
CHash160().Write(pubkey).Finalize(pubkeyHash);
|
||||
|
||||
// Script.
|
||||
CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
|
||||
CScript scriptSig;
|
||||
CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
const CMutableTransaction& txCredit = BuildCreditingTransaction(scriptPubKey, 1);
|
||||
CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, CScriptWitness(), CTransaction(txCredit));
|
||||
CScriptWitness& witness = txSpend.vin[0].scriptWitness;
|
||||
witness.stack.emplace_back();
|
||||
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0), witness.stack.back());
|
||||
witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
|
||||
witness.stack.push_back(ToByteVector(pubkey));
|
||||
|
||||
// Benchmark.
|
||||
bench.run([&] {
|
||||
ScriptError err;
|
||||
bool success = VerifyScript(
|
||||
txSpend.vin[0].scriptSig,
|
||||
txCredit.vout[0].scriptPubKey,
|
||||
&txSpend.vin[0].scriptWitness,
|
||||
flags,
|
||||
MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL),
|
||||
&err);
|
||||
assert(err == SCRIPT_ERR_OK);
|
||||
assert(success);
|
||||
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << txSpend;
|
||||
int csuccess = vextaconsensus_verify_script_with_amount(
|
||||
txCredit.vout[0].scriptPubKey.data(),
|
||||
txCredit.vout[0].scriptPubKey.size(),
|
||||
txCredit.vout[0].nValue,
|
||||
(const unsigned char*)stream.data(), stream.size(), 0, flags, nullptr);
|
||||
assert(csuccess == 1);
|
||||
#endif
|
||||
});
|
||||
ECC_Stop();
|
||||
}
|
||||
|
||||
static void VerifyNestedIfScript(benchmark::Bench& bench)
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> stack;
|
||||
CScript script;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
script << OP_1 << OP_IF;
|
||||
}
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
script << OP_1;
|
||||
}
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
script << OP_ENDIF;
|
||||
}
|
||||
bench.run([&] {
|
||||
auto stack_copy = stack;
|
||||
ScriptError error;
|
||||
bool ret = EvalScript(stack_copy, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
|
||||
assert(ret);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(VerifyScriptBench);
|
||||
BENCHMARK(VerifyNestedIfScript);
|
||||
56
src/bench/wallet_balance.cpp
Normal file
56
src/bench/wallet_balance.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2012-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <node/context.h>
|
||||
#include <test/util/mining.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/wallet.h>
|
||||
#include <validationinterface.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_watchonly, const bool add_mine)
|
||||
{
|
||||
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
const auto& ADDRESS_WATCHONLY = ADDRESS_dgbrt_UNSPENDABLE;
|
||||
|
||||
CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
|
||||
{
|
||||
wallet.SetupLegacyScriptPubKeyMan();
|
||||
if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false);
|
||||
}
|
||||
auto handler = test_setup->m_node.chain->handleNotifications({&wallet, [](CWallet*) {}});
|
||||
|
||||
const std::optional<std::string> address_mine{add_mine ? std::optional<std::string>{getnewaddress(wallet)} : std::nullopt};
|
||||
if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY);
|
||||
|
||||
for (int i = 0; i < 60; ++i) {
|
||||
generatetoaddress(test_setup->m_node, address_mine.value_or(ADDRESS_WATCHONLY));
|
||||
generatetoaddress(test_setup->m_node, ADDRESS_WATCHONLY);
|
||||
}
|
||||
SyncWithValidationInterfaceQueue();
|
||||
|
||||
auto bal = wallet.GetBalance(); // Cache
|
||||
|
||||
bench.run([&] {
|
||||
if (set_dirty) wallet.MarkDirty();
|
||||
bal = wallet.GetBalance();
|
||||
if (add_mine) assert(bal.m_mine_trusted > 0);
|
||||
if (add_watchonly) assert(bal.m_watchonly_trusted > 0);
|
||||
});
|
||||
}
|
||||
|
||||
static void WalletBalanceDirty(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ true, /* add_watchonly */ true, /* add_mine */ true); }
|
||||
static void WalletBalanceClean(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ true, /* add_mine */ true); }
|
||||
static void WalletBalanceMine(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ false, /* add_mine */ true); }
|
||||
static void WalletBalanceWatch(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ true, /* add_mine */ false); }
|
||||
|
||||
BENCHMARK(WalletBalanceDirty);
|
||||
BENCHMARK(WalletBalanceClean);
|
||||
BENCHMARK(WalletBalanceMine);
|
||||
BENCHMARK(WalletBalanceWatch);
|
||||
220
src/blockencodings.cpp
Normal file
220
src/blockencodings.cpp
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <blockencodings.h>
|
||||
#include <consensus/consensus.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <chainparams.h>
|
||||
#include <crypto/sha256.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <random.h>
|
||||
#include <streams.h>
|
||||
#include <txmempool.h>
|
||||
#include <validation.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) :
|
||||
nonce(GetRand(std::numeric_limits<uint64_t>::max())),
|
||||
shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {
|
||||
FillShortTxIDSelector();
|
||||
//TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase
|
||||
prefilledtxn[0] = {0, block.vtx[0]};
|
||||
for (size_t i = 1; i < block.vtx.size(); i++) {
|
||||
const CTransaction& tx = *block.vtx[i];
|
||||
shorttxids[i - 1] = GetShortID(fUseWTXID ? tx.GetWitnessHash() : tx.GetHash());
|
||||
}
|
||||
}
|
||||
|
||||
void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << header << nonce;
|
||||
CSHA256 hasher;
|
||||
hasher.Write((unsigned char*)&(*stream.begin()), stream.end() - stream.begin());
|
||||
uint256 shorttxidhash;
|
||||
hasher.Finalize(shorttxidhash.begin());
|
||||
shorttxidk0 = shorttxidhash.GetUint64(0);
|
||||
shorttxidk1 = shorttxidhash.GetUint64(1);
|
||||
}
|
||||
|
||||
uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const {
|
||||
static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids calculation assumes 6-byte shorttxids");
|
||||
return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn) {
|
||||
CBlockIndex pindex;
|
||||
if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))
|
||||
return READ_STATUS_INVALID;
|
||||
if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_WEIGHT / MIN_SERIALIZABLE_TRANSACTION_WEIGHT)
|
||||
return READ_STATUS_INVALID;
|
||||
|
||||
assert(header.IsNull() && txn_available.empty());
|
||||
header = cmpctblock.header;
|
||||
txn_available.resize(cmpctblock.BlockTxCount());
|
||||
|
||||
int32_t lastprefilledindex = -1;
|
||||
for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) {
|
||||
if (cmpctblock.prefilledtxn[i].tx->IsNull())
|
||||
return READ_STATUS_INVALID;
|
||||
|
||||
lastprefilledindex += cmpctblock.prefilledtxn[i].index + 1; //index is a uint16_t, so can't overflow here
|
||||
if (lastprefilledindex > std::numeric_limits<uint16_t>::max())
|
||||
return READ_STATUS_INVALID;
|
||||
if ((uint32_t)lastprefilledindex > cmpctblock.shorttxids.size() + i) {
|
||||
// If we are inserting a tx at an index greater than our full list of shorttxids
|
||||
// plus the number of prefilled txn we've inserted, then we have txn for which we
|
||||
// have neither a prefilled txn or a shorttxid!
|
||||
return READ_STATUS_INVALID;
|
||||
}
|
||||
txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx;
|
||||
}
|
||||
prefilled_count = cmpctblock.prefilledtxn.size();
|
||||
|
||||
// Calculate map of txids -> positions and check mempool to see what we have (or don't)
|
||||
// Because well-formed cmpctblock messages will have a (relatively) uniform distribution
|
||||
// of short IDs, any highly-uneven distribution of elements can be safely treated as a
|
||||
// READ_STATUS_FAILED.
|
||||
std::unordered_map<uint64_t, uint16_t> shorttxids(cmpctblock.shorttxids.size());
|
||||
uint16_t index_offset = 0;
|
||||
for (size_t i = 0; i < cmpctblock.shorttxids.size(); i++) {
|
||||
while (txn_available[i + index_offset])
|
||||
index_offset++;
|
||||
shorttxids[cmpctblock.shorttxids[i]] = i + index_offset;
|
||||
// To determine the chance that the number of entries in a bucket exceeds N,
|
||||
// we use the fact that the number of elements in a single bucket is
|
||||
// binomially distributed (with n = the number of shorttxids S, and p =
|
||||
// 1 / the number of buckets), that in the worst case the number of buckets is
|
||||
// equal to S (due to std::unordered_map having a default load factor of 1.0),
|
||||
// and that the chance for any bucket to exceed N elements is at most
|
||||
// buckets * (the chance that any given bucket is above N elements).
|
||||
// Thus: P(max_elements_per_bucket > N) <= S * (1 - cdf(binomial(n=S,p=1/S), N)).
|
||||
// If we assume blocks of up to 16000, allowing 12 elements per bucket should
|
||||
// only fail once per ~1 million block transfers (per peer and connection).
|
||||
if (shorttxids.bucket_size(shorttxids.bucket(cmpctblock.shorttxids[i])) > 12)
|
||||
return READ_STATUS_FAILED;
|
||||
}
|
||||
// TODO: in the shortid-collision case, we should instead request both transactions
|
||||
// which collided. Falling back to full-block-request here is overkill.
|
||||
if (shorttxids.size() != cmpctblock.shorttxids.size())
|
||||
return READ_STATUS_FAILED; // Short ID collision
|
||||
|
||||
std::vector<bool> have_txn(txn_available.size());
|
||||
{
|
||||
LOCK(pool->cs);
|
||||
for (size_t i = 0; i < pool->vTxHashes.size(); i++) {
|
||||
uint64_t shortid = cmpctblock.GetShortID(pool->vTxHashes[i].first);
|
||||
std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);
|
||||
if (idit != shorttxids.end()) {
|
||||
if (!have_txn[idit->second]) {
|
||||
txn_available[idit->second] = pool->vTxHashes[i].second->GetSharedTx();
|
||||
have_txn[idit->second] = true;
|
||||
mempool_count++;
|
||||
} else {
|
||||
// If we find two mempool txn that match the short id, just request it.
|
||||
// This should be rare enough that the extra bandwidth doesn't matter,
|
||||
// but eating a round-trip due to FillBlock failure would be annoying
|
||||
if (txn_available[idit->second]) {
|
||||
txn_available[idit->second].reset();
|
||||
mempool_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Though ideally we'd continue scanning for the two-txn-match-shortid case,
|
||||
// the performance win of an early exit here is too good to pass up and worth
|
||||
// the extra risk.
|
||||
if (mempool_count == shorttxids.size())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < extra_txn.size(); i++) {
|
||||
uint64_t shortid = cmpctblock.GetShortID(extra_txn[i].first);
|
||||
std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);
|
||||
if (idit != shorttxids.end()) {
|
||||
if (!have_txn[idit->second]) {
|
||||
txn_available[idit->second] = extra_txn[i].second;
|
||||
have_txn[idit->second] = true;
|
||||
mempool_count++;
|
||||
extra_count++;
|
||||
} else {
|
||||
// If we find two mempool/extra txn that match the short id, just
|
||||
// request it.
|
||||
// This should be rare enough that the extra bandwidth doesn't matter,
|
||||
// but eating a round-trip due to FillBlock failure would be annoying
|
||||
// Note that we don't want duplication between extra_txn and mempool to
|
||||
// trigger this case, so we compare witness hashes first
|
||||
if (txn_available[idit->second] &&
|
||||
txn_available[idit->second]->GetWitnessHash() != extra_txn[i].second->GetWitnessHash()) {
|
||||
txn_available[idit->second].reset();
|
||||
mempool_count--;
|
||||
extra_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Though ideally we'd continue scanning for the two-txn-match-shortid case,
|
||||
// the performance win of an early exit here is too good to pass up and worth
|
||||
// the extra risk.
|
||||
if (mempool_count == shorttxids.size())
|
||||
break;
|
||||
}
|
||||
|
||||
LogPrint(BCLog::CMPCTBLOCK, "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, PROTOCOL_VERSION));
|
||||
|
||||
return READ_STATUS_OK;
|
||||
}
|
||||
|
||||
bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const {
|
||||
assert(!header.IsNull());
|
||||
assert(index < txn_available.size());
|
||||
return txn_available[index] != nullptr;
|
||||
}
|
||||
|
||||
ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing) {
|
||||
assert(!header.IsNull());
|
||||
uint256 hash = header.GetHash();
|
||||
block = header;
|
||||
block.vtx.resize(txn_available.size());
|
||||
|
||||
size_t tx_missing_offset = 0;
|
||||
for (size_t i = 0; i < txn_available.size(); i++) {
|
||||
if (!txn_available[i]) {
|
||||
if (vtx_missing.size() <= tx_missing_offset)
|
||||
return READ_STATUS_INVALID;
|
||||
block.vtx[i] = vtx_missing[tx_missing_offset++];
|
||||
} else
|
||||
block.vtx[i] = std::move(txn_available[i]);
|
||||
}
|
||||
|
||||
// Make sure we can't call FillBlock again.
|
||||
header.SetNull();
|
||||
txn_available.clear();
|
||||
|
||||
if (vtx_missing.size() != tx_missing_offset)
|
||||
return READ_STATUS_INVALID;
|
||||
|
||||
BlockValidationState state;
|
||||
if (!CheckBlock(block, state, Params().GetConsensus())) {
|
||||
// TODO: We really want to just check merkle tree manually here,
|
||||
// but that is expensive, and CheckBlock caches a block's
|
||||
// "checked-status" (in the CBlock?). CBlock should be able to
|
||||
// check its own merkle root and cache that check.
|
||||
if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED)
|
||||
return READ_STATUS_FAILED; // Possible Short ID collision
|
||||
return READ_STATUS_CHECKBLOCK_FAILED;
|
||||
}
|
||||
|
||||
LogPrint(BCLog::CMPCTBLOCK, "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool (incl at least %lu from extra pool) and %lu txn requested\n", hash.ToString(), prefilled_count, mempool_count, extra_count, vtx_missing.size());
|
||||
if (vtx_missing.size() < 5) {
|
||||
for (const auto& tx : vtx_missing) {
|
||||
LogPrint(BCLog::CMPCTBLOCK, "Reconstructed block %s required tx %s\n", hash.ToString(), tx->GetHash().ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return READ_STATUS_OK;
|
||||
}
|
||||
141
src/blockencodings.h
Normal file
141
src/blockencodings.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_BLOCKENCODINGS_H
|
||||
#define DIGIBYTE_BLOCKENCODINGS_H
|
||||
|
||||
#include <primitives/block.h>
|
||||
|
||||
|
||||
class CTxMemPool;
|
||||
|
||||
// Transaction compression schemes for compact block relay can be introduced by writing
|
||||
// an actual formatter here.
|
||||
using TransactionCompression = DefaultFormatter;
|
||||
|
||||
class DifferenceFormatter
|
||||
{
|
||||
uint64_t m_shift = 0;
|
||||
|
||||
public:
|
||||
template<typename Stream, typename I>
|
||||
void Ser(Stream& s, I v)
|
||||
{
|
||||
if (v < m_shift || v >= std::numeric_limits<uint64_t>::max()) throw std::ios_base::failure("differential value overflow");
|
||||
WriteCompactSize(s, v - m_shift);
|
||||
m_shift = uint64_t(v) + 1;
|
||||
}
|
||||
template<typename Stream, typename I>
|
||||
void Unser(Stream& s, I& v)
|
||||
{
|
||||
uint64_t n = ReadCompactSize(s);
|
||||
m_shift += n;
|
||||
if (m_shift < n || m_shift >= std::numeric_limits<uint64_t>::max() || m_shift < std::numeric_limits<I>::min() || m_shift > std::numeric_limits<I>::max()) throw std::ios_base::failure("differential value overflow");
|
||||
v = I(m_shift++);
|
||||
}
|
||||
};
|
||||
|
||||
class BlockTransactionsRequest {
|
||||
public:
|
||||
// A BlockTransactionsRequest message
|
||||
uint256 blockhash;
|
||||
std::vector<uint16_t> indexes;
|
||||
|
||||
SERIALIZE_METHODS(BlockTransactionsRequest, obj)
|
||||
{
|
||||
READWRITE(obj.blockhash, Using<VectorFormatter<DifferenceFormatter>>(obj.indexes));
|
||||
}
|
||||
};
|
||||
|
||||
class BlockTransactions {
|
||||
public:
|
||||
// A BlockTransactions message
|
||||
uint256 blockhash;
|
||||
std::vector<CTransactionRef> txn;
|
||||
|
||||
BlockTransactions() {}
|
||||
explicit BlockTransactions(const BlockTransactionsRequest& req) :
|
||||
blockhash(req.blockhash), txn(req.indexes.size()) {}
|
||||
|
||||
SERIALIZE_METHODS(BlockTransactions, obj)
|
||||
{
|
||||
READWRITE(obj.blockhash, Using<VectorFormatter<TransactionCompression>>(obj.txn));
|
||||
}
|
||||
};
|
||||
|
||||
// Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock
|
||||
struct PrefilledTransaction {
|
||||
// Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs,
|
||||
// as a proper transaction-in-block-index in PartiallyDownloadedBlock
|
||||
uint16_t index;
|
||||
CTransactionRef tx;
|
||||
|
||||
SERIALIZE_METHODS(PrefilledTransaction, obj) { READWRITE(COMPACTSIZE(obj.index), Using<TransactionCompression>(obj.tx)); }
|
||||
};
|
||||
|
||||
typedef enum ReadStatus_t
|
||||
{
|
||||
READ_STATUS_OK,
|
||||
READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap
|
||||
READ_STATUS_FAILED, // Failed to process object
|
||||
READ_STATUS_CHECKBLOCK_FAILED, // Used only by FillBlock to indicate a
|
||||
// failure in CheckBlock.
|
||||
} ReadStatus;
|
||||
|
||||
class CBlockHeaderAndShortTxIDs {
|
||||
private:
|
||||
mutable uint64_t shorttxidk0, shorttxidk1;
|
||||
uint64_t nonce;
|
||||
|
||||
void FillShortTxIDSelector() const;
|
||||
|
||||
friend class PartiallyDownloadedBlock;
|
||||
|
||||
protected:
|
||||
std::vector<uint64_t> shorttxids;
|
||||
std::vector<PrefilledTransaction> prefilledtxn;
|
||||
|
||||
public:
|
||||
static constexpr int SHORTTXIDS_LENGTH = 6;
|
||||
|
||||
CBlockHeader header;
|
||||
|
||||
// Dummy for deserialization
|
||||
CBlockHeaderAndShortTxIDs() {}
|
||||
|
||||
CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID);
|
||||
|
||||
uint64_t GetShortID(const uint256& txhash) const;
|
||||
|
||||
size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); }
|
||||
|
||||
SERIALIZE_METHODS(CBlockHeaderAndShortTxIDs, obj)
|
||||
{
|
||||
READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn);
|
||||
if (ser_action.ForRead()) {
|
||||
if (obj.BlockTxCount() > std::numeric_limits<uint16_t>::max()) {
|
||||
throw std::ios_base::failure("indexes overflowed 16 bits");
|
||||
}
|
||||
obj.FillShortTxIDSelector();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PartiallyDownloadedBlock {
|
||||
protected:
|
||||
std::vector<CTransactionRef> txn_available;
|
||||
size_t prefilled_count = 0, mempool_count = 0, extra_count = 0;
|
||||
const CTxMemPool* pool;
|
||||
public:
|
||||
CBlockHeader header;
|
||||
explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
|
||||
|
||||
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
|
||||
ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);
|
||||
bool IsTxAvailable(size_t index) const;
|
||||
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_BLOCKENCODINGS_H
|
||||
308
src/blockfilter.cpp
Normal file
308
src/blockfilter.cpp
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
// Copyright (c) 2018-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
|
||||
#include <blockfilter.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <hash.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/script.h>
|
||||
#include <streams.h>
|
||||
#include <util/golombrice.h>
|
||||
|
||||
/// SerType used to serialize parameters in GCS filter encoding.
|
||||
static constexpr int GCS_SER_TYPE = SER_NETWORK;
|
||||
|
||||
/// Protocol version used to serialize parameters in GCS filter encoding.
|
||||
static constexpr int GCS_SER_VERSION = 0;
|
||||
|
||||
static const std::map<BlockFilterType, std::string> g_filter_types = {
|
||||
{BlockFilterType::BASIC, "basic"},
|
||||
};
|
||||
|
||||
// Map a value x that is uniformly distributed in the range [0, 2^64) to a
|
||||
// value uniformly distributed in [0, n) by returning the upper 64 bits of
|
||||
// x * n.
|
||||
//
|
||||
// See: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
static uint64_t MapIntoRange(uint64_t x, uint64_t n)
|
||||
{
|
||||
#ifdef __SIZEOF_INT128__
|
||||
return (static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(n)) >> 64;
|
||||
#else
|
||||
// To perform the calculation on 64-bit numbers without losing the
|
||||
// result to overflow, split the numbers into the most significant and
|
||||
// least significant 32 bits and perform multiplication piece-wise.
|
||||
//
|
||||
// See: https://stackoverflow.com/a/26855440
|
||||
uint64_t x_hi = x >> 32;
|
||||
uint64_t x_lo = x & 0xFFFFFFFF;
|
||||
uint64_t n_hi = n >> 32;
|
||||
uint64_t n_lo = n & 0xFFFFFFFF;
|
||||
|
||||
uint64_t ac = x_hi * n_hi;
|
||||
uint64_t ad = x_hi * n_lo;
|
||||
uint64_t bc = x_lo * n_hi;
|
||||
uint64_t bd = x_lo * n_lo;
|
||||
|
||||
uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF);
|
||||
uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32);
|
||||
return upper64;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t GCSFilter::HashToRange(const Element& element) const
|
||||
{
|
||||
uint64_t hash = CSipHasher(m_params.m_siphash_k0, m_params.m_siphash_k1)
|
||||
.Write(element.data(), element.size())
|
||||
.Finalize();
|
||||
return MapIntoRange(hash, m_F);
|
||||
}
|
||||
|
||||
std::vector<uint64_t> GCSFilter::BuildHashedSet(const ElementSet& elements) const
|
||||
{
|
||||
std::vector<uint64_t> hashed_elements;
|
||||
hashed_elements.reserve(elements.size());
|
||||
for (const Element& element : elements) {
|
||||
hashed_elements.push_back(HashToRange(element));
|
||||
}
|
||||
std::sort(hashed_elements.begin(), hashed_elements.end());
|
||||
return hashed_elements;
|
||||
}
|
||||
|
||||
GCSFilter::GCSFilter(const Params& params)
|
||||
: m_params(params), m_N(0), m_F(0), m_encoded{0}
|
||||
{}
|
||||
|
||||
GCSFilter::GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter)
|
||||
: m_params(params), m_encoded(std::move(encoded_filter))
|
||||
{
|
||||
VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
|
||||
|
||||
uint64_t N = ReadCompactSize(stream);
|
||||
m_N = static_cast<uint32_t>(N);
|
||||
if (m_N != N) {
|
||||
throw std::ios_base::failure("N must be <2^32");
|
||||
}
|
||||
m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);
|
||||
|
||||
// Verify that the encoded filter contains exactly N elements. If it has too much or too little
|
||||
// data, a std::ios_base::failure exception will be raised.
|
||||
BitStreamReader<VectorReader> bitreader(stream);
|
||||
for (uint64_t i = 0; i < m_N; ++i) {
|
||||
GolombRiceDecode(bitreader, m_params.m_P);
|
||||
}
|
||||
if (!stream.empty()) {
|
||||
throw std::ios_base::failure("encoded_filter contains excess data");
|
||||
}
|
||||
}
|
||||
|
||||
GCSFilter::GCSFilter(const Params& params, const ElementSet& elements)
|
||||
: m_params(params)
|
||||
{
|
||||
size_t N = elements.size();
|
||||
m_N = static_cast<uint32_t>(N);
|
||||
if (m_N != N) {
|
||||
throw std::invalid_argument("N must be <2^32");
|
||||
}
|
||||
m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_params.m_M);
|
||||
|
||||
CVectorWriter stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
|
||||
|
||||
WriteCompactSize(stream, m_N);
|
||||
|
||||
if (elements.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BitStreamWriter<CVectorWriter> bitwriter(stream);
|
||||
|
||||
uint64_t last_value = 0;
|
||||
for (uint64_t value : BuildHashedSet(elements)) {
|
||||
uint64_t delta = value - last_value;
|
||||
GolombRiceEncode(bitwriter, m_params.m_P, delta);
|
||||
last_value = value;
|
||||
}
|
||||
|
||||
bitwriter.Flush();
|
||||
}
|
||||
|
||||
bool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const
|
||||
{
|
||||
VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
|
||||
|
||||
// Seek forward by size of N
|
||||
uint64_t N = ReadCompactSize(stream);
|
||||
assert(N == m_N);
|
||||
|
||||
BitStreamReader<VectorReader> bitreader(stream);
|
||||
|
||||
uint64_t value = 0;
|
||||
size_t hashes_index = 0;
|
||||
for (uint32_t i = 0; i < m_N; ++i) {
|
||||
uint64_t delta = GolombRiceDecode(bitreader, m_params.m_P);
|
||||
value += delta;
|
||||
|
||||
while (true) {
|
||||
if (hashes_index == size) {
|
||||
return false;
|
||||
} else if (element_hashes[hashes_index] == value) {
|
||||
return true;
|
||||
} else if (element_hashes[hashes_index] > value) {
|
||||
break;
|
||||
}
|
||||
|
||||
hashes_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GCSFilter::Match(const Element& element) const
|
||||
{
|
||||
uint64_t query = HashToRange(element);
|
||||
return MatchInternal(&query, 1);
|
||||
}
|
||||
|
||||
bool GCSFilter::MatchAny(const ElementSet& elements) const
|
||||
{
|
||||
const std::vector<uint64_t> queries = BuildHashedSet(elements);
|
||||
return MatchInternal(queries.data(), queries.size());
|
||||
}
|
||||
|
||||
const std::string& BlockFilterTypeName(BlockFilterType filter_type)
|
||||
{
|
||||
static std::string unknown_retval = "";
|
||||
auto it = g_filter_types.find(filter_type);
|
||||
return it != g_filter_types.end() ? it->second : unknown_retval;
|
||||
}
|
||||
|
||||
bool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type) {
|
||||
for (const auto& entry : g_filter_types) {
|
||||
if (entry.second == name) {
|
||||
filter_type = entry.first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::set<BlockFilterType>& AllBlockFilterTypes()
|
||||
{
|
||||
static std::set<BlockFilterType> types;
|
||||
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, []() {
|
||||
for (auto entry : g_filter_types) {
|
||||
types.insert(entry.first);
|
||||
}
|
||||
});
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
const std::string& ListBlockFilterTypes()
|
||||
{
|
||||
static std::string type_list;
|
||||
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, []() {
|
||||
std::stringstream ret;
|
||||
bool first = true;
|
||||
for (auto entry : g_filter_types) {
|
||||
if (!first) ret << ", ";
|
||||
ret << entry.second;
|
||||
first = false;
|
||||
}
|
||||
type_list = ret.str();
|
||||
});
|
||||
|
||||
return type_list;
|
||||
}
|
||||
|
||||
static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
|
||||
const CBlockUndo& block_undo)
|
||||
{
|
||||
GCSFilter::ElementSet elements;
|
||||
|
||||
for (const CTransactionRef& tx : block.vtx) {
|
||||
for (const CTxOut& txout : tx->vout) {
|
||||
const CScript& script = txout.scriptPubKey;
|
||||
if (script.empty() || script[0] == OP_RETURN) continue;
|
||||
elements.emplace(script.begin(), script.end());
|
||||
}
|
||||
}
|
||||
|
||||
for (const CTxUndo& tx_undo : block_undo.vtxundo) {
|
||||
for (const Coin& prevout : tx_undo.vprevout) {
|
||||
const CScript& script = prevout.out.scriptPubKey;
|
||||
if (script.empty()) continue;
|
||||
elements.emplace(script.begin(), script.end());
|
||||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
BlockFilter::BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
|
||||
std::vector<unsigned char> filter)
|
||||
: m_filter_type(filter_type), m_block_hash(block_hash)
|
||||
{
|
||||
GCSFilter::Params params;
|
||||
if (!BuildParams(params)) {
|
||||
throw std::invalid_argument("unknown filter_type");
|
||||
}
|
||||
m_filter = GCSFilter(params, std::move(filter));
|
||||
}
|
||||
|
||||
BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)
|
||||
: m_filter_type(filter_type), m_block_hash(block.GetHash())
|
||||
{
|
||||
GCSFilter::Params params;
|
||||
if (!BuildParams(params)) {
|
||||
throw std::invalid_argument("unknown filter_type");
|
||||
}
|
||||
m_filter = GCSFilter(params, BasicFilterElements(block, block_undo));
|
||||
}
|
||||
|
||||
bool BlockFilter::BuildParams(GCSFilter::Params& params) const
|
||||
{
|
||||
switch (m_filter_type) {
|
||||
case BlockFilterType::BASIC:
|
||||
params.m_siphash_k0 = m_block_hash.GetUint64(0);
|
||||
params.m_siphash_k1 = m_block_hash.GetUint64(1);
|
||||
params.m_P = BASIC_FILTER_P;
|
||||
params.m_M = BASIC_FILTER_M;
|
||||
return true;
|
||||
case BlockFilterType::INVALID:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint256 BlockFilter::GetHash() const
|
||||
{
|
||||
const std::vector<unsigned char>& data = GetEncodedFilter();
|
||||
|
||||
uint256 result;
|
||||
CHash256().Write(data).Finalize(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint256 BlockFilter::ComputeHeader(const uint256& prev_header) const
|
||||
{
|
||||
const uint256& filter_hash = GetHash();
|
||||
|
||||
uint256 result;
|
||||
CHash256()
|
||||
.Write(filter_hash)
|
||||
.Write(prev_header)
|
||||
.Finalize(result);
|
||||
return result;
|
||||
}
|
||||
171
src/blockfilter.h
Normal file
171
src/blockfilter.h
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (c) 2018-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_BLOCKFILTER_H
|
||||
#define DIGIBYTE_BLOCKFILTER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <primitives/block.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
#include <undo.h>
|
||||
#include <util/bytevectorhash.h>
|
||||
|
||||
/**
|
||||
* This implements a Golomb-coded set as defined in BIP 158. It is a
|
||||
* compact, probabilistic data structure for testing set membership.
|
||||
*/
|
||||
class GCSFilter
|
||||
{
|
||||
public:
|
||||
typedef std::vector<unsigned char> Element;
|
||||
typedef std::unordered_set<Element, ByteVectorHash> ElementSet;
|
||||
|
||||
struct Params
|
||||
{
|
||||
uint64_t m_siphash_k0;
|
||||
uint64_t m_siphash_k1;
|
||||
uint8_t m_P; //!< Golomb-Rice coding parameter
|
||||
uint32_t m_M; //!< Inverse false positive rate
|
||||
|
||||
Params(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0, uint32_t M = 1)
|
||||
: m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M)
|
||||
{}
|
||||
};
|
||||
|
||||
private:
|
||||
Params m_params;
|
||||
uint32_t m_N; //!< Number of elements in the filter
|
||||
uint64_t m_F; //!< Range of element hashes, F = N * M
|
||||
std::vector<unsigned char> m_encoded;
|
||||
|
||||
/** Hash a data element to an integer in the range [0, N * M). */
|
||||
uint64_t HashToRange(const Element& element) const;
|
||||
|
||||
std::vector<uint64_t> BuildHashedSet(const ElementSet& elements) const;
|
||||
|
||||
/** Helper method used to implement Match and MatchAny */
|
||||
bool MatchInternal(const uint64_t* sorted_element_hashes, size_t size) const;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructs an empty filter. */
|
||||
explicit GCSFilter(const Params& params = Params());
|
||||
|
||||
/** Reconstructs an already-created filter from an encoding. */
|
||||
GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter);
|
||||
|
||||
/** Builds a new filter from the params and set of elements. */
|
||||
GCSFilter(const Params& params, const ElementSet& elements);
|
||||
|
||||
uint32_t GetN() const { return m_N; }
|
||||
const Params& GetParams() const { return m_params; }
|
||||
const std::vector<unsigned char>& GetEncoded() const { return m_encoded; }
|
||||
|
||||
/**
|
||||
* Checks if the element may be in the set. False positives are possible
|
||||
* with probability 1/M.
|
||||
*/
|
||||
bool Match(const Element& element) const;
|
||||
|
||||
/**
|
||||
* Checks if any of the given elements may be in the set. False positives
|
||||
* are possible with probability 1/M per element checked. This is more
|
||||
* efficient that checking Match on multiple elements separately.
|
||||
*/
|
||||
bool MatchAny(const ElementSet& elements) const;
|
||||
};
|
||||
|
||||
constexpr uint8_t BASIC_FILTER_P = 19;
|
||||
constexpr uint32_t BASIC_FILTER_M = 784931;
|
||||
|
||||
enum class BlockFilterType : uint8_t
|
||||
{
|
||||
BASIC = 0,
|
||||
INVALID = 255,
|
||||
};
|
||||
|
||||
/** Get the human-readable name for a filter type. Returns empty string for unknown types. */
|
||||
const std::string& BlockFilterTypeName(BlockFilterType filter_type);
|
||||
|
||||
/** Find a filter type by its human-readable name. */
|
||||
bool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type);
|
||||
|
||||
/** Get a list of known filter types. */
|
||||
const std::set<BlockFilterType>& AllBlockFilterTypes();
|
||||
|
||||
/** Get a comma-separated list of known filter type names. */
|
||||
const std::string& ListBlockFilterTypes();
|
||||
|
||||
/**
|
||||
* Complete block filter struct as defined in BIP 157. Serialization matches
|
||||
* payload of "cfilter" messages.
|
||||
*/
|
||||
class BlockFilter
|
||||
{
|
||||
private:
|
||||
BlockFilterType m_filter_type = BlockFilterType::INVALID;
|
||||
uint256 m_block_hash;
|
||||
GCSFilter m_filter;
|
||||
|
||||
bool BuildParams(GCSFilter::Params& params) const;
|
||||
|
||||
public:
|
||||
|
||||
BlockFilter() = default;
|
||||
|
||||
//! Reconstruct a BlockFilter from parts.
|
||||
BlockFilter(BlockFilterType filter_type, const uint256& block_hash,
|
||||
std::vector<unsigned char> filter);
|
||||
|
||||
//! Construct a new BlockFilter of the specified type from a block.
|
||||
BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);
|
||||
|
||||
BlockFilterType GetFilterType() const { return m_filter_type; }
|
||||
const uint256& GetBlockHash() const { return m_block_hash; }
|
||||
const GCSFilter& GetFilter() const { return m_filter; }
|
||||
|
||||
const std::vector<unsigned char>& GetEncodedFilter() const
|
||||
{
|
||||
return m_filter.GetEncoded();
|
||||
}
|
||||
|
||||
//! Compute the filter hash.
|
||||
uint256 GetHash() const;
|
||||
|
||||
//! Compute the filter header given the previous one.
|
||||
uint256 ComputeHeader(const uint256& prev_header) const;
|
||||
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& s) const {
|
||||
s << static_cast<uint8_t>(m_filter_type)
|
||||
<< m_block_hash
|
||||
<< m_filter.GetEncoded();
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s) {
|
||||
std::vector<unsigned char> encoded_filter;
|
||||
uint8_t filter_type;
|
||||
|
||||
s >> filter_type
|
||||
>> m_block_hash
|
||||
>> encoded_filter;
|
||||
|
||||
m_filter_type = static_cast<BlockFilterType>(filter_type);
|
||||
|
||||
GCSFilter::Params params;
|
||||
if (!BuildParams(params)) {
|
||||
throw std::ios_base::failure("unknown filter_type");
|
||||
}
|
||||
m_filter = GCSFilter(params, std::move(encoded_filter));
|
||||
}
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_BLOCKFILTER_H
|
||||
277
src/bloom.cpp
Normal file
277
src/bloom.cpp
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bloom.h>
|
||||
|
||||
#include <primitives/transaction.h>
|
||||
#include <hash.h>
|
||||
#include <script/script.h>
|
||||
#include <script/standard.h>
|
||||
#include <random.h>
|
||||
#include <streams.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
|
||||
#define LN2 0.6931471805599453094172321214581765680755001343602552
|
||||
|
||||
CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn, unsigned char nFlagsIn) :
|
||||
/**
|
||||
* The ideal size for a bloom filter with a given number of elements and false positive rate is:
|
||||
* - nElements * log(fp rate) / ln(2)^2
|
||||
* We ignore filter parameters which will create a bloom filter larger than the protocol limits
|
||||
*/
|
||||
vData(std::min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
|
||||
/**
|
||||
* The ideal number of hash functions is filter size * ln(2) / number of elements
|
||||
* Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
|
||||
* See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
|
||||
*/
|
||||
nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
|
||||
nTweak(nTweakIn),
|
||||
nFlags(nFlagsIn)
|
||||
{
|
||||
}
|
||||
|
||||
inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
|
||||
{
|
||||
// 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
|
||||
return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
|
||||
}
|
||||
|
||||
void CBloomFilter::insert(const std::vector<unsigned char>& vKey)
|
||||
{
|
||||
if (vData.empty()) // Avoid divide-by-zero (CVE-2013-5700)
|
||||
return;
|
||||
for (unsigned int i = 0; i < nHashFuncs; i++)
|
||||
{
|
||||
unsigned int nIndex = Hash(i, vKey);
|
||||
// Sets bit nIndex of vData
|
||||
vData[nIndex >> 3] |= (1 << (7 & nIndex));
|
||||
}
|
||||
}
|
||||
|
||||
void CBloomFilter::insert(const COutPoint& outpoint)
|
||||
{
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << outpoint;
|
||||
std::vector<unsigned char> data(stream.begin(), stream.end());
|
||||
insert(data);
|
||||
}
|
||||
|
||||
void CBloomFilter::insert(const uint256& hash)
|
||||
{
|
||||
std::vector<unsigned char> data(hash.begin(), hash.end());
|
||||
insert(data);
|
||||
}
|
||||
|
||||
bool CBloomFilter::contains(const std::vector<unsigned char>& vKey) const
|
||||
{
|
||||
if (vData.empty()) // Avoid divide-by-zero (CVE-2013-5700)
|
||||
return true;
|
||||
for (unsigned int i = 0; i < nHashFuncs; i++)
|
||||
{
|
||||
unsigned int nIndex = Hash(i, vKey);
|
||||
// Checks bit nIndex of vData
|
||||
if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBloomFilter::contains(const COutPoint& outpoint) const
|
||||
{
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << outpoint;
|
||||
std::vector<unsigned char> data(stream.begin(), stream.end());
|
||||
return contains(data);
|
||||
}
|
||||
|
||||
bool CBloomFilter::contains(const uint256& hash) const
|
||||
{
|
||||
std::vector<unsigned char> data(hash.begin(), hash.end());
|
||||
return contains(data);
|
||||
}
|
||||
|
||||
bool CBloomFilter::IsWithinSizeConstraints() const
|
||||
{
|
||||
return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
|
||||
}
|
||||
|
||||
bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
|
||||
{
|
||||
bool fFound = false;
|
||||
// Match if the filter contains the hash of tx
|
||||
// for finding tx when they appear in a block
|
||||
if (vData.empty()) // zero-size = "match-all" filter
|
||||
return true;
|
||||
const uint256& hash = tx.GetHash();
|
||||
if (contains(hash))
|
||||
fFound = true;
|
||||
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++)
|
||||
{
|
||||
const CTxOut& txout = tx.vout[i];
|
||||
// Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
|
||||
// If this matches, also add the specific output that was matched.
|
||||
// This means clients don't have to update the filter themselves when a new relevant tx
|
||||
// is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
|
||||
CScript::const_iterator pc = txout.scriptPubKey.begin();
|
||||
std::vector<unsigned char> data;
|
||||
while (pc < txout.scriptPubKey.end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!txout.scriptPubKey.GetOp(pc, opcode, data))
|
||||
break;
|
||||
if (data.size() != 0 && contains(data))
|
||||
{
|
||||
fFound = true;
|
||||
if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
|
||||
insert(COutPoint(hash, i));
|
||||
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
|
||||
{
|
||||
std::vector<std::vector<unsigned char> > vSolutions;
|
||||
TxoutType type = Solver(txout.scriptPubKey, vSolutions);
|
||||
if (type == TxoutType::PUBKEY || type == TxoutType::MULTISIG) {
|
||||
insert(COutPoint(hash, i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fFound)
|
||||
return true;
|
||||
|
||||
for (const CTxIn& txin : tx.vin)
|
||||
{
|
||||
// Match if the filter contains an outpoint tx spends
|
||||
if (contains(txin.prevout))
|
||||
return true;
|
||||
|
||||
// Match if the filter contains any arbitrary script data element in any scriptSig in tx
|
||||
CScript::const_iterator pc = txin.scriptSig.begin();
|
||||
std::vector<unsigned char> data;
|
||||
while (pc < txin.scriptSig.end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!txin.scriptSig.GetOp(pc, opcode, data))
|
||||
break;
|
||||
if (data.size() != 0 && contains(data))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CRollingBloomFilter::CRollingBloomFilter(const unsigned int nElements, const double fpRate)
|
||||
{
|
||||
double logFpRate = log(fpRate);
|
||||
/* The optimal number of hash functions is log(fpRate) / log(0.5), but
|
||||
* restrict it to the range 1-50. */
|
||||
nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50));
|
||||
/* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */
|
||||
nEntriesPerGeneration = (nElements + 1) / 2;
|
||||
uint32_t nMaxElements = nEntriesPerGeneration * 3;
|
||||
/* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)
|
||||
* => pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)
|
||||
* => 1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)
|
||||
* => log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits
|
||||
* => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))
|
||||
* => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))
|
||||
*/
|
||||
uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
|
||||
data.clear();
|
||||
/* For each data element we need to store 2 bits. If both bits are 0, the
|
||||
* bit is treated as unset. If the bits are (01), (10), or (11), the bit is
|
||||
* treated as set in generation 1, 2, or 3 respectively.
|
||||
* These bits are stored in separate integers: position P corresponds to bit
|
||||
* (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */
|
||||
data.resize(((nFilterBits + 63) / 64) << 1);
|
||||
reset();
|
||||
}
|
||||
|
||||
/* Similar to CBloomFilter::Hash */
|
||||
static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, const std::vector<unsigned char>& vDataToHash) {
|
||||
return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash);
|
||||
}
|
||||
|
||||
|
||||
// A replacement for x % n. This assumes that x and n are 32bit integers, and x is a uniformly random distributed 32bit value
|
||||
// which should be the case for a good hash.
|
||||
// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
static inline uint32_t FastMod(uint32_t x, size_t n) {
|
||||
return ((uint64_t)x * (uint64_t)n) >> 32;
|
||||
}
|
||||
|
||||
void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
|
||||
{
|
||||
if (nEntriesThisGeneration == nEntriesPerGeneration) {
|
||||
nEntriesThisGeneration = 0;
|
||||
nGeneration++;
|
||||
if (nGeneration == 4) {
|
||||
nGeneration = 1;
|
||||
}
|
||||
uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1);
|
||||
uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1);
|
||||
/* Wipe old entries that used this generation number. */
|
||||
for (uint32_t p = 0; p < data.size(); p += 2) {
|
||||
uint64_t p1 = data[p], p2 = data[p + 1];
|
||||
uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);
|
||||
data[p] = p1 & mask;
|
||||
data[p + 1] = p2 & mask;
|
||||
}
|
||||
}
|
||||
nEntriesThisGeneration++;
|
||||
|
||||
for (int n = 0; n < nHashFuncs; n++) {
|
||||
uint32_t h = RollingBloomHash(n, nTweak, vKey);
|
||||
int bit = h & 0x3F;
|
||||
/* FastMod works with the upper bits of h, so it is safe to ignore that the lower bits of h are already used for bit. */
|
||||
uint32_t pos = FastMod(h, data.size());
|
||||
/* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
|
||||
data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;
|
||||
data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;
|
||||
}
|
||||
}
|
||||
|
||||
void CRollingBloomFilter::insert(const uint256& hash)
|
||||
{
|
||||
std::vector<unsigned char> vData(hash.begin(), hash.end());
|
||||
insert(vData);
|
||||
}
|
||||
|
||||
bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
|
||||
{
|
||||
for (int n = 0; n < nHashFuncs; n++) {
|
||||
uint32_t h = RollingBloomHash(n, nTweak, vKey);
|
||||
int bit = h & 0x3F;
|
||||
uint32_t pos = FastMod(h, data.size());
|
||||
/* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
|
||||
if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CRollingBloomFilter::contains(const uint256& hash) const
|
||||
{
|
||||
std::vector<unsigned char> vData(hash.begin(), hash.end());
|
||||
return contains(vData);
|
||||
}
|
||||
|
||||
void CRollingBloomFilter::reset()
|
||||
{
|
||||
nTweak = GetRand(std::numeric_limits<unsigned int>::max());
|
||||
nEntriesThisGeneration = 0;
|
||||
nGeneration = 1;
|
||||
std::fill(data.begin(), data.end(), 0);
|
||||
}
|
||||
132
src/bloom.h
Normal file
132
src/bloom.h
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_BLOOM_H
|
||||
#define DIGIBYTE_BLOOM_H
|
||||
|
||||
#include <serialize.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class COutPoint;
|
||||
class CTransaction;
|
||||
class uint256;
|
||||
|
||||
//! 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001%
|
||||
static const unsigned int MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
||||
static const unsigned int MAX_HASH_FUNCS = 50;
|
||||
|
||||
/**
|
||||
* First two bits of nFlags control how much IsRelevantAndUpdate actually updates
|
||||
* The remaining bits are reserved
|
||||
*/
|
||||
enum bloomflags
|
||||
{
|
||||
BLOOM_UPDATE_NONE = 0,
|
||||
BLOOM_UPDATE_ALL = 1,
|
||||
// Only adds outpoints to the filter if the output is a pay-to-pubkey/pay-to-multisig script
|
||||
BLOOM_UPDATE_P2PUBKEY_ONLY = 2,
|
||||
BLOOM_UPDATE_MASK = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* BloomFilter is a probabilistic filter which SPV clients provide
|
||||
* so that we can filter the transactions we send them.
|
||||
*
|
||||
* This allows for significantly more efficient transaction and block downloads.
|
||||
*
|
||||
* Because bloom filters are probabilistic, a SPV node can increase the false-
|
||||
* positive rate, making us send it transactions which aren't actually its,
|
||||
* allowing clients to trade more bandwidth for more privacy by obfuscating which
|
||||
* keys are controlled by them.
|
||||
*/
|
||||
class CBloomFilter
|
||||
{
|
||||
private:
|
||||
std::vector<unsigned char> vData;
|
||||
unsigned int nHashFuncs;
|
||||
unsigned int nTweak;
|
||||
unsigned char nFlags;
|
||||
|
||||
unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new bloom filter which will provide the given fp rate when filled with the given number of elements
|
||||
* Note that if the given parameters will result in a filter outside the bounds of the protocol limits,
|
||||
* the filter created will be as close to the given parameters as possible within the protocol limits.
|
||||
* This will apply if nFPRate is very low or nElements is unreasonably high.
|
||||
* nTweak is a constant which is added to the seed value passed to the hash function
|
||||
* It should generally always be a random value (and is largely only exposed for unit testing)
|
||||
* nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK)
|
||||
*/
|
||||
CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweak, unsigned char nFlagsIn);
|
||||
CBloomFilter() : nHashFuncs(0), nTweak(0), nFlags(0) {}
|
||||
|
||||
SERIALIZE_METHODS(CBloomFilter, obj) { READWRITE(obj.vData, obj.nHashFuncs, obj.nTweak, obj.nFlags); }
|
||||
|
||||
void insert(const std::vector<unsigned char>& vKey);
|
||||
void insert(const COutPoint& outpoint);
|
||||
void insert(const uint256& hash);
|
||||
|
||||
bool contains(const std::vector<unsigned char>& vKey) const;
|
||||
bool contains(const COutPoint& outpoint) const;
|
||||
bool contains(const uint256& hash) const;
|
||||
|
||||
//! True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS
|
||||
//! (catch a filter which was just deserialized which was too big)
|
||||
bool IsWithinSizeConstraints() const;
|
||||
|
||||
//! Also adds any outputs which match the filter to the filter (to match their spending txes)
|
||||
bool IsRelevantAndUpdate(const CTransaction& tx);
|
||||
};
|
||||
|
||||
/**
|
||||
* RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
|
||||
* Construct it with the number of items to keep track of, and a false-positive
|
||||
* rate. Unlike CBloomFilter, by default nTweak is set to a cryptographically
|
||||
* secure random value for you. Similarly rather than clear() the method
|
||||
* reset() is provided, which also changes nTweak to decrease the impact of
|
||||
* false-positives.
|
||||
*
|
||||
* contains(item) will always return true if item was one of the last N to 1.5*N
|
||||
* insert()'ed ... but may also return true for items that were not inserted.
|
||||
*
|
||||
* It needs around 1.8 bytes per element per factor 0.1 of false positive rate.
|
||||
* For example, if we want 1000 elements, we'd need:
|
||||
* - ~1800 bytes for a false positive rate of 0.1
|
||||
* - ~3600 bytes for a false positive rate of 0.01
|
||||
* - ~5400 bytes for a false positive rate of 0.001
|
||||
*
|
||||
* If we make these simplifying assumptions:
|
||||
* - logFpRate / log(0.5) doesn't get rounded or clamped in the nHashFuncs calculation
|
||||
* - nElements is even, so that nEntriesPerGeneration == nElements / 2
|
||||
*
|
||||
* Then we get a more accurate estimate for filter bytes:
|
||||
*
|
||||
* 3/(log(256)*log(2)) * log(1/fpRate) * nElements
|
||||
*/
|
||||
class CRollingBloomFilter
|
||||
{
|
||||
public:
|
||||
CRollingBloomFilter(const unsigned int nElements, const double nFPRate);
|
||||
|
||||
void insert(const std::vector<unsigned char>& vKey);
|
||||
void insert(const uint256& hash);
|
||||
bool contains(const std::vector<unsigned char>& vKey) const;
|
||||
bool contains(const uint256& hash) const;
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
int nEntriesPerGeneration;
|
||||
int nEntriesThisGeneration;
|
||||
int nGeneration;
|
||||
std::vector<uint64_t> data;
|
||||
unsigned int nTweak;
|
||||
int nHashFuncs;
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_BLOOM_H
|
||||
203
src/chain.cpp
Normal file
203
src/chain.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <chain.h>
|
||||
#include <chainparams.h>
|
||||
#include <validation.h>
|
||||
|
||||
// Include whatever header actually declares LogPrintf in your codebase.
|
||||
// In DigiByte, it might be "logging.h" or "util/system.h". Adjust as needed:
|
||||
#include <logging.h> // or #include <util/system.h> or #include "util.h"
|
||||
|
||||
/**
|
||||
* CBlockIndex default constructor
|
||||
*/
|
||||
CBlockIndex::CBlockIndex()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* CBlockIndex constructor that copies from a block header.
|
||||
* We can safely call LogPrintf here because we are in a .cpp file that includes logging.
|
||||
*/
|
||||
CBlockIndex::CBlockIndex(const CBlockHeader& block)
|
||||
: nVersion(block.nVersion),
|
||||
hashMerkleRoot(block.hashMerkleRoot),
|
||||
nTime(block.nTime),
|
||||
nBits(block.nBits),
|
||||
nNonce(block.nNonce)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CChain::SetTip(CBlockIndex *pindex) {
|
||||
if (pindex == nullptr) {
|
||||
vChain.clear();
|
||||
return;
|
||||
}
|
||||
vChain.resize(pindex->nHeight + 1);
|
||||
while (pindex && vChain[pindex->nHeight] != pindex) {
|
||||
vChain[pindex->nHeight] = pindex;
|
||||
pindex = pindex->pprev;
|
||||
}
|
||||
}
|
||||
|
||||
CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
|
||||
int nStep = 1;
|
||||
std::vector<uint256> vHave;
|
||||
vHave.reserve(32);
|
||||
|
||||
if (!pindex)
|
||||
pindex = Tip();
|
||||
while (pindex) {
|
||||
vHave.push_back(pindex->GetBlockHash());
|
||||
// Stop when we have added the genesis block.
|
||||
if (pindex->nHeight == 0)
|
||||
break;
|
||||
// Exponentially larger steps back, plus the genesis block.
|
||||
int nHeight = std::max(pindex->nHeight - nStep, 0);
|
||||
if (Contains(pindex)) {
|
||||
// Use O(1) CChain index if possible.
|
||||
pindex = (*this)[nHeight];
|
||||
} else {
|
||||
// Otherwise, use O(log n) skiplist.
|
||||
pindex = pindex->GetAncestor(nHeight);
|
||||
}
|
||||
if (vHave.size() > 10)
|
||||
nStep *= 2;
|
||||
}
|
||||
|
||||
return CBlockLocator(vHave);
|
||||
}
|
||||
|
||||
const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
|
||||
if (pindex == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (pindex->nHeight > Height())
|
||||
pindex = pindex->GetAncestor(Height());
|
||||
while (pindex && !Contains(pindex))
|
||||
pindex = pindex->pprev;
|
||||
return pindex;
|
||||
}
|
||||
|
||||
CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime, int height) const
|
||||
{
|
||||
std::pair<int64_t, int> blockparams = std::make_pair(nTime, height);
|
||||
auto lower = std::lower_bound(
|
||||
vChain.begin(), vChain.end(), blockparams,
|
||||
[](CBlockIndex* pBlock, const std::pair<int64_t, int>& bp) {
|
||||
return pBlock->GetBlockTimeMax() < bp.first || pBlock->nHeight < bp.second;
|
||||
}
|
||||
);
|
||||
return (lower == vChain.end() ? nullptr : *lower);
|
||||
}
|
||||
|
||||
/** Turn the lowest '1' bit in the binary representation of a number into '0'. */
|
||||
int static inline InvertLowestOne(int n) { return n & (n - 1); }
|
||||
|
||||
/** Compute what height to jump back to with the CBlockIndex::pskip pointer. */
|
||||
int static inline GetSkipHeight(int height) {
|
||||
if (height < 2)
|
||||
return 0;
|
||||
|
||||
return (height & 1)
|
||||
? InvertLowestOne(InvertLowestOne(height - 1)) + 1
|
||||
: InvertLowestOne(height);
|
||||
}
|
||||
|
||||
const CBlockIndex* CBlockIndex::GetAncestor(int height) const
|
||||
{
|
||||
if (height > nHeight || height < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const CBlockIndex* pindexWalk = this;
|
||||
int heightWalk = nHeight;
|
||||
while (heightWalk > height) {
|
||||
int heightSkip = GetSkipHeight(heightWalk);
|
||||
int heightSkipPrev = GetSkipHeight(heightWalk - 1);
|
||||
if (pindexWalk->pskip != nullptr &&
|
||||
(heightSkip == height ||
|
||||
(heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
|
||||
heightSkipPrev >= height)))) {
|
||||
// Only follow pskip if pprev->pskip isn't better than pskip->pprev.
|
||||
pindexWalk = pindexWalk->pskip;
|
||||
heightWalk = heightSkip;
|
||||
} else {
|
||||
assert(pindexWalk->pprev);
|
||||
pindexWalk = pindexWalk->pprev;
|
||||
heightWalk--;
|
||||
}
|
||||
}
|
||||
return pindexWalk;
|
||||
}
|
||||
|
||||
CBlockIndex* CBlockIndex::GetAncestor(int height)
|
||||
{
|
||||
return const_cast<CBlockIndex*>(static_cast<const CBlockIndex*>(this)->GetAncestor(height));
|
||||
}
|
||||
|
||||
void CBlockIndex::BuildSkip()
|
||||
{
|
||||
if (pprev)
|
||||
pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
|
||||
}
|
||||
|
||||
arith_uint256 GetBlockProofBase(const CBlockIndex& block)
|
||||
{
|
||||
arith_uint256 bnTarget;
|
||||
bool fNegative;
|
||||
bool fOverflow;
|
||||
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
|
||||
if (fNegative || fOverflow || bnTarget == 0)
|
||||
return 0;
|
||||
|
||||
// 2**256 / (bnTarget+1)
|
||||
return (~bnTarget / (bnTarget + 1)) + 1;
|
||||
}
|
||||
|
||||
arith_uint256 GetBlockProof(const CBlockIndex& block)
|
||||
{
|
||||
// Vexta is SHA256D-only, so block proof is based only on this block's nBits.
|
||||
return GetBlockProofBase(block);
|
||||
}
|
||||
|
||||
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from,
|
||||
const CBlockIndex& tip, const Consensus::Params& params)
|
||||
{
|
||||
arith_uint256 r;
|
||||
int sign = 1;
|
||||
if (to.nChainWork > from.nChainWork) {
|
||||
r = to.nChainWork - from.nChainWork;
|
||||
} else {
|
||||
r = from.nChainWork - to.nChainWork;
|
||||
sign = -1;
|
||||
}
|
||||
r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);
|
||||
if (r.bits() > 63) {
|
||||
return sign * std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
return sign * r.GetLow64();
|
||||
}
|
||||
|
||||
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb)
|
||||
{
|
||||
if (pa->nHeight > pb->nHeight) {
|
||||
pa = pa->GetAncestor(pb->nHeight);
|
||||
} else if (pb->nHeight > pa->nHeight) {
|
||||
pb = pb->GetAncestor(pa->nHeight);
|
||||
}
|
||||
|
||||
while (pa != pb && pa && pb) {
|
||||
pa = pa->pprev;
|
||||
pb = pb->pprev;
|
||||
}
|
||||
|
||||
// Eventually all chain branches meet at the genesis block.
|
||||
assert(pa == pb);
|
||||
return pa;
|
||||
}
|
||||
454
src/chain.h
Normal file
454
src/chain.h
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_CHAIN_H
|
||||
#define DIGIBYTE_CHAIN_H
|
||||
|
||||
#include <arith_uint256.h>
|
||||
#include <consensus/params.h>
|
||||
#include <flatfile.h>
|
||||
#include <primitives/block.h>
|
||||
#include <pow.h>
|
||||
#include <tinyformat.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Maximum amount of time that a block timestamp is allowed to exceed the
|
||||
* current network-adjusted time before the block will be accepted.
|
||||
*/
|
||||
static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
|
||||
|
||||
/**
|
||||
* Timestamp window used as a grace period by code that compares external
|
||||
* timestamps (such as timestamps passed to RPCs, or wallet key creation times)
|
||||
* to block timestamps. This should be set at least as high as
|
||||
* MAX_FUTURE_BLOCK_TIME.
|
||||
*/
|
||||
static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
|
||||
|
||||
/**
|
||||
* Maximum gap between node time and block time used
|
||||
* for the "Catching up..." mode in GUI.
|
||||
*
|
||||
* Ref: https://github.com/digibyte/digibyte/pull/1026
|
||||
*/
|
||||
static constexpr int64_t MAX_BLOCK_TIME_GAP = 90 * 60;
|
||||
|
||||
class CBlockFileInfo
|
||||
{
|
||||
public:
|
||||
unsigned int nBlocks; //!< number of blocks stored in file
|
||||
unsigned int nSize; //!< number of used bytes of block file
|
||||
unsigned int nUndoSize; //!< number of used bytes in the undo file
|
||||
unsigned int nHeightFirst; //!< lowest height of block in file
|
||||
unsigned int nHeightLast; //!< highest height of block in file
|
||||
uint64_t nTimeFirst; //!< earliest time of block in file
|
||||
uint64_t nTimeLast; //!< latest time of block in file
|
||||
|
||||
SERIALIZE_METHODS(CBlockFileInfo, obj)
|
||||
{
|
||||
READWRITE(VARINT(obj.nBlocks));
|
||||
READWRITE(VARINT(obj.nSize));
|
||||
READWRITE(VARINT(obj.nUndoSize));
|
||||
READWRITE(VARINT(obj.nHeightFirst));
|
||||
READWRITE(VARINT(obj.nHeightLast));
|
||||
READWRITE(VARINT(obj.nTimeFirst));
|
||||
READWRITE(VARINT(obj.nTimeLast));
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
nBlocks = 0;
|
||||
nSize = 0;
|
||||
nUndoSize = 0;
|
||||
nHeightFirst = 0;
|
||||
nHeightLast = 0;
|
||||
nTimeFirst = 0;
|
||||
nTimeLast = 0;
|
||||
}
|
||||
|
||||
CBlockFileInfo() {
|
||||
SetNull();
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
/** update statistics (does not update nSize) */
|
||||
void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
|
||||
if (nBlocks==0 || nHeightFirst > nHeightIn)
|
||||
nHeightFirst = nHeightIn;
|
||||
if (nBlocks==0 || nTimeFirst > nTimeIn)
|
||||
nTimeFirst = nTimeIn;
|
||||
nBlocks++;
|
||||
if (nHeightIn > nHeightLast)
|
||||
nHeightLast = nHeightIn;
|
||||
if (nTimeIn > nTimeLast)
|
||||
nTimeLast = nTimeIn;
|
||||
}
|
||||
};
|
||||
|
||||
enum BlockStatus: uint32_t {
|
||||
//! Unused.
|
||||
BLOCK_VALID_UNKNOWN = 0,
|
||||
|
||||
//! Reserved (was BLOCK_VALID_HEADER).
|
||||
BLOCK_VALID_RESERVED = 1,
|
||||
|
||||
//! All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents
|
||||
//! are also at least TREE.
|
||||
BLOCK_VALID_TREE = 2,
|
||||
|
||||
/**
|
||||
* Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids,
|
||||
* sigops, size, merkle root. Implies all parents are at least TREE but not necessarily TRANSACTIONS. When all
|
||||
* parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will be set.
|
||||
*/
|
||||
BLOCK_VALID_TRANSACTIONS = 3,
|
||||
|
||||
//! Outputs do not overspend inputs, no double spends, coinbase output ok, no immature coinbase spends, BIP30.
|
||||
//! Implies all parents are also at least CHAIN.
|
||||
BLOCK_VALID_CHAIN = 4,
|
||||
|
||||
//! Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
|
||||
BLOCK_VALID_SCRIPTS = 5,
|
||||
|
||||
//! All validity bits.
|
||||
BLOCK_VALID_MASK = BLOCK_VALID_RESERVED | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
|
||||
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
|
||||
|
||||
BLOCK_HAVE_DATA = 8, //!< full block available in blk*.dat
|
||||
BLOCK_HAVE_UNDO = 16, //!< undo data available in rev*.dat
|
||||
BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO,
|
||||
|
||||
BLOCK_FAILED_VALID = 32, //!< stage after last reached validness failed
|
||||
BLOCK_FAILED_CHILD = 64, //!< descends from failed block
|
||||
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
|
||||
|
||||
BLOCK_OPT_WITNESS = 128, //!< block data in blk*.data was received with a witness-enforcing client
|
||||
};
|
||||
|
||||
/** The block chain is a tree shaped structure starting with the
|
||||
* genesis block at the root, with each block potentially having multiple
|
||||
* candidates to be the next block. A blockindex may have multiple pprev pointing
|
||||
* to it, but at most one of them can be part of the currently active branch.
|
||||
*/
|
||||
class CBlockIndex
|
||||
{
|
||||
public:
|
||||
//! pointer to the hash of the block, if any. Memory is owned by this CBlockIndex
|
||||
const uint256* phashBlock{nullptr};
|
||||
|
||||
//! pointer to the index of the predecessor of this block
|
||||
CBlockIndex* pprev{nullptr};
|
||||
|
||||
//! pointer to the index of some further predecessor of this block
|
||||
CBlockIndex* pskip{nullptr};
|
||||
|
||||
//! height of the entry in the chain. The genesis block has height 0
|
||||
int nHeight{0};
|
||||
|
||||
//! Which # file this block is stored in (blk?????.dat)
|
||||
int nFile{0};
|
||||
|
||||
//! Byte offset within blk?????.dat where this block's data is stored
|
||||
unsigned int nDataPos{0};
|
||||
|
||||
//! Byte offset within rev?????.dat where this block's undo data is stored
|
||||
unsigned int nUndoPos{0};
|
||||
|
||||
//! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
|
||||
arith_uint256 nChainWork{};
|
||||
|
||||
//! Number of transactions in this block.
|
||||
//! Note: in a potential headers-first mode, this number cannot be relied upon
|
||||
//! Note: this value is faked during UTXO snapshot load to ensure that
|
||||
//! LoadBlockIndex() will load index entries for blocks that we lack data for.
|
||||
//! @sa ActivateSnapshot
|
||||
unsigned int nTx{0};
|
||||
|
||||
//! (memory only) Number of transactions in the chain up to and including this block.
|
||||
//! This value will be non-zero only if and only if transactions for this block and all its parents are available.
|
||||
//! Change to 64-bit type when necessary; won't happen before 2030
|
||||
//!
|
||||
//! Note: this value is faked during use of a UTXO snapshot because we don't
|
||||
//! have the underlying block data available during snapshot load.
|
||||
//! @sa AssumeutxoData
|
||||
//! @sa ActivateSnapshot
|
||||
unsigned int nChainTx{0};
|
||||
|
||||
//! Verification status of this block. See enum BlockStatus
|
||||
//!
|
||||
//! Note: this value is modified to show BLOCK_OPT_WITNESS during UTXO snapshot
|
||||
//! load to avoid the block index being spuriously rewound.
|
||||
//! @sa NeedsRedownload
|
||||
//! @sa ActivateSnapshot
|
||||
uint32_t nStatus{0};
|
||||
|
||||
//! block header
|
||||
int32_t nVersion{0};
|
||||
uint256 hashMerkleRoot{};
|
||||
uint32_t nTime{0};
|
||||
uint32_t nBits{0};
|
||||
uint32_t nNonce{0};
|
||||
|
||||
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
|
||||
int32_t nSequenceId{0};
|
||||
|
||||
//! (memory only) Maximum nTime in the chain up to and including this block.
|
||||
unsigned int nTimeMax{0};
|
||||
|
||||
/**
|
||||
* Default constructor (no header):
|
||||
*/
|
||||
CBlockIndex();
|
||||
|
||||
/**
|
||||
* Full constructor that copies fields from a block header.
|
||||
* (Definition is moved to chain.cpp so we can log from there)
|
||||
*/
|
||||
explicit CBlockIndex(const CBlockHeader& block);
|
||||
|
||||
FlatFilePos GetBlockPos() const {
|
||||
FlatFilePos ret;
|
||||
if (nStatus & BLOCK_HAVE_DATA) {
|
||||
ret.nFile = nFile;
|
||||
ret.nPos = nDataPos;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
FlatFilePos GetUndoPos() const {
|
||||
FlatFilePos ret;
|
||||
if (nStatus & BLOCK_HAVE_UNDO) {
|
||||
ret.nFile = nFile;
|
||||
ret.nPos = nUndoPos;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CBlockHeader GetBlockHeader() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
block.nVersion = nVersion;
|
||||
if (pprev)
|
||||
block.hashPrevBlock = pprev->GetBlockHash();
|
||||
block.hashMerkleRoot = hashMerkleRoot;
|
||||
block.nTime = nTime;
|
||||
block.nBits = nBits;
|
||||
block.nNonce = nNonce;
|
||||
return block;
|
||||
}
|
||||
|
||||
uint256 GetBlockHash() const
|
||||
{
|
||||
return *phashBlock;
|
||||
}
|
||||
|
||||
uint256 GetBlockPoWHash() const
|
||||
{
|
||||
CBlockHeader block = GetBlockHeader();
|
||||
return block.GetHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this block's and all previous blocks' transactions have been
|
||||
* downloaded (and stored to disk) at some point.
|
||||
*
|
||||
* Does not imply the transactions are consensus-valid (ConnectTip might fail)
|
||||
* Does not imply the transactions are still stored on disk. (IsBlockPruned might return true)
|
||||
*/
|
||||
|
||||
bool HaveTxsDownloaded() const { return nChainTx != 0; }
|
||||
|
||||
int64_t GetBlockTime() const
|
||||
{
|
||||
return (int64_t)nTime;
|
||||
}
|
||||
|
||||
int64_t GetBlockTimeMax() const
|
||||
{
|
||||
return (int64_t)nTimeMax;
|
||||
}
|
||||
|
||||
static constexpr int nMedianTimeSpan = 11;
|
||||
|
||||
int64_t GetMedianTimePast() const
|
||||
{
|
||||
int64_t pmedian[nMedianTimeSpan];
|
||||
int64_t* pbegin = &pmedian[nMedianTimeSpan];
|
||||
int64_t* pend = &pmedian[nMedianTimeSpan];
|
||||
|
||||
const CBlockIndex* pindex = this;
|
||||
for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
|
||||
*(--pbegin) = pindex->GetBlockTime();
|
||||
|
||||
std::sort(pbegin, pend);
|
||||
return pbegin[(pend - pbegin)/2];
|
||||
}
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
|
||||
pprev, nHeight,
|
||||
hashMerkleRoot.ToString(),
|
||||
GetBlockHash().ToString());
|
||||
}
|
||||
|
||||
//! Check whether this block index entry is valid up to the passed validity level.
|
||||
bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const
|
||||
{
|
||||
assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.
|
||||
if (nStatus & BLOCK_FAILED_MASK)
|
||||
return false;
|
||||
return ((nStatus & BLOCK_VALID_MASK) >= nUpTo);
|
||||
}
|
||||
|
||||
//! Raise the validity level of this block index entry.
|
||||
//! Returns true if the validity was changed.
|
||||
bool RaiseValidity(enum BlockStatus nUpTo)
|
||||
{
|
||||
assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.
|
||||
if (nStatus & BLOCK_FAILED_MASK)
|
||||
return false;
|
||||
if ((nStatus & BLOCK_VALID_MASK) < nUpTo) {
|
||||
nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//! Build the skiplist pointer for this entry.
|
||||
void BuildSkip();
|
||||
|
||||
//! Efficiently find an ancestor of this block.
|
||||
CBlockIndex* GetAncestor(int height);
|
||||
const CBlockIndex* GetAncestor(int height) const;
|
||||
};
|
||||
|
||||
arith_uint256 GetBlockProof(const CBlockIndex& block);
|
||||
|
||||
/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */
|
||||
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&);
|
||||
/** Find the forking point between two chain tips. */
|
||||
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb);
|
||||
|
||||
|
||||
/** Used to marshal pointers into hashes for db storage. */
|
||||
class CDiskBlockIndex : public CBlockIndex
|
||||
{
|
||||
public:
|
||||
uint256 hashPrev;
|
||||
|
||||
CDiskBlockIndex() {
|
||||
hashPrev = uint256();
|
||||
}
|
||||
|
||||
explicit CDiskBlockIndex(const CBlockIndex* pindex) : CBlockIndex(*pindex) {
|
||||
hashPrev = (pprev ? pprev->GetBlockHash() : uint256());
|
||||
}
|
||||
|
||||
SERIALIZE_METHODS(CDiskBlockIndex, obj)
|
||||
{
|
||||
int _nVersion = s.GetVersion();
|
||||
if (!(s.GetType() & SER_GETHASH)) READWRITE(VARINT_MODE(_nVersion, VarIntMode::NONNEGATIVE_SIGNED));
|
||||
|
||||
READWRITE(VARINT_MODE(obj.nHeight, VarIntMode::NONNEGATIVE_SIGNED));
|
||||
READWRITE(VARINT(obj.nStatus));
|
||||
READWRITE(VARINT(obj.nTx));
|
||||
if (obj.nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) READWRITE(VARINT_MODE(obj.nFile, VarIntMode::NONNEGATIVE_SIGNED));
|
||||
if (obj.nStatus & BLOCK_HAVE_DATA) READWRITE(VARINT(obj.nDataPos));
|
||||
if (obj.nStatus & BLOCK_HAVE_UNDO) READWRITE(VARINT(obj.nUndoPos));
|
||||
|
||||
// block header
|
||||
READWRITE(obj.nVersion);
|
||||
READWRITE(obj.hashPrev);
|
||||
READWRITE(obj.hashMerkleRoot);
|
||||
READWRITE(obj.nTime);
|
||||
READWRITE(obj.nBits);
|
||||
READWRITE(obj.nNonce);
|
||||
}
|
||||
|
||||
uint256 GetBlockHash() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
block.nVersion = nVersion;
|
||||
block.hashPrevBlock = hashPrev;
|
||||
block.hashMerkleRoot = hashMerkleRoot;
|
||||
block.nTime = nTime;
|
||||
block.nBits = nBits;
|
||||
block.nNonce = nNonce;
|
||||
return block.GetHash();
|
||||
}
|
||||
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
std::string str = "CDiskBlockIndex(";
|
||||
str += CBlockIndex::ToString();
|
||||
str += strprintf("\n hashBlock=%s, hashPrev=%s)",
|
||||
GetBlockHash().ToString(),
|
||||
hashPrev.ToString());
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
/** An in-memory indexed chain of blocks. */
|
||||
class CChain {
|
||||
private:
|
||||
std::vector<CBlockIndex*> vChain;
|
||||
|
||||
public:
|
||||
/** Returns the index entry for the genesis block of this chain, or nullptr if none. */
|
||||
CBlockIndex *Genesis() const {
|
||||
return vChain.size() > 0 ? vChain[0] : nullptr;
|
||||
}
|
||||
|
||||
/** Returns the index entry for the tip of this chain, or nullptr if none. */
|
||||
CBlockIndex *Tip() const {
|
||||
return vChain.size() > 0 ? vChain[vChain.size() - 1] : nullptr;
|
||||
}
|
||||
|
||||
/** Returns the index entry at a particular height in this chain, or nullptr if no such height exists. */
|
||||
CBlockIndex *operator[](int nHeight) const {
|
||||
if (nHeight < 0 || nHeight >= (int)vChain.size())
|
||||
return nullptr;
|
||||
return vChain[nHeight];
|
||||
}
|
||||
|
||||
/** Efficiently check whether a block is present in this chain. */
|
||||
bool Contains(const CBlockIndex *pindex) const {
|
||||
return (*this)[pindex->nHeight] == pindex;
|
||||
}
|
||||
|
||||
/** Find the successor of a block in this chain, or nullptr if the given index is not found or is the tip. */
|
||||
CBlockIndex *Next(const CBlockIndex *pindex) const {
|
||||
if (Contains(pindex))
|
||||
return (*this)[pindex->nHeight + 1];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */
|
||||
int Height() const {
|
||||
return vChain.size() - 1;
|
||||
}
|
||||
|
||||
/** Set/initialize a chain with a given tip. */
|
||||
void SetTip(CBlockIndex *pindex);
|
||||
|
||||
/** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
|
||||
CBlockLocator GetLocator(const CBlockIndex *pindex = nullptr) const;
|
||||
|
||||
/** Find the last common block between this chain and a block index entry. */
|
||||
const CBlockIndex *FindFork(const CBlockIndex *pindex) const;
|
||||
|
||||
/** Find the earliest block with timestamp equal or greater than the given time and height equal or greater than the given height. */
|
||||
CBlockIndex* FindEarliestAtLeast(int64_t nTime, int height) const;
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_CHAIN_H
|
||||
632
src/chainparams.cpp
Normal file
632
src/chainparams.cpp
Normal file
|
|
@ -0,0 +1,632 @@
|
|||
// Copyright (c) 2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2026 The Vexta Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "arith_uint256.h"
|
||||
#include <chainparams.h>
|
||||
|
||||
#include <chainparamsseeds.h>
|
||||
#include <consensus/merkle.h>
|
||||
#include <deploymentinfo.h>
|
||||
#include <hash.h> // for signet block challenge hash
|
||||
#include <util/system.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
|
||||
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
|
||||
{
|
||||
CMutableTransaction txNew;
|
||||
txNew.nVersion = 1;
|
||||
txNew.vin.resize(1);
|
||||
txNew.vout.resize(1);
|
||||
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
|
||||
txNew.vout[0].nValue = genesisReward;
|
||||
txNew.vout[0].scriptPubKey = CScript() << 0x0 << OP_CHECKSIG;
|
||||
|
||||
CBlock genesis;
|
||||
genesis.nTime = nTime;
|
||||
genesis.nBits = nBits;
|
||||
genesis.nNonce = nNonce;
|
||||
genesis.nVersion = nVersion;
|
||||
genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));
|
||||
genesis.hashPrevBlock.SetNull();
|
||||
genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
|
||||
return genesis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the genesis block. Note that the output of its generation
|
||||
* transaction cannot be spent since it did not originally exist in the
|
||||
* database.
|
||||
*
|
||||
* CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
|
||||
* CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
|
||||
* CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
|
||||
* CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
|
||||
* vMerkleTree: 4a5e1e
|
||||
*/
|
||||
static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
|
||||
{
|
||||
const char* pszTimestamp = "Vexta Genesis Block 29/Jun/2026 - VTX network begins";
|
||||
const CScript genesisOutputScript = CScript() << 0x0 << OP_CHECKSIG;
|
||||
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main network on which people trade goods and services.
|
||||
*/
|
||||
class CMainParams : public CChainParams {
|
||||
public:
|
||||
CMainParams() {
|
||||
strNetworkID = CBaseChainParams::MAIN;
|
||||
consensus.signet_blocks = false;
|
||||
consensus.signet_challenge.clear();
|
||||
consensus.BIP16Exception = uint256S("0x0");
|
||||
|
||||
// BIP34, BIP65 and BIP66, CSV and Segwit were activated simultaneously
|
||||
// DEPLOYMENT_NVERSIONBIPS, DEPLOYMENT_CSV, DEPLOYMENT_SEGWIT
|
||||
consensus.BIP34Hash = uint256S("0xadd8ca420f557f62377ec2be6e6f47b96cf2e68160d58aeb7b73433de834cca0");
|
||||
consensus.BIP34Height = consensus.BIP65Height = consensus.BIP66Height = 1; // Vexta: active from block 1
|
||||
consensus.CSVHeight = consensus.SegwitHeight = 1; // Vexta: active from block 1
|
||||
|
||||
|
||||
consensus.powLimit = ArithToUint256(~arith_uint256(0) >> 20);
|
||||
consensus.nPowTargetSpacing = 10 * 60;
|
||||
consensus.nSubsidyHalvingInterval = 210000; // ~4 years at 10 minute blocks
|
||||
consensus.fPowAllowMinDifficultyBlocks = false;
|
||||
consensus.fEasyPow = false;
|
||||
consensus.fPowNoRetargeting = false;
|
||||
consensus.fRbfEnabled = false;
|
||||
|
||||
// Vexta consensus parameters
|
||||
consensus.nRuleChangeActivationThreshold = 28224; // 28224 - 70% of 40320 blocks
|
||||
consensus.nMinerConfirmationWindow = 40320; // 1 week of blocks
|
||||
|
||||
// Suppress unknown activation warnings before the configured warning height
|
||||
consensus.MinBIP9WarningHeight = 1; // Vexta: deployments are active from launch
|
||||
|
||||
// Vexta protocol activation heights
|
||||
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 27;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
|
||||
|
||||
// Deployment of Taproot (BIPs 340-342)
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
|
||||
|
||||
// The best chain should have at least this much work.
|
||||
consensus.nMinimumChainWork = uint256{};
|
||||
|
||||
// By default assume that the signatures in ancestors of this block are valid.
|
||||
consensus.defaultAssumeValid = uint256{};
|
||||
|
||||
/**
|
||||
* The message start string is designed to be unlikely to occur in normal data.
|
||||
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
|
||||
* a large 32-bit integer with any alignment.
|
||||
*/
|
||||
pchMessageStart[0] = 0x56; // V
|
||||
pchMessageStart[1] = 0x54; // T
|
||||
pchMessageStart[2] = 0x58; // X
|
||||
pchMessageStart[3] = 0x31; // 1
|
||||
nDefaultPort = 19333;
|
||||
nPruneAfterHeight = 100000;
|
||||
m_assumed_blockchain_size = 0;
|
||||
m_assumed_chain_state_size = 0;
|
||||
|
||||
genesis = CreateGenesisBlock(1782770400, 1605828, 0x1e0ffff0, BLOCK_VERSION_SHA256D, 50 * COIN);
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
assert(consensus.hashGenesisBlock == uint256S("0x0000027626959d894ae1c8a6f9050cdcbdf58eb0037ab06345cb5502955370f1"));
|
||||
assert(genesis.hashMerkleRoot == uint256S("0x3c1f602428f06c9baf0961930a5f711a2b5fd6157a9922365e7f1eca1970ff16"));
|
||||
|
||||
// DNS seeds will be added after the first public Vexta seed nodes are deployed.
|
||||
|
||||
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,70);
|
||||
base58Prefixes[SCRIPT_ADDRESS_OLD] = std::vector<unsigned char>(1,85);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,85);
|
||||
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,198);
|
||||
base58Prefixes[SECRET_KEY_OLD] = std::vector<unsigned char>(1,199);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
|
||||
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
|
||||
|
||||
bech32_hrp = "vtx";
|
||||
|
||||
vFixedSeeds.clear(); // Vexta: no hardcoded seeds yet
|
||||
|
||||
fDefaultConsistencyChecks = false;
|
||||
fRequireStandard = true;
|
||||
m_is_test_chain = false;
|
||||
m_is_mockable_chain = false;
|
||||
|
||||
checkpointData = {
|
||||
{
|
||||
{0, consensus.hashGenesisBlock},
|
||||
}
|
||||
};
|
||||
|
||||
chainTxData = ChainTxData{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
// Vexta difficulty parameters.
|
||||
//
|
||||
// Vexta uses a single SHA256D proof-of-work algorithm with a moving
|
||||
// averaging window for difficulty adjustment.
|
||||
|
||||
|
||||
consensus.difficultyAveragingWindow = 10; // 10 blocks
|
||||
consensus.difficultyTargetTimespan = consensus.difficultyAveragingWindow * consensus.nPowTargetSpacing;
|
||||
|
||||
|
||||
consensus.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 100;
|
||||
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Testnet (v3): public test network which is reset from time to time.
|
||||
*/
|
||||
class CTestNetParams : public CChainParams {
|
||||
public:
|
||||
CTestNetParams() {
|
||||
strNetworkID = "test";
|
||||
consensus.powLimit = ArithToUint256(~arith_uint256(0) >> 20);
|
||||
consensus.nPowTargetSpacing = 10 * 60;
|
||||
consensus.nSubsidyHalvingInterval = 210000; // ~4 years at 10 minute blocks
|
||||
|
||||
consensus.BIP16Exception = uint256();
|
||||
consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests)
|
||||
consensus.BIP34Hash = uint256();
|
||||
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in functional tests)
|
||||
consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in functional tests)
|
||||
consensus.CSVHeight = 1; // CSV activated on regtest (Used in rpc activation tests)
|
||||
consensus.SegwitHeight = 0; // SEGWIT is always activated on regtest unless overridden
|
||||
|
||||
consensus.MinBIP9WarningHeight = 0;
|
||||
|
||||
// Vexta difficulty parameters.
|
||||
//
|
||||
// Vexta uses a single SHA256D proof-of-work algorithm with a moving
|
||||
// averaging window for difficulty adjustment.
|
||||
|
||||
|
||||
consensus.difficultyAveragingWindow = 10; // 10 blocks
|
||||
consensus.difficultyTargetTimespan = consensus.difficultyAveragingWindow * consensus.nPowTargetSpacing;
|
||||
|
||||
|
||||
consensus.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 100;
|
||||
|
||||
|
||||
|
||||
// Vexta protocol activation heights
|
||||
|
||||
consensus.fPowAllowMinDifficultyBlocks = true;
|
||||
consensus.fEasyPow = false;
|
||||
consensus.fPowNoRetargeting = true;
|
||||
consensus.nRuleChangeActivationThreshold = 4032; // 4032 - 70% of 5760
|
||||
consensus.nMinerConfirmationWindow = 5760; // 1 day of blocks on testnet
|
||||
consensus.fRbfEnabled = false;
|
||||
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 27;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1619222400; // April 24th, 2021
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1628640000; // August 11th, 2021
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
|
||||
|
||||
// Deployment of Taproot (BIPs 340-342)
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1718921304; // 20th June 2024 Testnet
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1750457304; // 20th June 2025 Testnet
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
|
||||
|
||||
|
||||
// The best chain should have at least this much work.
|
||||
consensus.nMinimumChainWork = uint256{};
|
||||
|
||||
// By default assume that the signatures in ancestors of this block are valid.
|
||||
consensus.defaultAssumeValid = uint256{};
|
||||
|
||||
pchMessageStart[0] = 0x56; // V
|
||||
pchMessageStart[1] = 0x54; // T
|
||||
pchMessageStart[2] = 0x58; // X
|
||||
pchMessageStart[3] = 0x54; // T
|
||||
nDefaultPort = 12026;
|
||||
nPruneAfterHeight = 1000;
|
||||
m_assumed_blockchain_size = 0;
|
||||
m_assumed_chain_state_size = 0;
|
||||
|
||||
genesis = CreateGenesisBlock("Vexta Testnet Genesis Block 09/Jul/2026 - VTX test network begins", CScript() << 0x0 << OP_CHECKSIG, 1783555200, 2228323, 0x1e0ffff0, 1, 50 * COIN);
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
assert(consensus.hashGenesisBlock == uint256S("0x00000dc74b41d5ebb73e55098e160534f34ec418becf4a3aa5bb218e6055cca5"));
|
||||
assert(genesis.hashMerkleRoot == uint256S("0x0fba2f6943df4ab9ffd13b5cf1233a825e364d2228a4683a72866b47d6a767c7"));
|
||||
|
||||
vFixedSeeds.clear();
|
||||
vSeeds.clear();
|
||||
|
||||
// DNS seeds will be added after public Vexta testnet seed nodes are deployed.
|
||||
|
||||
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,126);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,140);
|
||||
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,254);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
|
||||
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
|
||||
|
||||
bech32_hrp = "vtxt";
|
||||
|
||||
vFixedSeeds.clear(); // Vexta: no hardcoded testnet seeds yet
|
||||
|
||||
fDefaultConsistencyChecks = false;
|
||||
fRequireStandard = false;
|
||||
m_is_test_chain = true;
|
||||
m_is_mockable_chain = false;
|
||||
|
||||
checkpointData = {
|
||||
{
|
||||
{0, consensus.hashGenesisBlock},
|
||||
}
|
||||
};
|
||||
|
||||
m_assumeutxo_data = MapAssumeutxo{};
|
||||
|
||||
chainTxData = ChainTxData{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Signet: test network with an additional consensus parameter (see BIP325).
|
||||
*/
|
||||
class SigNetParams : public CChainParams {
|
||||
public:
|
||||
explicit SigNetParams(const ArgsManager& args) {
|
||||
std::vector<uint8_t> bin;
|
||||
vSeeds.clear();
|
||||
|
||||
if (!args.IsArgSet("-signetchallenge")) {
|
||||
bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
|
||||
// DNS seeds will be added after first public Vexta signet seed nodes are online.
|
||||
|
||||
consensus.nMinimumChainWork = uint256{};
|
||||
consensus.defaultAssumeValid = uint256{};
|
||||
m_assumed_blockchain_size = 0;
|
||||
m_assumed_chain_state_size = 0;
|
||||
chainTxData = ChainTxData{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
} else {
|
||||
const auto signet_challenge = args.GetArgs("-signetchallenge");
|
||||
if (signet_challenge.size() != 1) {
|
||||
throw std::runtime_error(strprintf("%s: -signetchallenge cannot be multiple values.", __func__));
|
||||
}
|
||||
bin = ParseHex(signet_challenge[0]);
|
||||
|
||||
consensus.nMinimumChainWork = uint256{};
|
||||
consensus.defaultAssumeValid = uint256{};
|
||||
m_assumed_blockchain_size = 0;
|
||||
m_assumed_chain_state_size = 0;
|
||||
chainTxData = ChainTxData{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
LogPrintf("Signet with challenge %s\n", signet_challenge[0]);
|
||||
}
|
||||
|
||||
if (args.IsArgSet("-signetseednode")) {
|
||||
vSeeds = args.GetArgs("-signetseednode");
|
||||
}
|
||||
|
||||
strNetworkID = CBaseChainParams::SIGNET;
|
||||
consensus.signet_blocks = true;
|
||||
consensus.signet_challenge.assign(bin.begin(), bin.end());
|
||||
consensus.BIP16Exception = uint256{};
|
||||
consensus.BIP34Height = 1;
|
||||
consensus.BIP34Hash = uint256{};
|
||||
consensus.BIP65Height = 1;
|
||||
consensus.BIP66Height = 1;
|
||||
consensus.CSVHeight = 1;
|
||||
consensus.SegwitHeight = 1;
|
||||
consensus.nPowTargetSpacing = 10 * 60;
|
||||
consensus.nSubsidyHalvingInterval = 210000; // ~4 years at 10 minute blocks
|
||||
consensus.fPowAllowMinDifficultyBlocks = false;
|
||||
consensus.fEasyPow = false;
|
||||
consensus.fPowNoRetargeting = false;
|
||||
consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
|
||||
consensus.nMinerConfirmationWindow = 2016; // legacy Bitcoin confirmation window
|
||||
consensus.fRbfEnabled = false;
|
||||
|
||||
consensus.MinBIP9WarningHeight = 0;
|
||||
consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 27;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
|
||||
|
||||
// Activation of Taproot (BIPs 340-342)
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
|
||||
|
||||
// message start is defined as the first 4 bytes of the sha256d of the block script
|
||||
CHashWriter h(SER_DISK, 0);
|
||||
h << consensus.signet_challenge;
|
||||
uint256 hash = h.GetHash();
|
||||
memcpy(pchMessageStart, hash.begin(), 4);
|
||||
|
||||
nDefaultPort = 38443;
|
||||
nPruneAfterHeight = 1000;
|
||||
|
||||
genesis = CreateGenesisBlock("Vexta Signet Genesis Block 09/Jul/2026 - VTX signet network begins", CScript() << 0x0 << OP_CHECKSIG, 1783555202, 4047966, 0x1e0377ae, 1, 50 * COIN);
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
|
||||
assert(consensus.hashGenesisBlock == uint256S("0x00000297613fa90675b13ac95d0590e95f787b15410ee3e568d7bc9df796c3c4"));
|
||||
assert(genesis.hashMerkleRoot == uint256S("0xd4764aaa54047c0408946a09f43c28b167988604619d055854bc89d51bcb736e"));
|
||||
|
||||
vFixedSeeds.clear();
|
||||
|
||||
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,126);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,140);
|
||||
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,254);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
|
||||
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
|
||||
|
||||
bech32_hrp = "vtxt";
|
||||
|
||||
fDefaultConsistencyChecks = false;
|
||||
fRequireStandard = true;
|
||||
m_is_test_chain = true;
|
||||
m_is_mockable_chain = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Regression test: intended for private networks only. Has minimal difficulty to ensure that
|
||||
* blocks can be found instantly.
|
||||
*/
|
||||
class CRegTestParams : public CChainParams {
|
||||
public:
|
||||
explicit CRegTestParams(const ArgsManager& args) {
|
||||
strNetworkID = CBaseChainParams::REGTEST;
|
||||
consensus.signet_blocks = false;
|
||||
consensus.signet_challenge.clear();
|
||||
consensus.BIP16Exception = uint256();
|
||||
consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests)
|
||||
consensus.BIP34Hash = uint256();
|
||||
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in functional tests)
|
||||
consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in functional tests)
|
||||
consensus.CSVHeight = 432; // CSV activated on regtest (Used in rpc activation tests)
|
||||
consensus.SegwitHeight = 0; // SEGWIT is always activated on regtest unless overridden
|
||||
consensus.MinBIP9WarningHeight = 0;
|
||||
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
consensus.fPowAllowMinDifficultyBlocks = true;
|
||||
consensus.fEasyPow = false; // allow easy blocks on regtest (can be set with -easypow)
|
||||
consensus.nPowTargetSpacing = 10 * 60;
|
||||
consensus.nSubsidyHalvingInterval = 210000; // ~4 years at 10 minute blocks
|
||||
|
||||
consensus.difficultyAveragingWindow = 10; // 10 blocks
|
||||
consensus.difficultyTargetTimespan = consensus.difficultyAveragingWindow * consensus.nPowTargetSpacing;
|
||||
|
||||
|
||||
consensus.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 100;
|
||||
|
||||
|
||||
consensus.BIP65Height = 1351;
|
||||
consensus.BIP66Height = 1251;
|
||||
|
||||
// Vexta protocol activation heights
|
||||
consensus.nRuleChangeActivationThreshold = 168; // 70% of 240
|
||||
consensus.nMinerConfirmationWindow = 240; // 1 hour in RegTest
|
||||
consensus.fRbfEnabled = false;
|
||||
|
||||
consensus.fPowNoRetargeting = true;
|
||||
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 27;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
|
||||
|
||||
// Activation of Taproot (BIPs 340-342)
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
|
||||
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
|
||||
|
||||
consensus.nMinimumChainWork = uint256{};
|
||||
consensus.defaultAssumeValid = uint256{};
|
||||
|
||||
|
||||
pchMessageStart[0] = 0x56; // V
|
||||
pchMessageStart[1] = 0x54; // T
|
||||
pchMessageStart[2] = 0x58; // X
|
||||
pchMessageStart[3] = 0x52; // R
|
||||
nDefaultPort = 18444;
|
||||
nPruneAfterHeight = args.GetBoolArg("-fastprune", false) ? 100 : 1000;
|
||||
m_assumed_blockchain_size = 0;
|
||||
m_assumed_chain_state_size = 0;
|
||||
|
||||
bech32_hrp = "vtxrt";
|
||||
|
||||
UpdateActivationParametersFromArgs(args);
|
||||
|
||||
genesis = CreateGenesisBlock("Vexta Regtest Genesis Block 09/Jul/2026 - VTX regression test network begins", CScript() << 0x0 << OP_CHECKSIG, 1783555201, 5, 0x207fffff, 1, 50 * COIN);
|
||||
consensus.hashGenesisBlock = genesis.GetHash();
|
||||
|
||||
assert(consensus.hashGenesisBlock == uint256S("0x3b5c0230bafd65f3dabcda2a30f33cdef0c3cda635e7440bda6909bb581462b7"));
|
||||
assert(genesis.hashMerkleRoot == uint256S("0x1d7df76c2482ecb39a9347895f012dd0d03696f064feb4b484d5bdb4f33cd924"));
|
||||
|
||||
vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
|
||||
vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds.
|
||||
|
||||
fDefaultConsistencyChecks = true;
|
||||
fRequireStandard = true;
|
||||
m_is_test_chain = true;
|
||||
m_is_mockable_chain = true;
|
||||
|
||||
checkpointData = {
|
||||
{
|
||||
{0, consensus.hashGenesisBlock},
|
||||
}
|
||||
};
|
||||
|
||||
m_assumeutxo_data = MapAssumeutxo{};
|
||||
|
||||
chainTxData = ChainTxData{
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,126);
|
||||
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,140);
|
||||
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,254);
|
||||
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
|
||||
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
|
||||
}
|
||||
/**
|
||||
* Allows modifying the Version Bits regtest parameters.
|
||||
*/
|
||||
void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout, int min_activation_height)
|
||||
{
|
||||
consensus.vDeployments[d].nStartTime = nStartTime;
|
||||
consensus.vDeployments[d].nTimeout = nTimeout;
|
||||
consensus.vDeployments[d].min_activation_height = min_activation_height;
|
||||
}
|
||||
void UpdateActivationParametersFromArgs(const ArgsManager& args);
|
||||
};
|
||||
|
||||
static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& consensus)
|
||||
{
|
||||
for (const std::string& arg : args.GetArgs("-testactivationheight")) {
|
||||
const auto found{arg.find('@')};
|
||||
if (found == std::string::npos) {
|
||||
throw std::runtime_error(strprintf("Invalid format (%s) for -testactivationheight=name@height.", arg));
|
||||
}
|
||||
const auto name{arg.substr(0, found)};
|
||||
const auto value{arg.substr(found + 1)};
|
||||
int32_t height;
|
||||
if (!ParseInt32(value, &height) || height < 0 || height >= std::numeric_limits<int>::max()) {
|
||||
throw std::runtime_error(strprintf("Invalid height value (%s) for -testactivationheight=name@height.", arg));
|
||||
}
|
||||
if (name == "segwit") {
|
||||
consensus.SegwitHeight = int{height};
|
||||
} else if (name == "bip34") {
|
||||
consensus.BIP34Height = int{height};
|
||||
} else if (name == "dersig") {
|
||||
consensus.BIP66Height = int{height};
|
||||
} else if (name == "cltv") {
|
||||
consensus.BIP65Height = int{height};
|
||||
} else if (name == "csv") {
|
||||
consensus.CSVHeight = int{height};
|
||||
} else {
|
||||
throw std::runtime_error(strprintf("Invalid name (%s) for -testactivationheight=name@height.", arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method was added to enable easy mining on regtest networks only.
|
||||
// it will be easy to mine blocks in regtest network.
|
||||
// This method can only be applied to RegTest networks by design and is called from
|
||||
// `CRegTestParams::UpdateActivationParametersFromArgs`
|
||||
static void MaybeEnableEasyMining(const ArgsManager& args, Consensus::Params& consensus)
|
||||
{
|
||||
if (!args.IsArgSet("-easypow")) return;
|
||||
|
||||
consensus.fEasyPow = true;
|
||||
consensus.fPowAllowMinDifficultyBlocks = true;
|
||||
|
||||
|
||||
// Delay new difficulty retargeting algorithm.
|
||||
// This will also delay have fixed subsidy as follows:
|
||||
// else nSubsidy = 8000 * COIN;
|
||||
|
||||
// Delay softforks
|
||||
consensus.BIP34Height = 1000000;
|
||||
consensus.CSVHeight = 1000000;
|
||||
}
|
||||
|
||||
void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
|
||||
{
|
||||
MaybeEnableEasyMining(args, consensus);
|
||||
MaybeUpdateHeights(args, consensus);
|
||||
|
||||
if (!args.IsArgSet("-vbparams")) return;
|
||||
|
||||
for (const std::string& strDeployment : args.GetArgs("-vbparams")) {
|
||||
std::vector<std::string> vDeploymentParams;
|
||||
boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":"));
|
||||
if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) {
|
||||
throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]");
|
||||
}
|
||||
int64_t nStartTime, nTimeout;
|
||||
int min_activation_height = 0;
|
||||
if (!ParseInt64(vDeploymentParams[1], &nStartTime)) {
|
||||
throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1]));
|
||||
}
|
||||
if (!ParseInt64(vDeploymentParams[2], &nTimeout)) {
|
||||
throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2]));
|
||||
}
|
||||
if (vDeploymentParams.size() >= 4 && !ParseInt32(vDeploymentParams[3], &min_activation_height)) {
|
||||
throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3]));
|
||||
}
|
||||
bool found = false;
|
||||
for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
|
||||
if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) {
|
||||
UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout, min_activation_height);
|
||||
found = true;
|
||||
LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], nStartTime, nTimeout, min_activation_height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw std::runtime_error(strprintf("Invalid deployment (%s)", vDeploymentParams[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<const CChainParams> globalChainParams;
|
||||
|
||||
const CChainParams &Params() {
|
||||
assert(globalChainParams);
|
||||
return *globalChainParams;
|
||||
}
|
||||
|
||||
std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const std::string& chain)
|
||||
{
|
||||
if (chain == CBaseChainParams::MAIN) {
|
||||
return std::unique_ptr<CChainParams>(new CMainParams());
|
||||
} else if (chain == CBaseChainParams::TESTNET) {
|
||||
return std::unique_ptr<CChainParams>(new CTestNetParams());
|
||||
} else if (chain == CBaseChainParams::SIGNET) {
|
||||
return std::unique_ptr<CChainParams>(new SigNetParams(args));
|
||||
} else if (chain == CBaseChainParams::REGTEST) {
|
||||
return std::unique_ptr<CChainParams>(new CRegTestParams(args));
|
||||
}
|
||||
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
||||
}
|
||||
|
||||
void SelectParams(const std::string& network)
|
||||
{
|
||||
SelectBaseParams(network);
|
||||
globalChainParams = CreateChainParams(gArgs, network);
|
||||
}
|
||||
171
src/chainparams.h
Normal file
171
src/chainparams.h
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_CHAINPARAMS_H
|
||||
#define DIGIBYTE_CHAINPARAMS_H
|
||||
|
||||
#include <chainparamsbase.h>
|
||||
#include <consensus/params.h>
|
||||
#include <netaddress.h>
|
||||
#include <primitives/block.h>
|
||||
#include <protocol.h>
|
||||
#include <util/hash_type.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef std::map<int, uint256> MapCheckpoints;
|
||||
|
||||
struct CCheckpointData {
|
||||
MapCheckpoints mapCheckpoints;
|
||||
|
||||
int GetHeight() const {
|
||||
const auto& final_checkpoint = mapCheckpoints.rbegin();
|
||||
return final_checkpoint->first /* height */;
|
||||
}
|
||||
};
|
||||
|
||||
struct AssumeutxoHash : public BaseHash<uint256> {
|
||||
explicit AssumeutxoHash(const uint256& hash) : BaseHash(hash) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds configuration for use during UTXO snapshot load and validation. The contents
|
||||
* here are security critical, since they dictate which UTXO snapshots are recognized
|
||||
* as valid.
|
||||
*/
|
||||
struct AssumeutxoData {
|
||||
//! The expected hash of the deserialized UTXO set.
|
||||
const AssumeutxoHash hash_serialized;
|
||||
|
||||
//! Used to populate the nChainTx value, which is used during BlockManager::LoadBlockIndex().
|
||||
//!
|
||||
//! We need to hardcode the value here because this is computed cumulatively using block data,
|
||||
//! which we do not necessarily have at the time of snapshot load.
|
||||
const unsigned int nChainTx;
|
||||
};
|
||||
|
||||
using MapAssumeutxo = std::map<int, const AssumeutxoData>;
|
||||
|
||||
/**
|
||||
* Holds various statistics on transactions within a chain. Used to estimate
|
||||
* verification progress during chain sync.
|
||||
*
|
||||
* See also: CChainParams::TxData, GuessVerificationProgress.
|
||||
*/
|
||||
struct ChainTxData {
|
||||
int64_t nTime; //!< UNIX timestamp of last known number of transactions
|
||||
int64_t nTxCount; //!< total number of transactions between genesis and that timestamp
|
||||
double dTxRate; //!< estimated number of transactions per second after that timestamp
|
||||
};
|
||||
|
||||
/**
|
||||
* CChainParams defines various tweakable parameters of a given instance of the
|
||||
* DigiByte system.
|
||||
*/
|
||||
class CChainParams
|
||||
{
|
||||
public:
|
||||
enum Base58Type {
|
||||
PUBKEY_ADDRESS,
|
||||
SCRIPT_ADDRESS,
|
||||
SCRIPT_ADDRESS_OLD,
|
||||
SECRET_KEY,
|
||||
SECRET_KEY_OLD,
|
||||
EXT_PUBLIC_KEY,
|
||||
EXT_SECRET_KEY,
|
||||
|
||||
MAX_BASE58_TYPES
|
||||
};
|
||||
|
||||
const Consensus::Params& GetConsensus() const { return consensus; }
|
||||
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
|
||||
uint16_t GetDefaultPort() const { return nDefaultPort; }
|
||||
uint16_t GetDefaultPort(Network net) const
|
||||
{
|
||||
return net == NET_I2P ? I2P_SAM31_PORT : GetDefaultPort();
|
||||
}
|
||||
uint16_t GetDefaultPort(const std::string& addr) const
|
||||
{
|
||||
CNetAddr a;
|
||||
return a.SetSpecial(addr) ? GetDefaultPort(a.GetNetwork()) : GetDefaultPort();
|
||||
}
|
||||
|
||||
const CBlock& GenesisBlock() const { return genesis; }
|
||||
/** Default value for -checkmempool and -checkblockindex argument */
|
||||
bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
|
||||
/** Policy: Filter transactions that do not match well-defined patterns */
|
||||
bool RequireStandard() const { return fRequireStandard; }
|
||||
/** If this chain is exclusively used for testing */
|
||||
bool IsTestChain() const { return m_is_test_chain; }
|
||||
/** If this chain allows time to be mocked */
|
||||
bool IsMockableChain() const { return m_is_mockable_chain; }
|
||||
uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
|
||||
/** Minimum free space (in GB) needed for data directory */
|
||||
uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; }
|
||||
/** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/
|
||||
uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
|
||||
/** Whether it is possible to mine blocks on demand (no retargeting) */
|
||||
bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
|
||||
/** Return the network string */
|
||||
std::string NetworkIDString() const { return strNetworkID; }
|
||||
/** Return the list of hostnames to look up for DNS seeds */
|
||||
const std::vector<std::string>& DNSSeeds() const { return vSeeds; }
|
||||
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
|
||||
const std::string& Bech32HRP() const { return bech32_hrp; }
|
||||
const std::vector<uint8_t>& FixedSeeds() const { return vFixedSeeds; }
|
||||
const CCheckpointData& Checkpoints() const { return checkpointData; }
|
||||
|
||||
//! Get allowed assumeutxo configuration.
|
||||
//! @see ChainstateManager
|
||||
const MapAssumeutxo& Assumeutxo() const { return m_assumeutxo_data; }
|
||||
|
||||
const ChainTxData& TxData() const { return chainTxData; }
|
||||
protected:
|
||||
CChainParams() {}
|
||||
|
||||
Consensus::Params consensus;
|
||||
CMessageHeader::MessageStartChars pchMessageStart;
|
||||
uint16_t nDefaultPort;
|
||||
uint64_t nPruneAfterHeight;
|
||||
uint64_t m_assumed_blockchain_size;
|
||||
uint64_t m_assumed_chain_state_size;
|
||||
std::vector<std::string> vSeeds;
|
||||
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
|
||||
std::string bech32_hrp;
|
||||
std::string strNetworkID;
|
||||
CBlock genesis;
|
||||
std::vector<uint8_t> vFixedSeeds;
|
||||
bool fDefaultConsistencyChecks;
|
||||
bool fRequireStandard;
|
||||
bool m_is_test_chain;
|
||||
bool m_is_mockable_chain;
|
||||
CCheckpointData checkpointData;
|
||||
MapAssumeutxo m_assumeutxo_data;
|
||||
ChainTxData chainTxData;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.
|
||||
* @returns a CChainParams* of the chosen chain.
|
||||
* @throws a std::runtime_error if the chain is not supported.
|
||||
*/
|
||||
std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const std::string& chain);
|
||||
|
||||
/**
|
||||
* Return the currently selected parameters. This won't change after app
|
||||
* startup, except for unit tests.
|
||||
*/
|
||||
const CChainParams &Params();
|
||||
|
||||
/**
|
||||
* Sets the params returned by Params() to those for the given chain name.
|
||||
* @throws std::runtime_error when the chain is not supported.
|
||||
*/
|
||||
void SelectParams(const std::string& chain);
|
||||
|
||||
#endif // DIGIBYTE_CHAINPARAMS_H
|
||||
64
src/chainparamsbase.cpp
Normal file
64
src/chainparamsbase.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2026 The Vexta Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <chainparamsbase.h>
|
||||
|
||||
#include <tinyformat.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
const std::string CBaseChainParams::MAIN = "main";
|
||||
const std::string CBaseChainParams::TESTNET = "test";
|
||||
const std::string CBaseChainParams::SIGNET = "signet";
|
||||
const std::string CBaseChainParams::REGTEST = "regtest";
|
||||
|
||||
void SetupChainParamsBaseOptions(ArgsManager& argsman)
|
||||
{
|
||||
argsman.AddArg("-chain=<chain>", "Use the chain <chain> (default: main). Allowed values: main, test, signet, regtest", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||
argsman.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
|
||||
"This is intended for regression testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
|
||||
argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||
argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||
argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
|
||||
argsman.AddArg("-signet", "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||
argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_STRING, OptionsCategory::CHAINPARAMS);
|
||||
argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_STRING, OptionsCategory::CHAINPARAMS);
|
||||
argsman.AddArg("-easypow", "Allow easy minable blocks in regtest", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||
}
|
||||
|
||||
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
|
||||
|
||||
const CBaseChainParams& BaseParams()
|
||||
{
|
||||
assert(globalChainBaseParams);
|
||||
return *globalChainBaseParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Port numbers for incoming Tor connections (14122, 14123, 18543) have
|
||||
* been chosen arbitrarily to keep ranges of used ports tight.
|
||||
* Yoshi: Added +100 to base port to determine tor port
|
||||
*/
|
||||
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
|
||||
{
|
||||
if (chain == CBaseChainParams::MAIN)
|
||||
return std::make_unique<CBaseChainParams>("", 19332, 19432);
|
||||
else if (chain == CBaseChainParams::TESTNET)
|
||||
return std::make_unique<CBaseChainParams>("testnet4", 14023, 14123);
|
||||
else if (chain == CBaseChainParams::REGTEST)
|
||||
return std::make_unique<CBaseChainParams>("regtest", 18443, 18543);
|
||||
else if (chain == CBaseChainParams::SIGNET)
|
||||
return std::make_unique<CBaseChainParams>("signet", 19443, 19445);
|
||||
else
|
||||
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
||||
}
|
||||
|
||||
void SelectBaseParams(const std::string& chain)
|
||||
{
|
||||
globalChainBaseParams = CreateBaseChainParams(chain);
|
||||
gArgs.SelectConfigNetwork(chain);
|
||||
}
|
||||
64
src/chainparamsbase.h
Normal file
64
src/chainparamsbase.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2014-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_CHAINPARAMSBASE_H
|
||||
#define DIGIBYTE_CHAINPARAMSBASE_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class ArgsManager;
|
||||
|
||||
/**
|
||||
* CBaseChainParams defines the base parameters (shared between vexta-cli and vextad)
|
||||
* of a given instance of the DigiByte system.
|
||||
*/
|
||||
class CBaseChainParams
|
||||
{
|
||||
public:
|
||||
///@{
|
||||
/** Chain name strings */
|
||||
static const std::string MAIN;
|
||||
static const std::string TESTNET;
|
||||
static const std::string SIGNET;
|
||||
static const std::string REGTEST;
|
||||
///@}
|
||||
|
||||
const std::string& DataDir() const { return strDataDir; }
|
||||
uint16_t RPCPort() const { return m_rpc_port; }
|
||||
uint16_t OnionServiceTargetPort() const { return m_onion_service_target_port; }
|
||||
|
||||
CBaseChainParams() = delete;
|
||||
CBaseChainParams(const std::string& data_dir, uint16_t rpc_port, uint16_t onion_service_target_port)
|
||||
: m_rpc_port(rpc_port), m_onion_service_target_port(onion_service_target_port), strDataDir(data_dir) {}
|
||||
|
||||
private:
|
||||
const uint16_t m_rpc_port;
|
||||
const uint16_t m_onion_service_target_port;
|
||||
std::string strDataDir;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and returns a std::unique_ptr<CBaseChainParams> of the chosen chain.
|
||||
* @returns a CBaseChainParams* of the chosen chain.
|
||||
* @throws a std::runtime_error if the chain is not supported.
|
||||
*/
|
||||
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain);
|
||||
|
||||
/**
|
||||
*Set the arguments for chainparams
|
||||
*/
|
||||
void SetupChainParamsBaseOptions(ArgsManager& argsman);
|
||||
|
||||
/**
|
||||
* Return the currently selected parameters. This won't change after app
|
||||
* startup, except for unit tests.
|
||||
*/
|
||||
const CBaseChainParams& BaseParams();
|
||||
|
||||
/** Sets the params returned by Params() to those for the given network. */
|
||||
void SelectBaseParams(const std::string& chain);
|
||||
|
||||
#endif // DIGIBYTE_CHAINPARAMSBASE_H
|
||||
10
src/chainparamsseeds.h
Normal file
10
src/chainparamsseeds.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) 2026 The Vexta Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef VEXTA_CHAINPARAMSSEEDS_H
|
||||
#define VEXTA_CHAINPARAMSSEEDS_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#endif // VEXTA_CHAINPARAMSSEEDS_H
|
||||
32
src/checkpoints.cpp
Normal file
32
src/checkpoints.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2009-2018 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <checkpoints.h>
|
||||
|
||||
#include <chain.h>
|
||||
#include <chainparams.h>
|
||||
#include <reverse_iterator.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
namespace Checkpoints {
|
||||
|
||||
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data)
|
||||
{
|
||||
const MapCheckpoints& checkpoints = data.mapCheckpoints;
|
||||
|
||||
for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints))
|
||||
{
|
||||
const uint256& hash = i.second;
|
||||
CBlockIndex* pindex = LookupBlockIndex(hash);
|
||||
if (pindex) {
|
||||
return pindex;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Checkpoints
|
||||
27
src/checkpoints.h
Normal file
27
src/checkpoints.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2009-2018 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_CHECKPOINTS_H
|
||||
#define DIGIBYTE_CHECKPOINTS_H
|
||||
|
||||
#include <uint256.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
class CBlockIndex;
|
||||
struct CCheckpointData;
|
||||
|
||||
/**
|
||||
* Block-chain checkpoints are compiled-in sanity checks.
|
||||
* They are updated every release or three.
|
||||
*/
|
||||
namespace Checkpoints
|
||||
{
|
||||
|
||||
//! Returns last CBlockIndex* that is a checkpoint
|
||||
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data);
|
||||
|
||||
} //namespace Checkpoints
|
||||
|
||||
#endif // DIGIBYTE_CHECKPOINTS_H
|
||||
248
src/checkqueue.h
Normal file
248
src/checkqueue.h
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_CHECKQUEUE_H
|
||||
#define DIGIBYTE_CHECKQUEUE_H
|
||||
|
||||
#include <sync.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/threadnames.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
template <typename T>
|
||||
class CCheckQueueControl;
|
||||
|
||||
/**
|
||||
* Queue for verifications that have to be performed.
|
||||
* The verifications are represented by a type T, which must provide an
|
||||
* operator(), returning a bool.
|
||||
*
|
||||
* One thread (the master) is assumed to push batches of verifications
|
||||
* onto the queue, where they are processed by N-1 worker threads. When
|
||||
* the master is done adding work, it temporarily joins the worker pool
|
||||
* as an N'th worker, until all jobs are done.
|
||||
*/
|
||||
template <typename T>
|
||||
class CCheckQueue
|
||||
{
|
||||
private:
|
||||
//! Mutex to protect the inner state
|
||||
Mutex m_mutex;
|
||||
|
||||
//! Worker threads block on this when out of work
|
||||
std::condition_variable m_worker_cv;
|
||||
|
||||
//! Master thread blocks on this when out of work
|
||||
std::condition_variable m_master_cv;
|
||||
|
||||
//! The queue of elements to be processed.
|
||||
//! As the order of booleans doesn't matter, it is used as a LIFO (stack)
|
||||
std::vector<T> queue GUARDED_BY(m_mutex);
|
||||
|
||||
//! The number of workers (including the master) that are idle.
|
||||
int nIdle GUARDED_BY(m_mutex){0};
|
||||
|
||||
//! The total number of workers (including the master).
|
||||
int nTotal GUARDED_BY(m_mutex){0};
|
||||
|
||||
//! The temporary evaluation result.
|
||||
bool fAllOk GUARDED_BY(m_mutex){true};
|
||||
|
||||
/**
|
||||
* Number of verifications that haven't completed yet.
|
||||
* This includes elements that are no longer queued, but still in the
|
||||
* worker's own batches.
|
||||
*/
|
||||
unsigned int nTodo GUARDED_BY(m_mutex){0};
|
||||
|
||||
//! The maximum number of elements to be processed in one batch
|
||||
const unsigned int nBatchSize;
|
||||
|
||||
std::vector<std::thread> m_worker_threads;
|
||||
bool m_request_stop GUARDED_BY(m_mutex){false};
|
||||
|
||||
/** Internal function that does bulk of the verification work. */
|
||||
bool Loop(bool fMaster)
|
||||
{
|
||||
std::condition_variable& cond = fMaster ? m_master_cv : m_worker_cv;
|
||||
std::vector<T> vChecks;
|
||||
vChecks.reserve(nBatchSize);
|
||||
unsigned int nNow = 0;
|
||||
bool fOk = true;
|
||||
do {
|
||||
{
|
||||
WAIT_LOCK(m_mutex, lock);
|
||||
// first do the clean-up of the previous loop run (allowing us to do it in the same critsect)
|
||||
if (nNow) {
|
||||
fAllOk &= fOk;
|
||||
nTodo -= nNow;
|
||||
if (nTodo == 0 && !fMaster)
|
||||
// We processed the last element; inform the master it can exit and return the result
|
||||
m_master_cv.notify_one();
|
||||
} else {
|
||||
// first iteration
|
||||
nTotal++;
|
||||
}
|
||||
// logically, the do loop starts here
|
||||
while (queue.empty() && !m_request_stop) {
|
||||
if (fMaster && nTodo == 0) {
|
||||
nTotal--;
|
||||
bool fRet = fAllOk;
|
||||
// reset the status for new work later
|
||||
fAllOk = true;
|
||||
// return the current status
|
||||
return fRet;
|
||||
}
|
||||
nIdle++;
|
||||
cond.wait(lock); // wait
|
||||
nIdle--;
|
||||
}
|
||||
if (m_request_stop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decide how many work units to process now.
|
||||
// * Do not try to do everything at once, but aim for increasingly smaller batches so
|
||||
// all workers finish approximately simultaneously.
|
||||
// * Try to account for idle jobs which will instantly start helping.
|
||||
// * Don't do batches smaller than 1 (duh), or larger than nBatchSize.
|
||||
nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1)));
|
||||
vChecks.resize(nNow);
|
||||
for (unsigned int i = 0; i < nNow; i++) {
|
||||
// We want the lock on the m_mutex to be as short as possible, so swap jobs from the global
|
||||
// queue to the local batch vector instead of copying.
|
||||
vChecks[i].swap(queue.back());
|
||||
queue.pop_back();
|
||||
}
|
||||
// Check whether we need to do work at all
|
||||
fOk = fAllOk;
|
||||
}
|
||||
// execute work
|
||||
for (T& check : vChecks)
|
||||
if (fOk)
|
||||
fOk = check();
|
||||
vChecks.clear();
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public:
|
||||
//! Mutex to ensure only one concurrent CCheckQueueControl
|
||||
Mutex m_control_mutex;
|
||||
|
||||
//! Create a new check queue
|
||||
explicit CCheckQueue(unsigned int nBatchSizeIn)
|
||||
: nBatchSize(nBatchSizeIn)
|
||||
{
|
||||
}
|
||||
|
||||
//! Create a pool of new worker threads.
|
||||
void StartWorkerThreads(const int threads_num)
|
||||
{
|
||||
{
|
||||
LOCK(m_mutex);
|
||||
nIdle = 0;
|
||||
nTotal = 0;
|
||||
fAllOk = true;
|
||||
}
|
||||
assert(m_worker_threads.empty());
|
||||
for (int n = 0; n < threads_num; ++n) {
|
||||
m_worker_threads.emplace_back([this, n]() {
|
||||
util::ThreadRename(strprintf("scriptch.%i", n));
|
||||
Loop(false /* worker thread */);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//! Wait until execution finishes, and return whether all evaluations were successful.
|
||||
bool Wait()
|
||||
{
|
||||
return Loop(true /* master thread */);
|
||||
}
|
||||
|
||||
//! Add a batch of checks to the queue
|
||||
void Add(std::vector<T>& vChecks)
|
||||
{
|
||||
LOCK(m_mutex);
|
||||
for (T& check : vChecks) {
|
||||
queue.push_back(T());
|
||||
check.swap(queue.back());
|
||||
}
|
||||
nTodo += vChecks.size();
|
||||
if (vChecks.size() == 1)
|
||||
m_worker_cv.notify_one();
|
||||
else if (vChecks.size() > 1)
|
||||
m_worker_cv.notify_all();
|
||||
}
|
||||
|
||||
//! Stop all of the worker threads.
|
||||
void StopWorkerThreads()
|
||||
{
|
||||
WITH_LOCK(m_mutex, m_request_stop = true);
|
||||
m_worker_cv.notify_all();
|
||||
for (std::thread& t : m_worker_threads) {
|
||||
t.join();
|
||||
}
|
||||
m_worker_threads.clear();
|
||||
WITH_LOCK(m_mutex, m_request_stop = false);
|
||||
}
|
||||
|
||||
~CCheckQueue()
|
||||
{
|
||||
assert(m_worker_threads.empty());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* RAII-style controller object for a CCheckQueue that guarantees the passed
|
||||
* queue is finished before continuing.
|
||||
*/
|
||||
template <typename T>
|
||||
class CCheckQueueControl
|
||||
{
|
||||
private:
|
||||
CCheckQueue<T> * const pqueue;
|
||||
bool fDone;
|
||||
|
||||
public:
|
||||
CCheckQueueControl() = delete;
|
||||
CCheckQueueControl(const CCheckQueueControl&) = delete;
|
||||
CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;
|
||||
explicit CCheckQueueControl(CCheckQueue<T> * const pqueueIn) : pqueue(pqueueIn), fDone(false)
|
||||
{
|
||||
// passed queue is supposed to be unused, or nullptr
|
||||
if (pqueue != nullptr) {
|
||||
ENTER_CRITICAL_SECTION(pqueue->m_control_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
bool Wait()
|
||||
{
|
||||
if (pqueue == nullptr)
|
||||
return true;
|
||||
bool fRet = pqueue->Wait();
|
||||
fDone = true;
|
||||
return fRet;
|
||||
}
|
||||
|
||||
void Add(std::vector<T>& vChecks)
|
||||
{
|
||||
if (pqueue != nullptr)
|
||||
pqueue->Add(vChecks);
|
||||
}
|
||||
|
||||
~CCheckQueueControl()
|
||||
{
|
||||
if (!fDone)
|
||||
Wait();
|
||||
if (pqueue != nullptr) {
|
||||
LEAVE_CRITICAL_SECTION(pqueue->m_control_mutex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_CHECKQUEUE_H
|
||||
75
src/clientversion.cpp
Normal file
75
src/clientversion.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2012-202 The Bitcoin Core developers
|
||||
// Copyright (c) 2026 The Vexta Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <clientversion.h>
|
||||
|
||||
#include <tinyformat.h>
|
||||
|
||||
|
||||
/**
|
||||
* Name of client reported in the 'version' message. Report the same name
|
||||
* for both vextad and vexta-qt, to make it harder for attackers to
|
||||
* target servers or GUI users specifically.
|
||||
*/
|
||||
const std::string CLIENT_NAME("Vexta");
|
||||
|
||||
|
||||
#ifdef HAVE_BUILD_INFO
|
||||
#include <obj/build.h>
|
||||
// The <obj/build.h>, which is generated by the build environment (share/genbuild.sh),
|
||||
// could contain only one line of the following:
|
||||
// - "#define BUILD_GIT_TAG ...", if the top commit is tagged
|
||||
// - "#define BUILD_GIT_COMMIT ...", if the top commit is not tagged
|
||||
// - "// No build information available", if proper git information is not available
|
||||
#endif
|
||||
|
||||
//! git will put "#define GIT_COMMIT_ID ..." on the next line inside archives.
|
||||
#define GIT_COMMIT_ID "42174383ab483afff87e6cd3a15a367142a269a7"
|
||||
|
||||
#ifdef BUILD_GIT_TAG
|
||||
#define BUILD_DESC BUILD_GIT_TAG
|
||||
#define BUILD_SUFFIX ""
|
||||
#else
|
||||
#define BUILD_DESC "v" STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_BUILD)
|
||||
#ifdef BUILD_GIT_COMMIT
|
||||
#define BUILD_SUFFIX "-" BUILD_GIT_COMMIT
|
||||
#elif defined(GIT_COMMIT_ID)
|
||||
#define BUILD_SUFFIX "-g" GIT_COMMIT_ID
|
||||
#else
|
||||
#define BUILD_SUFFIX "-unk"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const std::string CLIENT_BUILD(BUILD_DESC BUILD_SUFFIX);
|
||||
|
||||
static std::string FormatVersion(int nVersion)
|
||||
{
|
||||
return strprintf("%d.%d.%d", nVersion / 10000, (nVersion / 100) % 100, nVersion % 100);
|
||||
}
|
||||
|
||||
std::string FormatFullVersion()
|
||||
{
|
||||
return CLIENT_BUILD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the subversion field according to BIP 14 spec (https://github.com/digibyte/bips/blob/master/bip-0014.mediawiki)
|
||||
*/
|
||||
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "/";
|
||||
ss << name << ":" << FormatVersion(nClientVersion);
|
||||
if (!comments.empty())
|
||||
{
|
||||
std::vector<std::string>::const_iterator it(comments.begin());
|
||||
ss << "(" << *it;
|
||||
for(++it; it != comments.end(); ++it)
|
||||
ss << "; " << *it;
|
||||
ss << ")";
|
||||
}
|
||||
ss << "/";
|
||||
return ss.str();
|
||||
}
|
||||
48
src/clientversion.h
Normal file
48
src/clientversion.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_CLIENTVERSION_H
|
||||
#define DIGIBYTE_CLIENTVERSION_H
|
||||
|
||||
#include <util/macros.h>
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif //HAVE_CONFIG_H
|
||||
|
||||
// Check that required client information is defined
|
||||
#if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR)
|
||||
#error Client version information missing: version is not defined by vexta-config.h or in any other way
|
||||
#endif
|
||||
|
||||
//! Copyright string used in Windows .rc files
|
||||
#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " " COPYRIGHT_HOLDERS_FINAL
|
||||
|
||||
/**
|
||||
* vextad-res.rc includes this file, but it cannot cope with real c++ code.
|
||||
* WINDRES_PREPROC is defined to indicate that its pre-processor is running.
|
||||
* Anything other than a define should be guarded below.
|
||||
*/
|
||||
|
||||
#if !defined(WINDRES_PREPROC)
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static const int CLIENT_VERSION =
|
||||
10000 * CLIENT_VERSION_MAJOR
|
||||
+ 100 * CLIENT_VERSION_MINOR
|
||||
+ 1 * CLIENT_VERSION_BUILD;
|
||||
|
||||
extern const std::string CLIENT_NAME;
|
||||
extern const std::string CLIENT_BUILD;
|
||||
|
||||
|
||||
std::string FormatFullVersion();
|
||||
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
|
||||
|
||||
#endif // WINDRES_PREPROC
|
||||
|
||||
#endif // DIGIBYTE_CLIENTVERSION_H
|
||||
291
src/coins.cpp
Normal file
291
src/coins.cpp
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <coins.h>
|
||||
|
||||
#include <consensus/consensus.h>
|
||||
#include <logging.h>
|
||||
#include <random.h>
|
||||
#include <version.h>
|
||||
|
||||
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
|
||||
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
|
||||
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
|
||||
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
|
||||
std::unique_ptr<CCoinsViewCursor> CCoinsView::Cursor() const { return nullptr; }
|
||||
|
||||
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const
|
||||
{
|
||||
Coin coin;
|
||||
return GetCoin(outpoint, coin);
|
||||
}
|
||||
|
||||
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
|
||||
bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
|
||||
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
|
||||
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
|
||||
std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
|
||||
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
|
||||
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
|
||||
std::unique_ptr<CCoinsViewCursor> CCoinsViewBacked::Cursor() const { return base->Cursor(); }
|
||||
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
|
||||
|
||||
CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
|
||||
|
||||
size_t CCoinsViewCache::DynamicMemoryUsage() const {
|
||||
return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;
|
||||
}
|
||||
|
||||
CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const {
|
||||
CCoinsMap::iterator it = cacheCoins.find(outpoint);
|
||||
if (it != cacheCoins.end())
|
||||
return it;
|
||||
Coin tmp;
|
||||
if (!base->GetCoin(outpoint, tmp))
|
||||
return cacheCoins.end();
|
||||
CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
|
||||
if (ret->second.coin.IsSpent()) {
|
||||
// The parent only has an empty entry for this outpoint; we can consider our
|
||||
// version as fresh.
|
||||
ret->second.flags = CCoinsCacheEntry::FRESH;
|
||||
}
|
||||
cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
|
||||
CCoinsMap::const_iterator it = FetchCoin(outpoint);
|
||||
if (it != cacheCoins.end()) {
|
||||
coin = it->second.coin;
|
||||
return !coin.IsSpent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
|
||||
assert(!coin.IsSpent());
|
||||
if (coin.out.scriptPubKey.IsUnspendable()) return;
|
||||
CCoinsMap::iterator it;
|
||||
bool inserted;
|
||||
std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
|
||||
bool fresh = false;
|
||||
if (!inserted) {
|
||||
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
|
||||
}
|
||||
if (!possible_overwrite) {
|
||||
if (!it->second.coin.IsSpent()) {
|
||||
throw std::logic_error("Attempted to overwrite an unspent coin (when possible_overwrite is false)");
|
||||
}
|
||||
// If the coin exists in this cache as a spent coin and is DIRTY, then
|
||||
// its spentness hasn't been flushed to the parent cache. We're
|
||||
// re-adding the coin to this cache now but we can't mark it as FRESH.
|
||||
// If we mark it FRESH and then spend it before the cache is flushed
|
||||
// we would remove it from this cache and would never flush spentness
|
||||
// to the parent cache.
|
||||
//
|
||||
// Re-adding a spent coin can happen in the case of a re-org (the coin
|
||||
// is 'spent' when the block adding it is disconnected and then
|
||||
// re-added when it is also added in a newly connected block).
|
||||
//
|
||||
// If the coin doesn't exist in the current cache, or is spent but not
|
||||
// DIRTY, then it can be marked FRESH.
|
||||
fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
|
||||
}
|
||||
it->second.coin = std::move(coin);
|
||||
it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
|
||||
cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
|
||||
}
|
||||
|
||||
void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin) {
|
||||
cachedCoinsUsage += coin.DynamicMemoryUsage();
|
||||
cacheCoins.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(std::move(outpoint)),
|
||||
std::forward_as_tuple(std::move(coin), CCoinsCacheEntry::DIRTY));
|
||||
}
|
||||
|
||||
void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite) {
|
||||
bool fCoinbase = tx.IsCoinBase();
|
||||
const uint256& txid = tx.GetHash();
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i) {
|
||||
bool overwrite = check_for_overwrite ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase;
|
||||
// Coinbase transactions can always be overwritten, in order to correctly
|
||||
// deal with the pre-BIP30 occurrences of duplicate coinbase transactions.
|
||||
cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
|
||||
CCoinsMap::iterator it = FetchCoin(outpoint);
|
||||
if (it == cacheCoins.end()) return false;
|
||||
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
|
||||
if (moveout) {
|
||||
*moveout = std::move(it->second.coin);
|
||||
}
|
||||
if (it->second.flags & CCoinsCacheEntry::FRESH) {
|
||||
cacheCoins.erase(it);
|
||||
} else {
|
||||
it->second.flags |= CCoinsCacheEntry::DIRTY;
|
||||
it->second.coin.Clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const Coin coinEmpty;
|
||||
|
||||
const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
|
||||
CCoinsMap::const_iterator it = FetchCoin(outpoint);
|
||||
if (it == cacheCoins.end()) {
|
||||
return coinEmpty;
|
||||
} else {
|
||||
return it->second.coin;
|
||||
}
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
|
||||
CCoinsMap::const_iterator it = FetchCoin(outpoint);
|
||||
return (it != cacheCoins.end() && !it->second.coin.IsSpent());
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const {
|
||||
CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
|
||||
return (it != cacheCoins.end() && !it->second.coin.IsSpent());
|
||||
}
|
||||
|
||||
uint256 CCoinsViewCache::GetBestBlock() const {
|
||||
if (hashBlock.IsNull())
|
||||
hashBlock = base->GetBestBlock();
|
||||
return hashBlock;
|
||||
}
|
||||
|
||||
void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
|
||||
hashBlock = hashBlockIn;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
|
||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
|
||||
// Ignore non-dirty entries (optimization).
|
||||
if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
|
||||
continue;
|
||||
}
|
||||
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
|
||||
if (itUs == cacheCoins.end()) {
|
||||
// The parent cache does not have an entry, while the child cache does.
|
||||
// We can ignore it if it's both spent and FRESH in the child
|
||||
if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
|
||||
// Create the coin in the parent cache, move the data up
|
||||
// and mark it as dirty.
|
||||
CCoinsCacheEntry& entry = cacheCoins[it->first];
|
||||
entry.coin = std::move(it->second.coin);
|
||||
cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
|
||||
entry.flags = CCoinsCacheEntry::DIRTY;
|
||||
// We can mark it FRESH in the parent if it was FRESH in the child
|
||||
// Otherwise it might have just been flushed from the parent's cache
|
||||
// and already exist in the grandparent
|
||||
if (it->second.flags & CCoinsCacheEntry::FRESH) {
|
||||
entry.flags |= CCoinsCacheEntry::FRESH;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Found the entry in the parent cache
|
||||
if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
|
||||
// The coin was marked FRESH in the child cache, but the coin
|
||||
// exists in the parent cache. If this ever happens, it means
|
||||
// the FRESH flag was misapplied and there is a logic error in
|
||||
// the calling code.
|
||||
throw std::logic_error("FRESH flag misapplied to coin that exists in parent cache");
|
||||
}
|
||||
|
||||
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
|
||||
// The grandparent cache does not have an entry, and the coin
|
||||
// has been spent. We can just delete it from the parent cache.
|
||||
cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
|
||||
cacheCoins.erase(itUs);
|
||||
} else {
|
||||
// A normal modification.
|
||||
cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
|
||||
itUs->second.coin = std::move(it->second.coin);
|
||||
cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
|
||||
itUs->second.flags |= CCoinsCacheEntry::DIRTY;
|
||||
// NOTE: It isn't safe to mark the coin as FRESH in the parent
|
||||
// cache. If it already existed and was spent in the parent
|
||||
// cache then marking it FRESH would prevent that spentness
|
||||
// from being flushed to the grandparent.
|
||||
}
|
||||
}
|
||||
}
|
||||
hashBlock = hashBlockIn;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::Flush() {
|
||||
bool fOk = base->BatchWrite(cacheCoins, hashBlock);
|
||||
cacheCoins.clear();
|
||||
cachedCoinsUsage = 0;
|
||||
return fOk;
|
||||
}
|
||||
|
||||
void CCoinsViewCache::Uncache(const COutPoint& hash)
|
||||
{
|
||||
CCoinsMap::iterator it = cacheCoins.find(hash);
|
||||
if (it != cacheCoins.end() && it->second.flags == 0) {
|
||||
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
|
||||
cacheCoins.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CCoinsViewCache::GetCacheSize() const {
|
||||
return cacheCoins.size();
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
|
||||
{
|
||||
if (!tx.IsCoinBase()) {
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
if (!HaveCoin(tx.vin[i].prevout)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCoinsViewCache::ReallocateCache()
|
||||
{
|
||||
// Cache should be empty when we're calling this.
|
||||
assert(cacheCoins.size() == 0);
|
||||
cacheCoins.~CCoinsMap();
|
||||
::new (&cacheCoins) CCoinsMap();
|
||||
}
|
||||
|
||||
static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut(), PROTOCOL_VERSION);
|
||||
static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_OUTPUT_WEIGHT;
|
||||
|
||||
const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
|
||||
{
|
||||
COutPoint iter(txid, 0);
|
||||
while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
|
||||
const Coin& alternate = view.AccessCoin(iter);
|
||||
if (!alternate.IsSpent()) return alternate;
|
||||
++iter.n;
|
||||
}
|
||||
return coinEmpty;
|
||||
}
|
||||
|
||||
bool CCoinsViewErrorCatcher::GetCoin(const COutPoint &outpoint, Coin &coin) const {
|
||||
try {
|
||||
return CCoinsViewBacked::GetCoin(outpoint, coin);
|
||||
} catch(const std::runtime_error& e) {
|
||||
for (auto f : m_err_callbacks) {
|
||||
f();
|
||||
}
|
||||
LogPrintf("Error reading from database: %s\n", e.what());
|
||||
// Starting the shutdown sequence and returning false to the caller would be
|
||||
// interpreted as 'entry not found' (as opposed to unable to read data), and
|
||||
// could lead to invalid interpretation. Just exit immediately, as we can't
|
||||
// continue anyway, and all writes should be atomic.
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
361
src/coins.h
Normal file
361
src/coins.h
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_COINS_H
|
||||
#define DIGIBYTE_COINS_H
|
||||
|
||||
#include <compressor.h>
|
||||
#include <core_memusage.h>
|
||||
#include <memusage.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
#include <util/hasher.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
* A UTXO entry.
|
||||
*
|
||||
* Serialized format:
|
||||
* - VARINT((coinbase ? 1 : 0) | (height << 1))
|
||||
* - the non-spent CTxOut (via TxOutCompression)
|
||||
*/
|
||||
class Coin
|
||||
{
|
||||
public:
|
||||
//! unspent transaction output
|
||||
CTxOut out;
|
||||
|
||||
//! whether containing transaction was a coinbase
|
||||
unsigned int fCoinBase : 1;
|
||||
|
||||
//! at which height this containing transaction was included in the active block chain
|
||||
uint32_t nHeight : 31;
|
||||
|
||||
//! construct a Coin from a CTxOut and height/coinbase information.
|
||||
Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn) : out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn) {}
|
||||
Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn) : out(outIn), fCoinBase(fCoinBaseIn),nHeight(nHeightIn) {}
|
||||
|
||||
void Clear() {
|
||||
out.SetNull();
|
||||
fCoinBase = false;
|
||||
nHeight = 0;
|
||||
}
|
||||
|
||||
//! empty constructor
|
||||
Coin() : fCoinBase(false), nHeight(0) { }
|
||||
|
||||
bool IsCoinBase() const {
|
||||
return fCoinBase;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s) const {
|
||||
assert(!IsSpent());
|
||||
uint32_t code = nHeight * uint32_t{2} + fCoinBase;
|
||||
::Serialize(s, VARINT(code));
|
||||
::Serialize(s, Using<TxOutCompression>(out));
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream &s) {
|
||||
uint32_t code = 0;
|
||||
::Unserialize(s, VARINT(code));
|
||||
nHeight = code >> 1;
|
||||
fCoinBase = code & 1;
|
||||
::Unserialize(s, Using<TxOutCompression>(out));
|
||||
}
|
||||
|
||||
/** Either this coin never existed (see e.g. coinEmpty in coins.cpp), or it
|
||||
* did exist and has been spent.
|
||||
*/
|
||||
bool IsSpent() const {
|
||||
return out.IsNull();
|
||||
}
|
||||
|
||||
size_t DynamicMemoryUsage() const {
|
||||
return memusage::DynamicUsage(out.scriptPubKey);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A Coin in one level of the coins database caching hierarchy.
|
||||
*
|
||||
* A coin can either be:
|
||||
* - unspent or spent (in which case the Coin object will be nulled out - see Coin.Clear())
|
||||
* - DIRTY or not DIRTY
|
||||
* - FRESH or not FRESH
|
||||
*
|
||||
* Out of these 2^3 = 8 states, only some combinations are valid:
|
||||
* - unspent, FRESH, DIRTY (e.g. a new coin created in the cache)
|
||||
* - unspent, not FRESH, DIRTY (e.g. a coin changed in the cache during a reorg)
|
||||
* - unspent, not FRESH, not DIRTY (e.g. an unspent coin fetched from the parent cache)
|
||||
* - spent, FRESH, not DIRTY (e.g. a spent coin fetched from the parent cache)
|
||||
* - spent, not FRESH, DIRTY (e.g. a coin is spent and spentness needs to be flushed to the parent)
|
||||
*/
|
||||
struct CCoinsCacheEntry
|
||||
{
|
||||
Coin coin; // The actual cached data.
|
||||
unsigned char flags;
|
||||
|
||||
enum Flags {
|
||||
/**
|
||||
* DIRTY means the CCoinsCacheEntry is potentially different from the
|
||||
* version in the parent cache. Failure to mark a coin as DIRTY when
|
||||
* it is potentially different from the parent cache will cause a
|
||||
* consensus failure, since the coin's state won't get written to the
|
||||
* parent when the cache is flushed.
|
||||
*/
|
||||
DIRTY = (1 << 0),
|
||||
/**
|
||||
* FRESH means the parent cache does not have this coin or that it is a
|
||||
* spent coin in the parent cache. If a FRESH coin in the cache is
|
||||
* later spent, it can be deleted entirely and doesn't ever need to be
|
||||
* flushed to the parent. This is a performance optimization. Marking a
|
||||
* coin as FRESH when it exists unspent in the parent cache will cause a
|
||||
* consensus failure, since it might not be deleted from the parent
|
||||
* when this cache is flushed.
|
||||
*/
|
||||
FRESH = (1 << 1),
|
||||
};
|
||||
|
||||
CCoinsCacheEntry() : flags(0) {}
|
||||
explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {}
|
||||
CCoinsCacheEntry(Coin&& coin_, unsigned char flag) : coin(std::move(coin_)), flags(flag) {}
|
||||
};
|
||||
|
||||
typedef std::unordered_map<COutPoint, CCoinsCacheEntry, SaltedOutpointHasher> CCoinsMap;
|
||||
|
||||
/** Cursor for iterating over CoinsView state */
|
||||
class CCoinsViewCursor
|
||||
{
|
||||
public:
|
||||
CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {}
|
||||
virtual ~CCoinsViewCursor() {}
|
||||
|
||||
virtual bool GetKey(COutPoint &key) const = 0;
|
||||
virtual bool GetValue(Coin &coin) const = 0;
|
||||
virtual unsigned int GetValueSize() const = 0;
|
||||
|
||||
virtual bool Valid() const = 0;
|
||||
virtual void Next() = 0;
|
||||
|
||||
//! Get best block at the time this cursor was created
|
||||
const uint256 &GetBestBlock() const { return hashBlock; }
|
||||
private:
|
||||
uint256 hashBlock;
|
||||
};
|
||||
|
||||
/** Abstract view on the open txout dataset. */
|
||||
class CCoinsView
|
||||
{
|
||||
public:
|
||||
/** Retrieve the Coin (unspent transaction output) for a given outpoint.
|
||||
* Returns true only when an unspent coin was found, which is returned in coin.
|
||||
* When false is returned, coin's value is unspecified.
|
||||
*/
|
||||
virtual bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
|
||||
|
||||
//! Just check whether a given outpoint is unspent.
|
||||
virtual bool HaveCoin(const COutPoint &outpoint) const;
|
||||
|
||||
//! Retrieve the block hash whose state this CCoinsView currently represents
|
||||
virtual uint256 GetBestBlock() const;
|
||||
|
||||
//! Retrieve the range of blocks that may have been only partially written.
|
||||
//! If the database is in a consistent state, the result is the empty vector.
|
||||
//! Otherwise, a two-element vector is returned consisting of the new and
|
||||
//! the old block hash, in that order.
|
||||
virtual std::vector<uint256> GetHeadBlocks() const;
|
||||
|
||||
//! Do a bulk modification (multiple Coin changes + BestBlock change).
|
||||
//! The passed mapCoins can be modified.
|
||||
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
|
||||
|
||||
//! Get a cursor to iterate over the whole state
|
||||
virtual std::unique_ptr<CCoinsViewCursor> Cursor() const;
|
||||
|
||||
//! As we use CCoinsViews polymorphically, have a virtual destructor
|
||||
virtual ~CCoinsView() {}
|
||||
|
||||
//! Estimate database size (0 if not implemented)
|
||||
virtual size_t EstimateSize() const { return 0; }
|
||||
};
|
||||
|
||||
|
||||
/** CCoinsView backed by another CCoinsView */
|
||||
class CCoinsViewBacked : public CCoinsView
|
||||
{
|
||||
protected:
|
||||
CCoinsView *base;
|
||||
|
||||
public:
|
||||
CCoinsViewBacked(CCoinsView *viewIn);
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
bool HaveCoin(const COutPoint &outpoint) const override;
|
||||
uint256 GetBestBlock() const override;
|
||||
std::vector<uint256> GetHeadBlocks() const override;
|
||||
void SetBackend(CCoinsView &viewIn);
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
|
||||
std::unique_ptr<CCoinsViewCursor> Cursor() const override;
|
||||
size_t EstimateSize() const override;
|
||||
};
|
||||
|
||||
|
||||
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
|
||||
class CCoinsViewCache : public CCoinsViewBacked
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* Make mutable so that we can "fill the cache" even from Get-methods
|
||||
* declared as "const".
|
||||
*/
|
||||
mutable uint256 hashBlock;
|
||||
mutable CCoinsMap cacheCoins;
|
||||
|
||||
/* Cached dynamic memory usage for the inner Coin objects. */
|
||||
mutable size_t cachedCoinsUsage;
|
||||
|
||||
public:
|
||||
CCoinsViewCache(CCoinsView *baseIn);
|
||||
|
||||
/**
|
||||
* By deleting the copy constructor, we prevent accidentally using it when one intends to create a cache on top of a base cache.
|
||||
*/
|
||||
CCoinsViewCache(const CCoinsViewCache &) = delete;
|
||||
|
||||
// Standard CCoinsView methods
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
bool HaveCoin(const COutPoint &outpoint) const override;
|
||||
uint256 GetBestBlock() const override;
|
||||
void SetBestBlock(const uint256 &hashBlock);
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
|
||||
std::unique_ptr<CCoinsViewCursor> Cursor() const override {
|
||||
throw std::logic_error("CCoinsViewCache cursor iteration not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have the given utxo already loaded in this cache.
|
||||
* The semantics are the same as HaveCoin(), but no calls to
|
||||
* the backing CCoinsView are made.
|
||||
*/
|
||||
bool HaveCoinInCache(const COutPoint &outpoint) const;
|
||||
|
||||
/**
|
||||
* Return a reference to Coin in the cache, or coinEmpty if not found. This is
|
||||
* more efficient than GetCoin.
|
||||
*
|
||||
* Generally, do not hold the reference returned for more than a short scope.
|
||||
* While the current implementation allows for modifications to the contents
|
||||
* of the cache while holding the reference, this behavior should not be relied
|
||||
* on! To be safe, best to not hold the returned reference through any other
|
||||
* calls to this cache.
|
||||
*/
|
||||
const Coin& AccessCoin(const COutPoint &output) const;
|
||||
|
||||
/**
|
||||
* Add a coin. Set possible_overwrite to true if an unspent version may
|
||||
* already exist in the cache.
|
||||
*/
|
||||
void AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite);
|
||||
|
||||
/**
|
||||
* Emplace a coin into cacheCoins without performing any checks, marking
|
||||
* the emplaced coin as dirty.
|
||||
*
|
||||
* NOT FOR GENERAL USE. Used only when loading coins from a UTXO snapshot.
|
||||
* @sa ChainstateManager::PopulateAndValidateSnapshot()
|
||||
*/
|
||||
void EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin);
|
||||
|
||||
/**
|
||||
* Spend a coin. Pass moveto in order to get the deleted data.
|
||||
* If no unspent output exists for the passed outpoint, this call
|
||||
* has no effect.
|
||||
*/
|
||||
bool SpendCoin(const COutPoint &outpoint, Coin* moveto = nullptr);
|
||||
|
||||
/**
|
||||
* Push the modifications applied to this cache to its base.
|
||||
* Failure to call this method before destruction will cause the changes to be forgotten.
|
||||
* If false is returned, the state of this cache (and its backing view) will be undefined.
|
||||
*/
|
||||
bool Flush();
|
||||
|
||||
/**
|
||||
* Removes the UTXO with the given outpoint from the cache, if it is
|
||||
* not modified.
|
||||
*/
|
||||
void Uncache(const COutPoint &outpoint);
|
||||
|
||||
//! Calculate the size of the cache (in number of transaction outputs)
|
||||
unsigned int GetCacheSize() const;
|
||||
|
||||
//! Calculate the size of the cache (in bytes)
|
||||
size_t DynamicMemoryUsage() const;
|
||||
|
||||
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
|
||||
bool HaveInputs(const CTransaction& tx) const;
|
||||
|
||||
//! Force a reallocation of the cache map. This is required when downsizing
|
||||
//! the cache because the map's allocator may be hanging onto a lot of
|
||||
//! memory despite having called .clear().
|
||||
//!
|
||||
//! See: https://stackoverflow.com/questions/42114044/how-to-release-unordered-map-memory
|
||||
void ReallocateCache();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @note this is marked const, but may actually append to `cacheCoins`, increasing
|
||||
* memory usage.
|
||||
*/
|
||||
CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
|
||||
};
|
||||
|
||||
//! Utility function to add all of a transaction's outputs to a cache.
|
||||
//! When check is false, this assumes that overwrites are only possible for coinbase transactions.
|
||||
//! When check is true, the underlying view may be queried to determine whether an addition is
|
||||
//! an overwrite.
|
||||
// TODO: pass in a boolean to limit these possible overwrites to known
|
||||
// (pre-BIP34) cases.
|
||||
void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false);
|
||||
|
||||
//! Utility function to find any unspent output with a given txid.
|
||||
//! This function can be quite expensive because in the event of a transaction
|
||||
//! which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK
|
||||
//! lookups to database, so it should be used with care.
|
||||
const Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid);
|
||||
|
||||
/**
|
||||
* This is a minimally invasive approach to shutdown on LevelDB read errors from the
|
||||
* chainstate, while keeping user interface out of the common library, which is shared
|
||||
* between vextad, and vexta-qt and non-server tools.
|
||||
*
|
||||
* Writes do not need similar protection, as failure to write is handled by the caller.
|
||||
*/
|
||||
class CCoinsViewErrorCatcher final : public CCoinsViewBacked
|
||||
{
|
||||
public:
|
||||
explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
|
||||
|
||||
void AddReadErrCallback(std::function<void()> f) {
|
||||
m_err_callbacks.emplace_back(std::move(f));
|
||||
}
|
||||
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
|
||||
private:
|
||||
/** A list of callbacks to execute upon leveldb read error. */
|
||||
std::vector<std::function<void()>> m_err_callbacks;
|
||||
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_COINS_H
|
||||
119
src/compat.h
Normal file
119
src/compat.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_COMPAT_H
|
||||
#define DIGIBYTE_COMPAT_H
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#ifdef FD_SETSIZE
|
||||
#undef FD_SETSIZE // prevent redefinition compiler warning
|
||||
#endif
|
||||
#define FD_SETSIZE 1024 // max number of fds in fd_set
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
typedef unsigned int SOCKET;
|
||||
#include <errno.h>
|
||||
#define WSAGetLastError() errno
|
||||
#define WSAEINVAL EINVAL
|
||||
#define WSAEALREADY EALREADY
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define WSAEAGAIN EAGAIN
|
||||
#define WSAEMSGSIZE EMSGSIZE
|
||||
#define WSAEINTR EINTR
|
||||
#define WSAEINPROGRESS EINPROGRESS
|
||||
#define WSAEADDRINUSE EADDRINUSE
|
||||
#define WSAENOTSOCK EBADF
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#define SOCKET_ERROR -1
|
||||
#else
|
||||
#ifndef WSAEAGAIN
|
||||
#ifdef EAGAIN
|
||||
#define WSAEAGAIN EAGAIN
|
||||
#else
|
||||
#define WSAEAGAIN WSAEWOULDBLOCK
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR 0400
|
||||
#define S_IWUSR 0200
|
||||
#endif
|
||||
#else
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#if !defined(ssize_t)
|
||||
#ifdef _WIN64
|
||||
typedef int64_t ssize_t;
|
||||
#else
|
||||
typedef int32_t ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAVE_DECL_STRNLEN == 0
|
||||
size_t strnlen( const char *start, size_t max_len);
|
||||
#endif // HAVE_DECL_STRNLEN
|
||||
|
||||
#ifndef WIN32
|
||||
typedef void* sockopt_arg_type;
|
||||
#else
|
||||
typedef char* sockopt_arg_type;
|
||||
#endif
|
||||
|
||||
// Note these both should work with the current usage of poll, but best to be safe
|
||||
// WIN32 poll is broken https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/
|
||||
// __APPLE__ poll is broke https://github.com/digibyte/digibyte/pull/14336#issuecomment-437384408
|
||||
#if defined(__linux__)
|
||||
#define USE_POLL
|
||||
#endif
|
||||
|
||||
bool static inline IsSelectableSocket(const SOCKET& s) {
|
||||
#if defined(USE_POLL) || defined(WIN32)
|
||||
return true;
|
||||
#else
|
||||
return (s < FD_SETSIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// MSG_NOSIGNAL is not available on some platforms, if it doesn't exist define it as 0
|
||||
#if !defined(MSG_NOSIGNAL)
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
// MSG_DONTWAIT is not available on some platforms, if it doesn't exist define it as 0
|
||||
#if !defined(MSG_DONTWAIT)
|
||||
#define MSG_DONTWAIT 0
|
||||
#endif
|
||||
|
||||
#endif // DIGIBYTE_COMPAT_H
|
||||
57
src/compat/assumptions.h
Normal file
57
src/compat/assumptions.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
// Compile-time verification of assumptions we make.
|
||||
|
||||
#ifndef DIGIBYTE_COMPAT_ASSUMPTIONS_H
|
||||
#define DIGIBYTE_COMPAT_ASSUMPTIONS_H
|
||||
|
||||
#include <limits>
|
||||
|
||||
// Assumption: We assume that the macro NDEBUG is not defined.
|
||||
// Example(s): We use assert(...) extensively with the assumption of it never
|
||||
// being a noop at runtime.
|
||||
#if defined(NDEBUG)
|
||||
# error "Vexta cannot be compiled without assertions."
|
||||
#endif
|
||||
|
||||
// Assumption: We assume a C++17 (ISO/IEC 14882:2017) compiler (minimum requirement).
|
||||
// Example(s): We assume the presence of C++17 features everywhere :-)
|
||||
// ISO Standard C++17 [cpp.predefined]p1:
|
||||
// "The name __cplusplus is defined to the value 201703L when compiling a C++
|
||||
// translation unit."
|
||||
static_assert(__cplusplus >= 201703L, "C++17 standard assumed");
|
||||
|
||||
// Assumption: We assume the floating-point types to fulfill the requirements of
|
||||
// IEC 559 (IEEE 754) standard.
|
||||
// Example(s): Floating-point division by zero in ConnectBlock, CreateTransaction
|
||||
// and EstimateMedianVal.
|
||||
static_assert(std::numeric_limits<float>::is_iec559, "IEEE 754 float assumed");
|
||||
static_assert(std::numeric_limits<double>::is_iec559, "IEEE 754 double assumed");
|
||||
|
||||
// Assumption: We assume eight bits per byte (obviously, but remember: don't
|
||||
// trust -- verify!).
|
||||
// Example(s): Everywhere :-)
|
||||
static_assert(std::numeric_limits<unsigned char>::digits == 8, "8-bit byte assumed");
|
||||
|
||||
// Assumption: We assume integer widths.
|
||||
// Example(s): GetSizeOfCompactSize and WriteCompactSize in the serialization
|
||||
// code.
|
||||
static_assert(sizeof(short) == 2, "16-bit short assumed");
|
||||
static_assert(sizeof(int) == 4, "32-bit int assumed");
|
||||
static_assert(sizeof(unsigned) == 4, "32-bit unsigned assumed");
|
||||
|
||||
// Assumption: We assume size_t to be 32-bit or 64-bit.
|
||||
// Example(s): size_t assumed to be at least 32-bit in ecdsa_signature_parse_der_lax(...).
|
||||
// size_t assumed to be 32-bit or 64-bit in MallocUsage(...).
|
||||
static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t assumed to be 32-bit or 64-bit");
|
||||
static_assert(sizeof(size_t) == sizeof(void*), "Sizes of size_t and void* assumed to be equal");
|
||||
|
||||
// Some important things we are NOT assuming (non-exhaustive list):
|
||||
// * We are NOT assuming a specific value for std::endian::native.
|
||||
// * We are NOT assuming a specific value for std::locale("").name().
|
||||
// * We are NOT assuming a specific value for std::numeric_limits<char>::is_signed.
|
||||
|
||||
#endif // DIGIBYTE_COMPAT_ASSUMPTIONS_H
|
||||
60
src/compat/byteswap.h
Normal file
60
src/compat/byteswap.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2014-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_COMPAT_BYTESWAP_H
|
||||
#define DIGIBYTE_COMPAT_BYTESWAP_H
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(HAVE_BYTESWAP_H)
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#if defined(MAC_OSX)
|
||||
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16(x) OSSwapInt16(x)
|
||||
#define bswap_32(x) OSSwapInt32(x)
|
||||
#define bswap_64(x) OSSwapInt64(x)
|
||||
|
||||
#else
|
||||
// Non-MacOS / non-Darwin
|
||||
|
||||
#if HAVE_DECL_BSWAP_16 == 0
|
||||
inline uint16_t bswap_16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
#endif // HAVE_DECL_BSWAP16 == 0
|
||||
|
||||
#if HAVE_DECL_BSWAP_32 == 0
|
||||
inline uint32_t bswap_32(uint32_t x)
|
||||
{
|
||||
return (((x & 0xff000000U) >> 24) | ((x & 0x00ff0000U) >> 8) |
|
||||
((x & 0x0000ff00U) << 8) | ((x & 0x000000ffU) << 24));
|
||||
}
|
||||
#endif // HAVE_DECL_BSWAP32 == 0
|
||||
|
||||
#if HAVE_DECL_BSWAP_64 == 0
|
||||
inline uint64_t bswap_64(uint64_t x)
|
||||
{
|
||||
return (((x & 0xff00000000000000ull) >> 56)
|
||||
| ((x & 0x00ff000000000000ull) >> 40)
|
||||
| ((x & 0x0000ff0000000000ull) >> 24)
|
||||
| ((x & 0x000000ff00000000ull) >> 8)
|
||||
| ((x & 0x00000000ff000000ull) << 8)
|
||||
| ((x & 0x0000000000ff0000ull) << 24)
|
||||
| ((x & 0x000000000000ff00ull) << 40)
|
||||
| ((x & 0x00000000000000ffull) << 56));
|
||||
}
|
||||
#endif // HAVE_DECL_BSWAP64 == 0
|
||||
|
||||
#endif // defined(MAC_OSX)
|
||||
|
||||
#endif // DIGIBYTE_COMPAT_BYTESWAP_H
|
||||
24
src/compat/cpuid.h
Normal file
24
src/compat/cpuid.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2017-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_COMPAT_CPUID_H
|
||||
#define DIGIBYTE_COMPAT_CPUID_H
|
||||
|
||||
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
|
||||
#define HAVE_GETCPUID
|
||||
|
||||
#include <cpuid.h>
|
||||
|
||||
// We can't use cpuid.h's __get_cpuid as it does not support subleafs.
|
||||
void static inline GetCPUID(uint32_t leaf, uint32_t subleaf, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__cpuid_count(leaf, subleaf, a, b, c, d);
|
||||
#else
|
||||
__asm__ ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(leaf), "2"(subleaf));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
|
||||
#endif // DIGIBYTE_COMPAT_CPUID_H
|
||||
242
src/compat/endian.h
Normal file
242
src/compat/endian.h
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_COMPAT_ENDIAN_H
|
||||
#define DIGIBYTE_COMPAT_ENDIAN_H
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif
|
||||
|
||||
#include <compat/byteswap.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(HAVE_ENDIAN_H)
|
||||
#include <endian.h>
|
||||
#elif defined(HAVE_SYS_ENDIAN_H)
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CONFIG_H
|
||||
// While not technically a supported configuration, defaulting to defining these
|
||||
// DECLs when we were compiled without autotools makes it easier for other build
|
||||
// systems to build things like libvextaconsensus for strange targets.
|
||||
#ifdef htobe16
|
||||
#define HAVE_DECL_HTOBE16 1
|
||||
#endif
|
||||
#ifdef htole16
|
||||
#define HAVE_DECL_HTOLE16 1
|
||||
#endif
|
||||
#ifdef be16toh
|
||||
#define HAVE_DECL_BE16TOH 1
|
||||
#endif
|
||||
#ifdef le16toh
|
||||
#define HAVE_DECL_LE16TOH 1
|
||||
#endif
|
||||
|
||||
#ifdef htobe32
|
||||
#define HAVE_DECL_HTOBE32 1
|
||||
#endif
|
||||
#ifdef htole32
|
||||
#define HAVE_DECL_HTOLE32 1
|
||||
#endif
|
||||
#ifdef be32toh
|
||||
#define HAVE_DECL_BE32TOH 1
|
||||
#endif
|
||||
#ifdef le32toh
|
||||
#define HAVE_DECL_LE32TOH 1
|
||||
#endif
|
||||
|
||||
#ifdef htobe64
|
||||
#define HAVE_DECL_HTOBE64 1
|
||||
#endif
|
||||
#ifdef htole64
|
||||
#define HAVE_DECL_HTOLE64 1
|
||||
#endif
|
||||
#ifdef be64toh
|
||||
#define HAVE_DECL_BE64TOH 1
|
||||
#endif
|
||||
#ifdef le64toh
|
||||
#define HAVE_DECL_LE64TOH 1
|
||||
#endif
|
||||
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#if defined(WORDS_BIGENDIAN)
|
||||
|
||||
#if HAVE_DECL_HTOBE16 == 0
|
||||
inline uint16_t htobe16(uint16_t host_16bits)
|
||||
{
|
||||
return host_16bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE16
|
||||
|
||||
#if HAVE_DECL_HTOLE16 == 0
|
||||
inline uint16_t htole16(uint16_t host_16bits)
|
||||
{
|
||||
return bswap_16(host_16bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE16
|
||||
|
||||
#if HAVE_DECL_BE16TOH == 0
|
||||
inline uint16_t be16toh(uint16_t big_endian_16bits)
|
||||
{
|
||||
return big_endian_16bits;
|
||||
}
|
||||
#endif // HAVE_DECL_BE16TOH
|
||||
|
||||
#if HAVE_DECL_LE16TOH == 0
|
||||
inline uint16_t le16toh(uint16_t little_endian_16bits)
|
||||
{
|
||||
return bswap_16(little_endian_16bits);
|
||||
}
|
||||
#endif // HAVE_DECL_LE16TOH
|
||||
|
||||
#if HAVE_DECL_HTOBE32 == 0
|
||||
inline uint32_t htobe32(uint32_t host_32bits)
|
||||
{
|
||||
return host_32bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE32
|
||||
|
||||
#if HAVE_DECL_HTOLE32 == 0
|
||||
inline uint32_t htole32(uint32_t host_32bits)
|
||||
{
|
||||
return bswap_32(host_32bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE32
|
||||
|
||||
#if HAVE_DECL_BE32TOH == 0
|
||||
inline uint32_t be32toh(uint32_t big_endian_32bits)
|
||||
{
|
||||
return big_endian_32bits;
|
||||
}
|
||||
#endif // HAVE_DECL_BE32TOH
|
||||
|
||||
#if HAVE_DECL_LE32TOH == 0
|
||||
inline uint32_t le32toh(uint32_t little_endian_32bits)
|
||||
{
|
||||
return bswap_32(little_endian_32bits);
|
||||
}
|
||||
#endif // HAVE_DECL_LE32TOH
|
||||
|
||||
#if HAVE_DECL_HTOBE64 == 0
|
||||
inline uint64_t htobe64(uint64_t host_64bits)
|
||||
{
|
||||
return host_64bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE64
|
||||
|
||||
#if HAVE_DECL_HTOLE64 == 0
|
||||
inline uint64_t htole64(uint64_t host_64bits)
|
||||
{
|
||||
return bswap_64(host_64bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE64
|
||||
|
||||
#if HAVE_DECL_BE64TOH == 0
|
||||
inline uint64_t be64toh(uint64_t big_endian_64bits)
|
||||
{
|
||||
return big_endian_64bits;
|
||||
}
|
||||
#endif // HAVE_DECL_BE64TOH
|
||||
|
||||
#if HAVE_DECL_LE64TOH == 0
|
||||
inline uint64_t le64toh(uint64_t little_endian_64bits)
|
||||
{
|
||||
return bswap_64(little_endian_64bits);
|
||||
}
|
||||
#endif // HAVE_DECL_LE64TOH
|
||||
|
||||
#else // WORDS_BIGENDIAN
|
||||
|
||||
#if HAVE_DECL_HTOBE16 == 0
|
||||
inline uint16_t htobe16(uint16_t host_16bits)
|
||||
{
|
||||
return bswap_16(host_16bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE16
|
||||
|
||||
#if HAVE_DECL_HTOLE16 == 0
|
||||
inline uint16_t htole16(uint16_t host_16bits)
|
||||
{
|
||||
return host_16bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE16
|
||||
|
||||
#if HAVE_DECL_BE16TOH == 0
|
||||
inline uint16_t be16toh(uint16_t big_endian_16bits)
|
||||
{
|
||||
return bswap_16(big_endian_16bits);
|
||||
}
|
||||
#endif // HAVE_DECL_BE16TOH
|
||||
|
||||
#if HAVE_DECL_LE16TOH == 0
|
||||
inline uint16_t le16toh(uint16_t little_endian_16bits)
|
||||
{
|
||||
return little_endian_16bits;
|
||||
}
|
||||
#endif // HAVE_DECL_LE16TOH
|
||||
|
||||
#if HAVE_DECL_HTOBE32 == 0
|
||||
inline uint32_t htobe32(uint32_t host_32bits)
|
||||
{
|
||||
return bswap_32(host_32bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE32
|
||||
|
||||
#if HAVE_DECL_HTOLE32 == 0
|
||||
inline uint32_t htole32(uint32_t host_32bits)
|
||||
{
|
||||
return host_32bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE32
|
||||
|
||||
#if HAVE_DECL_BE32TOH == 0
|
||||
inline uint32_t be32toh(uint32_t big_endian_32bits)
|
||||
{
|
||||
return bswap_32(big_endian_32bits);
|
||||
}
|
||||
#endif // HAVE_DECL_BE32TOH
|
||||
|
||||
#if HAVE_DECL_LE32TOH == 0
|
||||
inline uint32_t le32toh(uint32_t little_endian_32bits)
|
||||
{
|
||||
return little_endian_32bits;
|
||||
}
|
||||
#endif // HAVE_DECL_LE32TOH
|
||||
|
||||
#if HAVE_DECL_HTOBE64 == 0
|
||||
inline uint64_t htobe64(uint64_t host_64bits)
|
||||
{
|
||||
return bswap_64(host_64bits);
|
||||
}
|
||||
#endif // HAVE_DECL_HTOBE64
|
||||
|
||||
#if HAVE_DECL_HTOLE64 == 0
|
||||
inline uint64_t htole64(uint64_t host_64bits)
|
||||
{
|
||||
return host_64bits;
|
||||
}
|
||||
#endif // HAVE_DECL_HTOLE64
|
||||
|
||||
#if HAVE_DECL_BE64TOH == 0
|
||||
inline uint64_t be64toh(uint64_t big_endian_64bits)
|
||||
{
|
||||
return bswap_64(big_endian_64bits);
|
||||
}
|
||||
#endif // HAVE_DECL_BE64TOH
|
||||
|
||||
#if HAVE_DECL_LE64TOH == 0
|
||||
inline uint64_t le64toh(uint64_t little_endian_64bits)
|
||||
{
|
||||
return little_endian_64bits;
|
||||
}
|
||||
#endif // HAVE_DECL_LE64TOH
|
||||
|
||||
#endif // WORDS_BIGENDIAN
|
||||
|
||||
#endif // DIGIBYTE_COMPAT_ENDIAN_H
|
||||
63
src/compat/glibc_compat.cpp
Normal file
63
src/compat/glibc_compat.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__i386__) || defined(__arm__)
|
||||
|
||||
extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);
|
||||
|
||||
extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
|
||||
{
|
||||
int32_t c1 = 0, c2 = 0;
|
||||
int64_t uu = u, vv = v;
|
||||
int64_t w;
|
||||
int64_t r;
|
||||
|
||||
if (uu < 0) {
|
||||
c1 = ~c1, c2 = ~c2, uu = -uu;
|
||||
}
|
||||
if (vv < 0) {
|
||||
c1 = ~c1, vv = -vv;
|
||||
}
|
||||
|
||||
w = __udivmoddi4(uu, vv, (uint64_t*)&r);
|
||||
if (c1)
|
||||
w = -w;
|
||||
if (c2)
|
||||
r = -r;
|
||||
|
||||
*rp = r;
|
||||
return w;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" float log2f_old(float x);
|
||||
#ifdef __i386__
|
||||
__asm(".symver log2f_old,log2f@GLIBC_2.1");
|
||||
#elif defined(__amd64__)
|
||||
__asm(".symver log2f_old,log2f@GLIBC_2.2.5");
|
||||
#elif defined(__arm__)
|
||||
__asm(".symver log2f_old,log2f@GLIBC_2.4");
|
||||
#elif defined(__aarch64__)
|
||||
__asm(".symver log2f_old,log2f@GLIBC_2.17");
|
||||
#elif defined(__powerpc64__)
|
||||
# ifdef WORDS_BIGENDIAN
|
||||
__asm(".symver log2f_old,log2f@GLIBC_2.3");
|
||||
# else
|
||||
__asm(".symver log2f_old,log2f@GLIBC_2.17");
|
||||
# endif
|
||||
#elif defined(__riscv)
|
||||
__asm(".symver log2f_old,log2f@GLIBC_2.27");
|
||||
#endif
|
||||
extern "C" float __wrap_log2f(float x)
|
||||
{
|
||||
return log2f_old(x);
|
||||
}
|
||||
69
src/compat/glibc_sanity.cpp
Normal file
69
src/compat/glibc_sanity.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(HAVE_SYS_SELECT_H)
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
extern "C" void* memcpy(void* a, const void* b, size_t c);
|
||||
void* memcpy_int(void* a, const void* b, size_t c)
|
||||
{
|
||||
return memcpy(a, b, c);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// trigger: Use the memcpy_int wrapper which calls our internal memcpy.
|
||||
// A direct call to memcpy may be optimized away by the compiler.
|
||||
// test: Fill an array with a sequence of integers. memcpy to a new empty array.
|
||||
// Verify that the arrays are equal. Use an odd size to decrease the odds of
|
||||
// the call being optimized away.
|
||||
template <unsigned int T>
|
||||
bool sanity_test_memcpy()
|
||||
{
|
||||
unsigned int memcpy_test[T];
|
||||
unsigned int memcpy_verify[T] = {};
|
||||
for (unsigned int i = 0; i != T; ++i)
|
||||
memcpy_test[i] = i;
|
||||
|
||||
memcpy_int(memcpy_verify, memcpy_test, sizeof(memcpy_test));
|
||||
|
||||
for (unsigned int i = 0; i != T; ++i) {
|
||||
if (memcpy_verify[i] != i)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(HAVE_SYS_SELECT_H)
|
||||
// trigger: Call FD_SET to trigger __fdelt_chk. FORTIFY_SOURCE must be defined
|
||||
// as >0 and optimizations must be set to at least -O2.
|
||||
// test: Add a file descriptor to an empty fd_set. Verify that it has been
|
||||
// correctly added.
|
||||
bool sanity_test_fdelt()
|
||||
{
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
return FD_ISSET(0, &fds);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
bool glibc_sanity_test()
|
||||
{
|
||||
#if defined(HAVE_SYS_SELECT_H)
|
||||
if (!sanity_test_fdelt())
|
||||
return false;
|
||||
#endif
|
||||
return sanity_test_memcpy<1025>();
|
||||
}
|
||||
62
src/compat/glibcxx_sanity.cpp
Normal file
62
src/compat/glibcxx_sanity.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <list>
|
||||
#include <locale>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace
|
||||
{
|
||||
// trigger: use ctype<char>::widen to trigger ctype<char>::_M_widen_init().
|
||||
// test: convert a char from narrow to wide and back. Verify that the result
|
||||
// matches the original.
|
||||
bool sanity_test_widen(char testchar)
|
||||
{
|
||||
const std::ctype<char>& test(std::use_facet<std::ctype<char> >(std::locale()));
|
||||
return test.narrow(test.widen(testchar), 'b') == testchar;
|
||||
}
|
||||
|
||||
// trigger: use list::push_back and list::pop_back to trigger _M_hook and
|
||||
// _M_unhook.
|
||||
// test: Push a sequence of integers into a list. Pop them off and verify that
|
||||
// they match the original sequence.
|
||||
bool sanity_test_list(unsigned int size)
|
||||
{
|
||||
std::list<unsigned int> test;
|
||||
for (unsigned int i = 0; i != size; ++i)
|
||||
test.push_back(i + 1);
|
||||
|
||||
if (test.size() != size)
|
||||
return false;
|
||||
|
||||
while (!test.empty()) {
|
||||
if (test.back() != test.size())
|
||||
return false;
|
||||
test.pop_back();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// trigger: string::at(x) on an empty string to trigger __throw_out_of_range_fmt.
|
||||
// test: force std::string to throw an out_of_range exception. Verify that
|
||||
// it's caught correctly.
|
||||
bool sanity_test_range_fmt()
|
||||
{
|
||||
std::string test;
|
||||
try {
|
||||
test.at(1);
|
||||
} catch (const std::out_of_range&) {
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool glibcxx_sanity_test()
|
||||
{
|
||||
return sanity_test_widen('a') && sanity_test_list(100) && sanity_test_range_fmt();
|
||||
}
|
||||
10
src/compat/sanity.h
Normal file
10
src/compat/sanity.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) 2009-2014 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_COMPAT_SANITY_H
|
||||
#define DIGIBYTE_COMPAT_SANITY_H
|
||||
|
||||
bool glibcxx_sanity_test();
|
||||
|
||||
#endif // DIGIBYTE_COMPAT_SANITY_H
|
||||
72
src/compat/stdin.cpp
Normal file
72
src/compat/stdin.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2018-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio> // for fileno(), stdin
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h> // for SetStdinEcho()
|
||||
#include <io.h> // for isatty()
|
||||
#else
|
||||
#include <termios.h> // for SetStdinEcho()
|
||||
#include <unistd.h> // for SetStdinEcho(), isatty()
|
||||
#include <poll.h> // for StdinReady()
|
||||
#endif
|
||||
|
||||
#include <compat/stdin.h>
|
||||
|
||||
// https://stackoverflow.com/questions/1413445/reading-a-password-from-stdcin
|
||||
void SetStdinEcho(bool enable)
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DWORD mode;
|
||||
GetConsoleMode(hStdin, &mode);
|
||||
if (!enable) {
|
||||
mode &= ~ENABLE_ECHO_INPUT;
|
||||
} else {
|
||||
mode |= ENABLE_ECHO_INPUT;
|
||||
}
|
||||
SetConsoleMode(hStdin, mode);
|
||||
#else
|
||||
struct termios tty;
|
||||
tcgetattr(STDIN_FILENO, &tty);
|
||||
if (!enable) {
|
||||
tty.c_lflag &= ~ECHO;
|
||||
} else {
|
||||
tty.c_lflag |= ECHO;
|
||||
}
|
||||
(void)tcsetattr(STDIN_FILENO, TCSANOW, &tty);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool StdinTerminal()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return _isatty(_fileno(stdin));
|
||||
#else
|
||||
return isatty(fileno(stdin));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool StdinReady()
|
||||
{
|
||||
if (!StdinTerminal()) {
|
||||
return true;
|
||||
}
|
||||
#ifdef WIN32
|
||||
return false;
|
||||
#else
|
||||
struct pollfd fds;
|
||||
fds.fd = 0; /* this is STDIN */
|
||||
fds.events = POLLIN;
|
||||
return poll(&fds, 1, 0) == 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
NoechoInst::NoechoInst() { SetStdinEcho(false); }
|
||||
NoechoInst::~NoechoInst() { SetStdinEcho(true); }
|
||||
18
src/compat/stdin.h
Normal file
18
src/compat/stdin.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2018 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_COMPAT_STDIN_H
|
||||
#define DIGIBYTE_COMPAT_STDIN_H
|
||||
|
||||
struct NoechoInst {
|
||||
NoechoInst();
|
||||
~NoechoInst();
|
||||
};
|
||||
|
||||
#define NO_STDIN_ECHO() NoechoInst _no_echo
|
||||
|
||||
bool StdinTerminal();
|
||||
bool StdinReady();
|
||||
|
||||
#endif // DIGIBYTE_COMPAT_STDIN_H
|
||||
19
src/compat/strnlen.cpp
Normal file
19
src/compat/strnlen.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#if HAVE_DECL_STRNLEN == 0
|
||||
size_t strnlen( const char *start, size_t max_len)
|
||||
{
|
||||
const char *end = (const char *)memchr(start, '\0', max_len);
|
||||
|
||||
return end ? (size_t)(end - start) : max_len;
|
||||
}
|
||||
#endif // HAVE_DECL_STRNLEN
|
||||
193
src/compressor.cpp
Normal file
193
src/compressor.cpp
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <compressor.h>
|
||||
|
||||
#include <pubkey.h>
|
||||
#include <script/standard.h>
|
||||
|
||||
/*
|
||||
* These check for scripts for which a special case with a shorter encoding is defined.
|
||||
* They are implemented separately from the CScript test, as these test for exact byte
|
||||
* sequence correspondences, and are more strict. For example, IsToPubKey also verifies
|
||||
* whether the public key is valid (as invalid ones cannot be represented in compressed
|
||||
* form).
|
||||
*/
|
||||
|
||||
static bool IsToKeyID(const CScript& script, CKeyID &hash)
|
||||
{
|
||||
if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160
|
||||
&& script[2] == 20 && script[23] == OP_EQUALVERIFY
|
||||
&& script[24] == OP_CHECKSIG) {
|
||||
memcpy(&hash, &script[3], 20);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsToScriptID(const CScript& script, CScriptID &hash)
|
||||
{
|
||||
if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20
|
||||
&& script[22] == OP_EQUAL) {
|
||||
memcpy(&hash, &script[2], 20);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsToPubKey(const CScript& script, CPubKey &pubkey)
|
||||
{
|
||||
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
|
||||
&& (script[1] == 0x02 || script[1] == 0x03)) {
|
||||
pubkey.Set(&script[1], &script[34]);
|
||||
return true;
|
||||
}
|
||||
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
|
||||
&& script[1] == 0x04) {
|
||||
pubkey.Set(&script[1], &script[66]);
|
||||
return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CompressScript(const CScript& script, CompressedScript& out)
|
||||
{
|
||||
CKeyID keyID;
|
||||
if (IsToKeyID(script, keyID)) {
|
||||
out.resize(21);
|
||||
out[0] = 0x00;
|
||||
memcpy(&out[1], &keyID, 20);
|
||||
return true;
|
||||
}
|
||||
CScriptID scriptID;
|
||||
if (IsToScriptID(script, scriptID)) {
|
||||
out.resize(21);
|
||||
out[0] = 0x01;
|
||||
memcpy(&out[1], &scriptID, 20);
|
||||
return true;
|
||||
}
|
||||
CPubKey pubkey;
|
||||
if (IsToPubKey(script, pubkey)) {
|
||||
out.resize(33);
|
||||
memcpy(&out[1], &pubkey[1], 32);
|
||||
if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
|
||||
out[0] = pubkey[0];
|
||||
return true;
|
||||
} else if (pubkey[0] == 0x04) {
|
||||
out[0] = 0x04 | (pubkey[64] & 0x01);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int GetSpecialScriptSize(unsigned int nSize)
|
||||
{
|
||||
if (nSize == 0 || nSize == 1)
|
||||
return 20;
|
||||
if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)
|
||||
return 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in)
|
||||
{
|
||||
switch(nSize) {
|
||||
case 0x00:
|
||||
script.resize(25);
|
||||
script[0] = OP_DUP;
|
||||
script[1] = OP_HASH160;
|
||||
script[2] = 20;
|
||||
memcpy(&script[3], in.data(), 20);
|
||||
script[23] = OP_EQUALVERIFY;
|
||||
script[24] = OP_CHECKSIG;
|
||||
return true;
|
||||
case 0x01:
|
||||
script.resize(23);
|
||||
script[0] = OP_HASH160;
|
||||
script[1] = 20;
|
||||
memcpy(&script[2], in.data(), 20);
|
||||
script[22] = OP_EQUAL;
|
||||
return true;
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
script.resize(35);
|
||||
script[0] = 33;
|
||||
script[1] = nSize;
|
||||
memcpy(&script[2], in.data(), 32);
|
||||
script[34] = OP_CHECKSIG;
|
||||
return true;
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
unsigned char vch[33] = {};
|
||||
vch[0] = nSize - 2;
|
||||
memcpy(&vch[1], in.data(), 32);
|
||||
CPubKey pubkey{vch};
|
||||
if (!pubkey.Decompress())
|
||||
return false;
|
||||
assert(pubkey.size() == 65);
|
||||
script.resize(67);
|
||||
script[0] = 65;
|
||||
memcpy(&script[1], pubkey.begin(), 65);
|
||||
script[66] = OP_CHECKSIG;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Amount compression:
|
||||
// * If the amount is 0, output 0
|
||||
// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
|
||||
// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)
|
||||
// * call the result n
|
||||
// * output 1 + 10*(9*n + d - 1) + e
|
||||
// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
|
||||
// (this is decodable, as d is in [1-9] and e is in [0-9])
|
||||
|
||||
uint64_t CompressAmount(uint64_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return 0;
|
||||
int e = 0;
|
||||
while (((n % 10) == 0) && e < 9) {
|
||||
n /= 10;
|
||||
e++;
|
||||
}
|
||||
if (e < 9) {
|
||||
int d = (n % 10);
|
||||
assert(d >= 1 && d <= 9);
|
||||
n /= 10;
|
||||
return 1 + (n*9 + d - 1)*10 + e;
|
||||
} else {
|
||||
return 1 + (n - 1)*10 + 9;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t DecompressAmount(uint64_t x)
|
||||
{
|
||||
// x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9
|
||||
if (x == 0)
|
||||
return 0;
|
||||
x--;
|
||||
// x = 10*(9*n + d - 1) + e
|
||||
int e = x % 10;
|
||||
x /= 10;
|
||||
uint64_t n = 0;
|
||||
if (e < 9) {
|
||||
// x = 9*n + d - 1
|
||||
int d = (x % 9) + 1;
|
||||
x /= 9;
|
||||
// x = n
|
||||
n = x*10 + d;
|
||||
} else {
|
||||
n = x+1;
|
||||
}
|
||||
while (e) {
|
||||
n *= 10;
|
||||
e--;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
119
src/compressor.h
Normal file
119
src/compressor.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_COMPRESSOR_H
|
||||
#define DIGIBYTE_COMPRESSOR_H
|
||||
|
||||
#include <prevector.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/script.h>
|
||||
#include <serialize.h>
|
||||
#include <span.h>
|
||||
|
||||
/**
|
||||
* This saves us from making many heap allocations when serializing
|
||||
* and deserializing compressed scripts.
|
||||
*
|
||||
* This prevector size is determined by the largest .resize() in the
|
||||
* CompressScript function. The largest compressed script format is a
|
||||
* compressed public key, which is 33 bytes.
|
||||
*/
|
||||
using CompressedScript = prevector<33, unsigned char>;
|
||||
|
||||
|
||||
bool CompressScript(const CScript& script, CompressedScript& out);
|
||||
unsigned int GetSpecialScriptSize(unsigned int nSize);
|
||||
bool DecompressScript(CScript& script, unsigned int nSize, const CompressedScript& in);
|
||||
|
||||
/**
|
||||
* Compress amount.
|
||||
*
|
||||
* nAmount is of type uint64_t and thus cannot be negative. If you're passing in
|
||||
* a CAmount (int64_t), make sure to properly handle the case where the amount
|
||||
* is negative before calling CompressAmount(...).
|
||||
*
|
||||
* @pre Function defined only for 0 <= nAmount <= MAX_MONEY.
|
||||
*/
|
||||
uint64_t CompressAmount(uint64_t nAmount);
|
||||
|
||||
uint64_t DecompressAmount(uint64_t nAmount);
|
||||
|
||||
/** Compact serializer for scripts.
|
||||
*
|
||||
* It detects common cases and encodes them much more efficiently.
|
||||
* 3 special cases are defined:
|
||||
* * Pay to pubkey hash (encoded as 21 bytes)
|
||||
* * Pay to script hash (encoded as 21 bytes)
|
||||
* * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes)
|
||||
*
|
||||
* Other scripts up to 121 bytes require 1 byte + script length. Above
|
||||
* that, scripts up to 16505 bytes require 2 bytes + script length.
|
||||
*/
|
||||
struct ScriptCompression
|
||||
{
|
||||
/**
|
||||
* make this static for now (there are only 6 special scripts defined)
|
||||
* this can potentially be extended together with a new nVersion for
|
||||
* transactions, in which case this value becomes dependent on nVersion
|
||||
* and nHeight of the enclosing transaction.
|
||||
*/
|
||||
static const unsigned int nSpecialScripts = 6;
|
||||
|
||||
template<typename Stream>
|
||||
void Ser(Stream &s, const CScript& script) {
|
||||
CompressedScript compr;
|
||||
if (CompressScript(script, compr)) {
|
||||
s << MakeSpan(compr);
|
||||
return;
|
||||
}
|
||||
unsigned int nSize = script.size() + nSpecialScripts;
|
||||
s << VARINT(nSize);
|
||||
s << MakeSpan(script);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unser(Stream &s, CScript& script) {
|
||||
unsigned int nSize = 0;
|
||||
s >> VARINT(nSize);
|
||||
if (nSize < nSpecialScripts) {
|
||||
CompressedScript vch(GetSpecialScriptSize(nSize), 0x00);
|
||||
s >> MakeSpan(vch);
|
||||
DecompressScript(script, nSize, vch);
|
||||
return;
|
||||
}
|
||||
nSize -= nSpecialScripts;
|
||||
if (nSize > MAX_SCRIPT_SIZE) {
|
||||
// Overly long script, replace with a short invalid one
|
||||
script << OP_RETURN;
|
||||
s.ignore(nSize);
|
||||
} else {
|
||||
script.resize(nSize);
|
||||
s >> MakeSpan(script);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct AmountCompression
|
||||
{
|
||||
template<typename Stream, typename I> void Ser(Stream& s, I val)
|
||||
{
|
||||
s << VARINT(CompressAmount(val));
|
||||
}
|
||||
template<typename Stream, typename I> void Unser(Stream& s, I& val)
|
||||
{
|
||||
uint64_t v;
|
||||
s >> VARINT(v);
|
||||
val = DecompressAmount(v);
|
||||
}
|
||||
};
|
||||
|
||||
/** wrapper for CTxOut that provides a more compact serialization */
|
||||
struct TxOutCompression
|
||||
{
|
||||
FORMATTER_METHODS(CTxOut, obj) { READWRITE(Using<AmountCompression>(obj.nValue), Using<ScriptCompression>(obj.scriptPubKey)); }
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_COMPRESSOR_H
|
||||
0
src/config/.empty
Normal file
0
src/config/.empty
Normal file
37
src/consensus/consensus.h
Normal file
37
src/consensus/consensus.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_CONSENSUS_CONSENSUS_H
|
||||
#define DIGIBYTE_CONSENSUS_CONSENSUS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */
|
||||
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000;
|
||||
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
|
||||
static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
|
||||
|
||||
/** The maximum allowed number of signature check operations in a block (network rule) */
|
||||
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;
|
||||
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
|
||||
static const int COINBASE_MATURITY = 8;
|
||||
static const int COINBASE_MATURITY_2 = 100;
|
||||
/** The maximum allowed number of signature check operations in a block (network rule) */
|
||||
|
||||
|
||||
static const int WITNESS_SCALE_FACTOR = 4;
|
||||
|
||||
static const size_t MIN_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 60; // 60 is the lower bound for the size of a valid serialized CTransaction
|
||||
static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10; // 10 is the lower bound for the size of a serialized CTransaction
|
||||
|
||||
/** Flags for nSequence and nLockTime locks */
|
||||
/** Interpret sequence numbers as relative lock-time constraints. */
|
||||
static constexpr unsigned int LOCKTIME_VERIFY_SEQUENCE = (1 << 0);
|
||||
/** Use GetMedianTimePast() instead of nTime for end point timestamp. */
|
||||
static constexpr unsigned int LOCKTIME_MEDIAN_TIME_PAST = (1 << 1);
|
||||
|
||||
#endif // DIGIBYTE_CONSENSUS_CONSENSUS_H
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue