Rebase LBRY on top of Bitcoin 0.17 #263

Closed
lbrynaut wants to merge 18 commits from updated-rebase-0.17-deps into bitcoin-0.17
59 changed files with 6844 additions and 2063 deletions
Showing only changes of commit 68a8864847 - Show all commits

View file

@ -146,6 +146,12 @@ AC_ARG_WITH([qrencode],
[use_qr=$withval],
[use_qr=auto])
AC_ARG_WITH([icu],
[AS_HELP_STRING([--with-icu],
[Required ICU root path])],
[ICU_PREFIX=$withval],
[ICU_PREFIX=auto])
AC_ARG_ENABLE([hardening],
[AS_HELP_STRING([--disable-hardening],
[do not attempt to harden the resulting executables (default is to harden when possible)])],
@ -640,6 +646,7 @@ if test x$ac_cv_sys_large_files != x &&
CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=$ac_cv_sys_large_files"
fi
AX_CHECK_LINK_FLAG([[-static-libstdc++]], [LDFLAGS="$LDFLAGS -static-libstdc++"])
AX_CHECK_LINK_FLAG([[-Wl,--large-address-aware]], [LDFLAGS="$LDFLAGS -Wl,--large-address-aware"])
AX_GCC_FUNC_ATTRIBUTE([visibility])
@ -895,6 +902,7 @@ AX_BOOST_SYSTEM
AX_BOOST_FILESYSTEM
AX_BOOST_THREAD
AX_BOOST_CHRONO
AX_BOOST_LOCALE
dnl Boost 1.56 through 1.62 allow using std::atomic instead of its own atomic
dnl counter implementations. In 1.63 and later the std::atomic approach is default.
@ -961,7 +969,7 @@ fi
if test x$use_boost = xyes; then
BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB"
BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB $BOOST_LOCALE_LIB"
dnl If boost (prior to 1.57) was built without c++11, it emulated scoped enums
@ -1057,6 +1065,16 @@ if test x$use_pkgconfig = xyes; then
m4_ifdef(
[PKG_CHECK_MODULES],
[
ICU_CPPFLAGS="-I$ICU_PREFIX/include"
CPPFLAGS="$ICU_CPPFLAGS $CPPFLAGS"
ICU_LIBS="-L$ICU_PREFIX/lib -licui18n -licuuc -licudata -ldl"
AC_MSG_WARN([Using ICU_CPPFLAGS $ICU_CPPFLAGS])
AC_MSG_WARN([Using CPPFLAGS $CPPFLAGS])
AC_CHECK_HEADER([unicode/errorcode.h],,AC_MSG_ERROR(libicu headers missing))
AC_CHECK_LIB([icudata], [main], ICU_LIBS="-L$ICU_PREFIX/lib -licui18n -licuuc -licudata -ldl",
AC_CHECK_LIB([icu18n], [main],ICU_LIBS=$ICU_LIBS, ICU_LIBS="-L$ICU_PREFIX/lib -lsicudt -lsicuin -lsicuio -lsicule -lsiculx -lsicutest -lsicutu -lsicuuc"))
PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl not found.)])
PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto not found.)])
BITCOIN_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [BITCOIN_QT_FAIL(libprotobuf not found)])])
@ -1082,6 +1100,18 @@ if test x$use_pkgconfig = xyes; then
]
)
else
ICU_CPPFLAGS="-I$ICU_PREFIX/include"
CPPFLAGS="$ICU_CPPFLAGS $CPPFLAGS"
ICU_LIBS="-L$ICU_PREFIX/lib -licui18n -licuuc -licudata -ldl"
AC_MSG_WARN([Using ICU_CPPFLAGS $ICU_CPPFLAGS])
AC_MSG_WARN([Using ICU_LIBS $ICU_LIBS])
AC_MSG_WARN([Using CPPFLAGS $CPPFLAGS])
AC_CHECK_HEADER([unicode/errorcode.h],,AC_MSG_ERROR(libicu headers missing))
AC_CHECK_LIB([icudata], [main], ICU_LIBS="-L$ICU_PREFIX/lib -licui18n -licuuc -licudata -ldl",
AC_CHECK_LIB([icu18n], [main],ICU_LIBS=$ICU_LIBS, ICU_LIBS="-L$ICU_PREFIX/lib -lsicudt -lsicuin -lsicuio -lsicule -lsiculx -lsicutest -lsicutu -lsicuuc"))
AC_CHECK_HEADER([openssl/crypto.h],,AC_MSG_ERROR(libcrypto headers missing))
AC_CHECK_LIB([crypto], [main],CRYPTO_LIBS=-lcrypto, AC_MSG_ERROR(libcrypto missing))
@ -1385,6 +1415,9 @@ AC_SUBST(LIBTOOL_APP_LDFLAGS)
AC_SUBST(USE_UPNP)
AC_SUBST(USE_QRCODE)
AC_SUBST(BOOST_LIBS)
AC_SUBST(ICU_PREFIX)
AC_SUBST(ICU_CPPFLAGS)
AC_SUBST(ICU_LIBS)
AC_SUBST(TESTDEFS)
AC_SUBST(LEVELDB_TARGET_FLAGS)
AC_SUBST(MINIUPNPC_CPPFLAGS)
@ -1431,7 +1464,7 @@ if test x$need_bundled_univalue = xyes; then
AC_CONFIG_SUBDIRS([src/univalue])
fi
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery --disable-jni"
ac_configure_args="${ac_configure_args} --enable-static --disable-shared --with-pic --with-bignum=no --enable-module-recovery --disable-jni"
AC_CONFIG_SUBDIRS([src/secp256k1])
AC_OUTPUT

457
reproducible_build.sh Executable file
View file

@ -0,0 +1,457 @@
#!/bin/bash
set -xeuo pipefail
function HELP {
echo "Build lbrycrd"
echo "-----"
echo "When run without any arguments, this script expects the current directory"
echo "to be the lbrycrd repo and it builds what is in that directory"
echo
echo "This is a long build process so it can be split into two parts"
echo "Specify the -d flag to build only the dependencies"
echo "and the -l flag to build only lbrycrd. This will fail"
echo "if the dependencies weren't built earlier"
echo
echo "Optional arguments:"
echo
echo "-c: don't clone a fresh copy of the repo"
echo "-f: check formatting of committed code relative to master"
echo "-r: remove intermediate files."
echo "-l: build only lbrycrd"
echo "-d: build only the dependencies"
echo "-o: timeout build after 40 minutes"
echo "-t: turn trace on"
echo "-h: show help"
exit 1
}
CLONE=true
CLEAN=false
CHECK_CODE_FORMAT=false
BUILD_DEPENDENCIES=true
BUILD_LBRYCRD=true
TIMEOUT=false
THREE_MB=3145728
# this flag gets set to False if
# the script exits due to a timeout
OUTPUT_LOG=true
while getopts :crfldoth:w:d: FLAG; do
case $FLAG in
c)
CLONE=false
;;
r)
CLEAN=true
;;
f)
CHECK_CODE_FORMAT=true
;;
l)
BUILD_DEPENDENCIES=false
;;
d)
BUILD_LBRYCRD=false
;;
o)
TIMEOUT=true
;;
t)
set -o xtrace
;;
h)
HELP
;;
\?) #unrecognized option - show help
echo "Option -$OPTARG not allowed."
HELP
;;
:)
echo "Option -$OPTARG requires an argument."
HELP
;;
esac
done
shift $((OPTIND-1))
SUDO=''
if (( EUID != 0 )); then
SUDO='sudo'
fi
if [ "${CLONE}" = false ]; then
if [ "$(basename "$PWD")" != "lbrycrd" ]; then
echo "Not currently in the lbrycrd directory. Cowardly refusing to go forward"
exit 1
fi
SOURCE_DIR=$PWD
fi
if [ -z "${TRAVIS_OS_NAME+x}" ]; then
if [ "$(uname -s)" = "Darwin" ]; then
OS_NAME="osx"
else
OS_NAME="linux"
fi
else
OS_NAME="${TRAVIS_OS_NAME}"
fi
if [ -z "${TRAVIS_BUILD_DIR+x}" ]; then
START_TIME_FILE="$PWD/start_time"
else
# if we are on travis (the primary use case for setting a timeout)
# this file is created when the build starts
START_TIME_FILE="$TRAVIS_BUILD_DIR/start_time"
fi
rm -f ${START_TIME_FILE}
date +%s > ${START_TIME_FILE}
NEXT_TIME=60
function exit_at_60() {
if [ -f "${START_TIME_FILE}" ]; then
NOW=$(date +%s)
START=$(cat "${START_TIME_FILE}")
TIMEOUT_SECS=3600 # 60 * 60
TIME=$((NOW - START))
if (( TIME > NEXT_TIME )); then
echo "Build has taken $((TIME / 60)) minutes: $1"
NEXT_TIME=$((TIME + 60))
fi
if [ "$TIMEOUT" = true ] && (( TIME > TIMEOUT_SECS )); then
echo 'Exiting at 60 minutes to allow the cache to populate'
OUTPUT_LOG=false
exit 1
fi
fi
}
# two arguments
# - pid (probably from $!)
# - echo message
function wait_and_echo() {
PID=$1
(set -o | grep xtrace | grep -q on)
TRACE_STATUS=$?
# disable xtrace or else this will get verbose, which is what
# I'm trying to avoid by going through all of this nonsense anyway
set +o xtrace
TIME=0
SLEEP=5
# loop until the process is no longer running
# check every $SLEEP seconds, echoing a message every minute
while (ps -p "${PID}" > /dev/null); do
exit_at_60 "$2"
sleep "${SLEEP}"
done
# restore the xtrace setting
if [ "${TRACE_STATUS}" -eq 0 ]; then
set -o xtrace
fi
wait "$PID"
return $?
}
# run a command ($1) in the background
# logging its stdout and stderr to $2
# and wait until it completed
function background() {
$1 >> "$2" 2>&1 &
BACKGROUND_PID=$!
wait_and_echo $BACKGROUND_PID "$3"
}
function cleanup() {
rv=$?
# cat the log file if it exists
if [ -f "$2" ] && [ "${OUTPUT_LOG}" = true ]; then
echo
echo "Output of log file $2"
echo
tail -n 1000 "$2"
echo
fi
# delete the build directory
rm -rf "$1"
echo "Build failed. Removing $1"
exit $rv
}
function cat_and_exit() {
rv=$?
# cat the log file if it exists
if [ -f "$1" ] && [ "${OUTPUT_LOG}" = true ]; then
echo
echo "Output of log file $1"
echo
# This used to be the last 3MB but outputing that
# caused problems on travis.
# Hopefully the last 1000 lines is enough
# to debug whatever went wrong
tail -n 1000 "$1"
echo
fi
exit $rv
}
function brew_if_not_installed() {
if ! brew ls | grep $1 --quiet; then
brew install $1
fi
}
function install_brew_packages() {
brew update > /dev/null
brew unlink python
brew_if_not_installed autoconf
brew_if_not_installed automake
# something weird happened where glibtoolize was failing to find
# sed, and reinstalling fixes it.
brew reinstall -s libtool
brew_if_not_installed pkg-config
brew_if_not_installed protobuf
brew_if_not_installed gmp
if [ "${CHECK_CODE_FORMAT}" = true ]; then
brew_if_not_installed clang-format
fi
}
function install_apt_packages() {
if [ -z "${TRAVIS+x}" ]; then
# if not on travis, its nice to see progress
QUIET=""
else
QUIET="-qq"
fi
# get the required OS packages
$SUDO apt-get ${QUIET} update
$SUDO apt-get ${QUIET} install -y --no-install-recommends \
build-essential python-dev libbz2-dev libtool \
autotools-dev autoconf git pkg-config wget \
ca-certificates automake bsdmainutils
if [ "${CHECK_CODE_FORMAT}" = true ]; then
$SUDO apt-get ${QUIET} install -y --no-install-recommends \
clang-format-3.4
fi
}
function build_dependencies() {
if [ "${OS_NAME}" = "osx" ]; then
PARALLEL="-j $(sysctl -n hw.ncpu)"
install_brew_packages
else
PARALLEL="-j $(grep -c processor /proc/cpuinfo)"
install_apt_packages
fi
if [ "$CLEAN" = true ]; then
rm -rf "${LBRYCRD_DEPENDENCIES}"
rm -rf "${OUTPUT_DIR}"
fi
if [ ! -d "${LBRYCRD_DEPENDENCIES}" ]; then
git clone https://github.com/lbrynaut/lbrycrd-dependencies.git "${LBRYCRD_DEPENDENCIES}"
fi
# TODO: if the repo exists, make sure its clean: revert to head.
mkdir -p "${LOG_DIR}"
build_dependency "${OPENSSL_PREFIX}" "${LOG_DIR}/openssl_build.log" build_openssl
build_dependency "${ICU_PREFIX}" "${LOG_DIR}/icu_build.log" build_icu
build_dependency "${BDB_PREFIX}" "${LOG_DIR}/bdb_build.log" build_bdb
set +u
export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:${OPENSSL_PREFIX}/lib/pkgconfig/"
set -u
build_dependency "${BOOST_PREFIX}" "${LOG_DIR}/boost_build.log" build_boost
build_dependency "${LIBEVENT_PREFIX}" "${LOG_DIR}/libevent_build.log" build_libevent
}
function build_bdb() {
BDB_LOG="$1"
if [ "${OS_NAME}" = "osx" ]; then
patch db-4.8.30.NC/dbinc/atomic.h < atomic.patch
fi
cd db-4.8.30.NC/build_unix
echo "Building bdb. tail -f $BDB_LOG to see the details and monitor progress"
../dist/configure --prefix="${BDB_PREFIX}" --enable-cxx --disable-shared --with-pic > "${BDB_LOG}"
background "make ${PARALLEL}" "${BDB_LOG}" "Waiting for bdb to finish building"
make install >> "${BDB_LOG}" 2>&1
}
function build_openssl() {
OPENSSL_LOG="$1"
mkdir -p "${OPENSSL_PREFIX}/ssl"
cd openssl-1.0.1p
echo "Building openssl. tail -f $OPENSSL_LOG to see the details and monitor progress"
if [ "${OS_NAME}" = "osx" ]; then
./Configure --prefix="${OPENSSL_PREFIX}" --openssldir="${OPENSSL_PREFIX}/ssl" \
-fPIC darwin64-x86_64-cc \
no-shared no-dso no-engines > "${OPENSSL_LOG}"
else
[[ $(uname -m) = 'i686' ]] && OS_ARCH="linux-generic32" || OS_ARCH="linux-x86_64"
./Configure --prefix="${OPENSSL_PREFIX}" --openssldir="${OPENSSL_PREFIX}/ssl" \
${OS_ARCH} -fPIC -static no-shared no-dso > "${OPENSSL_LOG}"
fi
background "make ${PARALLEL}" "${OPENSSL_LOG}" "Waiting for openssl to finish building"
make install >> "${OPENSSL_LOG}" 2>&1
}
function build_boost() {
BOOST_LOG="$1"
cd boost_1_67_0
echo "int main() { return 0; }" > libs/regex/build/has_icu_test.cpp
echo "int main() { return 0; }" > libs/locale/build/has_icu_test.cpp
export BOOST_ICU_LIBS="$(pkg-config icu-i18n --libs) -dl"
export BOOST_LDFLAGS="${BOOST_PREFIX}/lib ${ICU_PREFIX}/lib ${BOOST_ICU_LIBS}"
echo "BOOST_ICU_LIBS: $BOOST_ICU_LIBS"
echo "BOOST_LDFLAGS: $BOOST_ICU_LIBS"
echo "Building Boost. tail -f ${BOOST_LOG} to see the details and monitor progress"
./bootstrap.sh --prefix="${BOOST_PREFIX}" "--with-icu=${ICU_PREFIX}" > "${BOOST_LOG}" 2>&1
b2cmd="./b2 link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH=${ICU_PREFIX} -sICU_LINK=${BOOST_ICU_LIBS}"
background "${b2cmd}" "${BOOST_LOG}" "Waiting for boost to finish building"
}
function build_icu() {
ICU_LOG="$1"
mkdir -p "${ICU_PREFIX}/icu"
wget http://download.icu-project.org/files/icu4c/55.1/icu4c-55_1-src.tgz
tar -xf icu4c-55_1-src.tgz
rm -f icu4c-55_1-src.tgz
pushd icu/source > /dev/null
echo "Building icu. tail -f $ICU_LOG to see the details and monitor progress"
./configure --prefix="${ICU_PREFIX}" --enable-draft --enable-tools \
--enable-static --enable-shared --disable-extras --disable-icuio \
--disable-layout --disable-layoutex --disable-tests --disable-samples
if [ ! -z ${TARGET+x} ]; then
TMP_TARGET="${TARGET}"
unset TARGET
fi
set +e
background "make ${PARALLEL} VERBOSE=1" "${ICU_LOG}" "Waiting for icu to finish building"
make install >> "${ICU_LOG}" 2>&1
if [ ! -z ${TARGET+x} ]; then
TARGET="${TMP_TARGET}"
fi
set -e
popd > /dev/null
}
function build_libevent() {
LIBEVENT_LOG="$1"
if [ ! -d libevent ]; then
git clone --branch release-2.0.22-stable https://github.com/libevent/libevent.git
fi
cd libevent
echo "Building libevent. tail -f ${LIBEVENT_LOG} to see the details and monitor progress"
./autogen.sh > "${LIBEVENT_LOG}" 2>&1
./configure --prefix="${LIBEVENT_PREFIX}" --enable-static --disable-shared --with-pic \
LDFLAGS="-L${OPENSSL_PREFIX}/lib/" \
CPPFLAGS="-I${OPENSSL_PREFIX}/include" >> "${LIBEVENT_LOG}" 2>&1
background "make ${PARALLEL}" "${LIBEVENT_LOG}" "Waiting for libevent to finish building"
make install >> "${LIBEVENT_LOG}"
}
function build_dependency() {
PREFIX=$1
LOG=$2
BUILD=$3
if [ ! -d "${PREFIX}" ]; then
trap 'cleanup "${PREFIX}" "${LOG}"' INT TERM EXIT
cd "${LBRYCRD_DEPENDENCIES}"
rm -rf ${PREFIX}
mkdir -p "${PREFIX}"
"${BUILD}" "${LOG}"
trap - INT TERM EXIT
fi
}
function build_lbrycrd() {
if [ "$CLONE" == true ]; then
cd "${LBRYCRD_DEPENDENCIES}"
git clone https://github.com/lbryio/lbrycrd
cd lbrycrd
else
cd "${SOURCE_DIR}"
fi
./autogen.sh > "${LBRYCRD_LOG}" 2>&1
LDFLAGS="-L${OPENSSL_PREFIX}/lib/ -L${BDB_PREFIX}/lib/ -L${LIBEVENT_PREFIX}/lib/ -L${ICU_PREFIX}/lib/ -static-libstdc++"
if [ "${OS_NAME}" = "osx" ]; then
OPTIONS="--enable-cxx --enable-static --disable-shared --with-pic"
CPPFLAGS="-I${OPENSSL_PREFIX}/include -I${BDB_PREFIX}/include -I${LIBEVENT_PREFIX}/include/ -I${ICU_PREFIX}/include"
else
OPTIONS=""
CPPFLAGS="-I${OPENSSL_PREFIX}/include -I${BDB_PREFIX}/include -I${LIBEVENT_PREFIX}/include/ -I${ICU_PREFIX}/include -Wno-unused-local-typedefs"
fi
CPPFLAGS="${CPPFLAGS}" LDFLAGS="${LDFLAGS}" \
./configure --without-gui ${OPTIONS} \
--with-boost="${BOOST_PREFIX}" \
--with-icu="${ICU_PREFIX}" >> "${LBRYCRD_LOG}" 2>&1
background "make ${PARALLEL}" "${LBRYCRD_LOG}" "Waiting for lbrycrd to finish building"
if [ "${OS_NAME}" = "linux" ]; then
LD_LIBRARY_PATH="${ICU_PREFIX}/lib" src/test/test_lbrycrd
else
DYLD_LIBRARY_PATH="${ICU_PREFIX}/lib" src/test/test_lbrycrd
fi
strip src/lbrycrdd
strip src/lbrycrd-cli
strip src/lbrycrd-tx
strip src/test/test_lbrycrd
}
function clang_format_diff(){
# run a code formatting check on any commits not in master
# requires clang-format
if ! git config remote.origin2.url > /dev/null; then
git remote add origin2 https://github.com/lbryio/lbrycrd.git
fi
git fetch origin2
git diff -U0 origin2/master -- '*.h' '*.cpp' | ./contrib/devtools/clang-format-diff.py -p1
}
# these variables are needed in both functions
LBRYCRD_DEPENDENCIES="$(pwd)/lbrycrd-dependencies"
OUTPUT_DIR="$(pwd)/build"
LOG_DIR="$(pwd)/logs"
ICU_PREFIX="${OUTPUT_DIR}/icu"
BDB_PREFIX="${OUTPUT_DIR}/bdb"
OPENSSL_PREFIX="${OUTPUT_DIR}/openssl"
BOOST_PREFIX="${OUTPUT_DIR}/boost"
LIBEVENT_PREFIX="${OUTPUT_DIR}/libevent"
if [ "${BUILD_DEPENDENCIES}" = true ]; then
build_dependencies
fi
if [ "${CHECK_CODE_FORMAT}" = true ]; then
LINES_W_FORMAT_REQUIRED=$(clang_format_diff | wc -l)
if [ ${LINES_W_FORMAT_REQUIRED} -ne 0 ]; then
echo "Failed to pass clang format diff: See below for the diff"
clang_format_diff
exit 1
fi
fi
set +u
export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:${OPENSSL_PREFIX}/lib/pkgconfig/:${LIBEVENT_PREFIX}/lib/pkgconfig/"
set -u
if [ "${BUILD_LBRYCRD}" = true ]; then
LBRYCRD_LOG="${LOG_DIR}/lbrycrd_build.log"
echo "Building lbrycrd. tail -f ${LBRYCRD_LOG} to see the details and monitor progress"
trap 'cat_and_exit "${LBRYCRD_LOG}"' INT TERM EXIT
build_lbrycrd
trap - INT TERM EXIT
fi

View file

@ -19,7 +19,7 @@ else
LIBUNIVALUE = $(UNIVALUE_LIBS)
endif
BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(ICU_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) $(ICU_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS)
@ -102,6 +102,7 @@ BITCOIN_CORE_H = \
chainparamsseeds.h \
checkpoints.h \
checkqueue.h \
claimtrie.h \
clientversion.h \
coins.h \
compat.h \
@ -127,12 +128,14 @@ BITCOIN_CORE_H = \
key.h \
key_io.h \
keystore.h \
lbry.h \
dbwrapper.h \
limitedmap.h \
logging.h \
memusage.h \
merkleblock.h \
miner.h \
nameclaim.h \
net.h \
net_processing.h \
netaddress.h \
@ -178,10 +181,12 @@ BITCOIN_CORE_H = \
txdb.h \
txmempool.h \
ui_interface.h \
uint256.h \
undo.h \
util.h \
utilmemory.h \
utilmoneystr.h \
utilstrencodings.h \
utiltime.h \
validation.h \
validationinterface.h \
@ -221,6 +226,7 @@ libbitcoin_server_a_SOURCES = \
blockencodings.cpp \
chain.cpp \
checkpoints.cpp \
claimtrie.cpp \
consensus/tx_verify.cpp \
httprpc.cpp \
httpserver.cpp \
@ -228,8 +234,10 @@ libbitcoin_server_a_SOURCES = \
index/txindex.cpp \
init.cpp \
dbwrapper.cpp \
lbry.cpp \
merkleblock.cpp \
miner.cpp \
nameclaim.cpp \
net.cpp \
net_processing.cpp \
noui.cpp \
@ -240,6 +248,7 @@ libbitcoin_server_a_SOURCES = \
pow.cpp \
rest.cpp \
rpc/blockchain.cpp \
rpc/claimtrie.cpp \
rpc/mining.cpp \
rpc/misc.cpp \
rpc/net.cpp \
@ -253,6 +262,8 @@ libbitcoin_server_a_SOURCES = \
txdb.cpp \
txmempool.cpp \
ui_interface.cpp \
uint256.cpp \
utilstrencodings.cpp \
validation.cpp \
validationinterface.cpp \
versionbits.cpp \
@ -416,6 +427,7 @@ libbitcoin_util_a_SOURCES = \
support/cleanse.cpp \
sync.cpp \
threadinterrupt.cpp \
uint256.cpp \
util.cpp \
utilmoneystr.cpp \
utilstrencodings.cpp \
@ -441,7 +453,7 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
bitcoind_SOURCES = bitcoind.cpp
bitcoind_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
bitcoind_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
bitcoind_LDFLAGS = -L$(ICU_PREFIX)/lib $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
bitcoind_SOURCES += bitcoind-res.rc
@ -461,7 +473,7 @@ bitcoind_LDADD = \
$(LIBMEMENV) \
$(LIBSECP256K1)
bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
bitcoind_LDADD += $(BOOST_LIBS) $(ICU_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
# bitcoin-cli binary #
bitcoin_cli_SOURCES = bitcoin-cli.cpp

View file

@ -55,8 +55,8 @@ if ENABLE_WALLET
bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
endif
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(ICU_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
bench_bench_bitcoin_LDFLAGS = -L$(ICU_PREFIX)/lib $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)

View file

@ -409,9 +409,9 @@ if ENABLE_ZMQ
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(ICU_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_bitcoin_qt_LDFLAGS = -L$(ICU_PREFIX)/lib $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_bitcoin_qt_LIBTOOLFLAGS = $(AM_LIBTOOLFLAGS) --tag CXX
#locale/foo.ts -> locale/foo.qm

View file

@ -64,9 +64,9 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(ICU_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_test_test_bitcoin_qt_LDFLAGS = -L$(ICU_PREFIX)/lib $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno

View file

@ -61,6 +61,9 @@ BITCOIN_TESTS =\
test/miner_tests.cpp \
test/multisig_tests.cpp \
test/net_tests.cpp \
test/claimtriecache_tests.cpp \
test/claimtriebranching_tests.cpp \
test/nameclaim_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
test/policyestimator_tests.cpp \
@ -117,8 +120,8 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(ICU_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
test_test_bitcoin_LDFLAGS = -L$(ICU_PREFIX)/lib $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
if ENABLE_ZMQ
test_test_bitcoin_LDADD += $(ZMQ_LIBS)
@ -143,7 +146,7 @@ test_test_bitcoin_fuzzy_LDADD = \
$(LIBBITCOIN_CRYPTO_SHANI) \
$(LIBSECP256K1)
test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) $(ICU_LIBS)
#
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)

View file

@ -23,7 +23,7 @@ static const CAmount CENT = 1000000;
* 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 = 21000000 * COIN;
static const CAmount MAX_MONEY = 21000000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
#endif // BITCOIN_AMOUNT_H

View file

@ -209,6 +209,7 @@ public:
//! block header
int32_t nVersion;
uint256 hashMerkleRoot;
uint256 hashClaimTrie;
uint32_t nTime;
uint32_t nBits;
uint32_t nNonce;
@ -237,6 +238,7 @@ public:
nVersion = 0;
hashMerkleRoot = uint256();
hashClaimTrie = uint256();
nTime = 0;
nBits = 0;
nNonce = 0;
@ -253,6 +255,7 @@ public:
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
hashClaimTrie = block.hashClaimTrie;
nTime = block.nTime;
nBits = block.nBits;
nNonce = block.nNonce;
@ -283,6 +286,7 @@ public:
if (pprev)
block.hashPrevBlock = pprev->GetBlockHash();
block.hashMerkleRoot = hashMerkleRoot;
block.hashClaimTrie = hashClaimTrie;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
@ -294,6 +298,11 @@ public:
return *phashBlock;
}
uint256 GetBlockPoWHash() const
{
return GetBlockHeader().GetPoWHash();
}
int64_t GetBlockTime() const
{
return (int64_t)nTime;
@ -322,9 +331,10 @@ public:
std::string ToString() const
{
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, claimtrie=%s, hashBlock=%s)",
pprev, nHeight,
hashMerkleRoot.ToString(),
hashClaimTrie.ToString(),
GetBlockHash().ToString());
}
@ -402,6 +412,7 @@ public:
READWRITE(this->nVersion);
READWRITE(hashPrev);
READWRITE(hashMerkleRoot);
READWRITE(hashClaimTrie);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
@ -413,19 +424,20 @@ public:
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.hashClaimTrie = hashClaimTrie;
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)",
str += strprintf("\n hashBlock=%s, hashClaimTrie=%s, hashPrev=%s)",
GetBlockHash().ToString(),
hashClaimTrie.ToString(),
hashPrev.ToString());
return str;
}

View file

@ -14,6 +14,38 @@
#include <chainparamsseeds.h>
//#define FIND_GENESIS
#define GENESIS_MERKLE_ROOT "b8211c82c3d15bcd78bba57005b86fed515149a53a425eb592c07af99fe559cc"
#define MAINNET_GENESIS_HASH "9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463"
#define MAINNET_GENESIS_NONCE 1287
#define TESTNET_GENESIS_HASH "9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463"
#define TESTNET_GENESIS_NONCE 1287
#define REGTEST_GENESIS_HASH "6e3fcf1299d4ec5d79c3a4c91d624a4acf9e2e173d95a1a0504f677669687556"
#define REGTEST_GENESIS_NONCE 1
bool CheckProofOfWork2(uint256 hash, unsigned int nBits, const Consensus::Params& params)
{
bool fNegative;
bool fOverflow;
arith_uint256 bnTarget;
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
// Check range
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
return error("CheckProofOfWork(): nBits below minimum work");
// Check proof of work matches claimed amount
if (UintToArith256(hash) > bnTarget)
return error("CheckProofOfWork(): hash doesn't match nBits");
return true;
}
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;
@ -22,6 +54,9 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
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() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
//txNew.vout[0].scriptPubKey = CScript() << ParseHex("0425caecb9fbf6cf50979644e85c11e3ec9007fd477fab9683648c6539e59b59c3a4d9b9c0b552c37eee6476f3e0d8425ac0346fe69ad61628b8c340d42fbfa3fd") << OP_CHECKSIG;
//txNew.vout[0].scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ParseHex("e5ff2d9e3a254622ae493573169c0fa94c82fe4f") << OP_EQUALVERIFY << OP_CHECKSIG;
txNew.vout[0].scriptPubKey = genesisOutputScript;
CBlock genesis;
@ -32,6 +67,21 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
genesis.hashClaimTrie = uint256S("0x0000000000000000000000000000000000000000000000000000000000000001");
#ifdef FIND_GENESIS
while (true)
{
genesis.nNonce += 1;
if (CheckProofOfWork2(genesis.GetPoWHash(), nBits, consensus))
{
std::cout << "nonce: " << genesis.nNonce << std::endl;
std::cout << "hex: " << genesis.GetHash().GetHex() << std::endl;
std::cout << "pow hash: " << genesis.GetPoWHash().GetHex() << std::endl;
break;
}
}
#endif
return genesis;
}
@ -48,8 +98,8 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
*/
static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
const char* pszTimestamp = "insert timestamp string";//"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
const CScript genesisOutputScript = CScript() << OP_DUP << OP_HASH160 << ParseHex("345991dbf57bfb014b87006acdfafbfc5fe8292f") << OP_EQUALVERIFY << OP_CHECKSIG;
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
}
@ -73,16 +123,23 @@ void CChainParams::UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64
class CMainParams : public CChainParams {
public:
CMainParams() {
strNetworkID = "main";
consensus.nSubsidyHalvingInterval = 210000;
strNetworkID = "lbrycrd";
consensus.nSubsidyLevelInterval = 1<<5;
consensus.nMajorityEnforceBlockUpgrade = 750;
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 1000;
consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
consensus.BIP34Height = 227931;
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.BIP34Height = 1;
consensus.BIP34Hash = uint256S("0xdecb9e2cca03a419fd9cca0cb2b1d5ad11b088f22f8f38556d93ac4358b86c24");
consensus.BIP65Height = 1;
consensus.BIP66Height = 1;
consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 150; //retarget every block
consensus.nPowTargetSpacing = 150;
consensus.nOriginalClaimExpirationTime = 262974;
consensus.nExtendedClaimExpirationTime = 2102400;
consensus.nExtendedClaimExpirationForkHeight = 400155;
consensus.nNormalizedNameForkHeight = 1000000; // FIXME: pick a real fork height
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016
@ -98,82 +155,77 @@ public:
// Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1479168000; // November 15th, 2016.
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017.
// FIXME: Update times
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1634352575; //1479168000; // November 15th, 2016.
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1634352575; //1510704000; // November 15th, 2017.
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000028822fef1c230963535a90d");
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000607ca7e806c4c1e9"); //400000
// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8"); //534292
//consensus.defaultAssumeValid = uint256S("0xf0e56e70782af63ccb49c76e852540688755869ba59ec68cac9c04a6b4d9f5ca"); //400000
consensus.defaultAssumeValid = uint256S("0xa6bbb48f5343eb9b0287c22f3ea8b29f36cf10794a37f8a925a894d6f4519913"); //4000
/**
* 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] = 0xf9;
pchMessageStart[1] = 0xbe;
pchMessageStart[2] = 0xb4;
pchMessageStart[3] = 0xd9;
nDefaultPort = 8333;
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xe4;
pchMessageStart[2] = 0xaa;
pchMessageStart[3] = 0xf1;
nDefaultPort = 9246;
nPruneAfterHeight = 100000;
genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
genesis = CreateGenesisBlock(1446058291, MAINNET_GENESIS_NONCE, 0x1f00ffff, 1, 400000000 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
#ifdef FIND_GENESIS
std::cout << "hex: " << consensus.hashGenesisBlock.GetHex() << std::endl;
std::cout << "merkle root: " << genesis.hashMerkleRoot.GetHex() << std::endl;
#else
assert(consensus.hashGenesisBlock == uint256S(MAINNET_GENESIS_HASH));
assert(genesis.hashMerkleRoot == uint256S(GENESIS_MERKLE_ROOT));
#endif
vSeeds.clear();
vFixedSeeds.clear();
// Note that of those which support the service bits prefix, most only support a subset of
// possible options.
// This is fine at runtime as we'll fall back to using them as a oneshot if they don't support the
// service bits we want, but we should get them updated to support all service bits wanted by any
// release ASAP to avoid it where possible.
vSeeds.emplace_back("seed.bitcoin.sipa.be"); // Pieter Wuille, only supports x1, x5, x9, and xd
vSeeds.emplace_back("dnsseed.bluematt.me"); // Matt Corallo, only supports x9
vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org"); // Luke Dashjr
vSeeds.emplace_back("seed.bitcoinstats.com"); // Christian Decker, supports x1 - xf
vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch"); // Jonas Schnelli, only supports x1, x5, x9, and xd
vSeeds.emplace_back("seed.btc.petertodd.org"); // Peter Todd, only supports x1, x5, x9, and xd
vSeeds.emplace_back("seed.bitcoin.sprovoost.nl"); // Sjors Provoost
vSeeds.emplace_back("dnsseed1.lbry.io"); // lbry.io
vSeeds.emplace_back("dnsseed2.lbry.io"); // lbry.io
vSeeds.emplace_back("dnsseed3.lbry.io"); // lbry.io
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
bech32_hrp = "bc";
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0x55);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,0x7a);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,0x1c);
base58Prefixes[EXT_PUBLIC_KEY] = {0x01, 0x9c, 0x35, 0x4F};
base58Prefixes[EXT_SECRET_KEY] = {0x01, 0x9c, 0x31, 0x18};
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
/* bech32_hrp = "bc"; */
bech32_hrp = "lb"; // FIXME: change this?
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
// FIXME: update checkpoints?
checkpointData = {
{
{ 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
{ 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
{ 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")},
{105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")},
{134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")},
{168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")},
{193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")},
{210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")},
{216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")},
{225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")},
{250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")},
{279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")},
{295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")},
{ 4000, uint256S("0xa6bbb48f5343eb9b0287c22f3ea8b29f36cf10794a37f8a925a894d6f4519913") },
}
};
// FIXME:
chainTxData = ChainTxData{
// Data from rpc: getchaintxstats 4096 0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8
/* nTime */ 1532884444,
/* nTxCount */ 331282217,
/* dTxRate */ 2.4
1467272478, 4146, 600.0
/* // Data from rpc: getchaintxstats 4096 0000000000000000002e63058c023a9a1de233554f28c7b21380b6c9003f36a8 */
/* /\* nTime *\/ 1532884444, */
/* /\* nTxCount *\/ 331282217, */
/* /\* dTxRate *\/ 2.4 */
};
/* disable fallback fee on mainnet */
@ -187,18 +239,26 @@ public:
class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
strNetworkID = "test";
consensus.nSubsidyHalvingInterval = 210000;
strNetworkID = "lbrycrdtest";
consensus.nSubsidyLevelInterval = 1 << 5;
consensus.nMajorityEnforceBlockUpgrade = 51;
consensus.nMajorityRejectBlockOutdated = 75;
consensus.nMajorityWindow = 100;
consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
// FIXME: adjust heights
consensus.BIP34Height = 21111;
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.powLimit = uint256S("0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 150;
consensus.nPowTargetSpacing = 150;
consensus.nOriginalClaimExpirationTime = 262974;
consensus.nExtendedClaimExpirationTime = 2102400;
consensus.nExtendedClaimExpirationForkHeight = 278160;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = false;
consensus.nNormalizedNameForkHeight = 1000000; // FIXME: pick a real fork height
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
@ -216,30 +276,32 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000007dbe94253893cbd463");
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000a0c3931735170");
// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x0000000000000037a8cd3e06cd5edbfe9dd1dbcc5dacab279376ef7cfc2b4c75"); //1354312
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
pchMessageStart[3] = 0x07;
nDefaultPort = 18333;
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xe4;
pchMessageStart[2] = 0xaa;
pchMessageStart[3] = 0xe1;
nDefaultPort = 19246;
nPruneAfterHeight = 1000;
genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
genesis = CreateGenesisBlock(1446058291, TESTNET_GENESIS_NONCE, 0x1f00ffff, 1, 400000000 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
#ifdef FIND_GENESIS
std::cout << "testnet genesis hash: " << genesis.GetHash().GetHex() << std::endl;
std::cout << "testnet merkle hash: " << genesis.hashMerkleRoot.GetHex() << std::endl;
#else
assert(consensus.hashGenesisBlock == uint256S(TESTNET_GENESIS_HASH));
assert(genesis.hashMerkleRoot == uint256S(GENESIS_MERKLE_ROOT));
#endif
vFixedSeeds.clear();
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch");
vSeeds.emplace_back("seed.tbtc.petertodd.org");
vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl");
vSeeds.emplace_back("testnet-seed.bluematt.me"); // Just a static list of stable node(s), only supports x9
vSeeds.emplace_back("testdnsseed1.lbry.io");
vSeeds.emplace_back("testdnsseed2.lbry.io");
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
@ -247,21 +309,24 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
bech32_hrp = "tb";
/* bech32_hrp = "tb"; */
bech32_hrp = "lt"; // FIXME: change?
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fMineBlocksOnDemand = false;
fTestnetToBeDeprecatedFieldRPC = true;
checkpointData = {
{
{546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")},
{0, uint256S(TESTNET_GENESIS_HASH)},
}
};
// FIXME:
chainTxData = ChainTxData{
// Data from rpc: getchaintxstats 4096 0000000000000037a8cd3e06cd5edbfe9dd1dbcc5dacab279376ef7cfc2b4c75
/* nTime */ 1531929919,
@ -280,18 +345,23 @@ public:
class CRegTestParams : public CChainParams {
public:
CRegTestParams() {
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
strNetworkID = "lbrycrdreg";
consensus.nSubsidyLevelInterval = 1 << 5;
consensus.BIP16Exception = uint256();
consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
// FIXME: heights
consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests)
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = true;
consensus.nPowTargetTimespan = 1;//14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 1;
consensus.nOriginalClaimExpirationTime = 500;
consensus.nExtendedClaimExpirationTime = 600;
consensus.nExtendedClaimExpirationForkHeight = 800;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false;
consensus.nNormalizedNameForkHeight = 2000; // FIXME: pick a real fork height
consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
@ -311,27 +381,34 @@ public:
consensus.defaultAssumeValid = uint256S("0x00");
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda;
nDefaultPort = 18444;
pchMessageStart[1] = 0xe4;
pchMessageStart[2] = 0xaa;
pchMessageStart[3] = 0xd1;
nDefaultPort = 29246;
nPruneAfterHeight = 1000;
genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
genesis = CreateGenesisBlock(1446058291, REGTEST_GENESIS_NONCE, 0x207fffff, 1, 400000000 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
#ifdef FIND_GENESIS
std::cout << "regtest genensis hash: " << genesis.GetHash().GetHex() << std::endl;
std::cout << "regtest hashmerkleroot: " << genesis.hashMerkleRoot.GetHex() << std::endl;
#else
assert(consensus.hashGenesisBlock == uint256S(REGTEST_GENESIS_HASH));
assert(genesis.hashMerkleRoot == uint256S(GENESIS_MERKLE_ROOT));
#endif
vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds.
fMiningRequiresPeers = false;
fDefaultConsistencyChecks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
fTestnetToBeDeprecatedFieldRPC = false;
checkpointData = {
{
{0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")},
{0, uint256S(REGTEST_GENESIS_HASH)},
}
};

View file

@ -6,6 +6,7 @@
#ifndef BITCOIN_CHAINPARAMS_H
#define BITCOIN_CHAINPARAMS_H
#include <arith_uint256.h>
#include <chainparamsbase.h>
#include <consensus/params.h>
#include <primitives/block.h>
@ -94,9 +95,11 @@ protected:
std::string strNetworkID;
CBlock genesis;
std::vector<SeedSpec6> vFixedSeeds;
bool fMiningRequiresPeers;
bool fDefaultConsistencyChecks;
bool fRequireStandard;
bool fMineBlocksOnDemand;
bool fTestnetToBeDeprecatedFieldRPC;
CCheckpointData checkpointData;
ChainTxData chainTxData;
bool m_fallback_fee_enabled;

View file

@ -33,11 +33,11 @@ const CBaseChainParams& BaseParams()
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
{
if (chain == CBaseChainParams::MAIN)
return MakeUnique<CBaseChainParams>("", 8332);
return MakeUnique<CBaseChainParams>("", 9246);
else if (chain == CBaseChainParams::TESTNET)
return MakeUnique<CBaseChainParams>("testnet3", 18332);
return MakeUnique<CBaseChainParams>("testnet3", 19246);
else if (chain == CBaseChainParams::REGTEST)
return MakeUnique<CBaseChainParams>("regtest", 18443);
return MakeUnique<CBaseChainParams>("regtest", 29246);
else
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}

View file

@ -44,6 +44,12 @@ std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain
*/
void SetupChainParamsBaseOptions();
/**
* Append the help messages for the chainparams options to the
* parameter string.
*/
void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp=true);
/**
* Return the currently selected parameters. This won't change after app
* startup, except for unit tests.
@ -53,4 +59,16 @@ const CBaseChainParams& BaseParams();
/** Sets the params returned by Params() to those for the given network. */
void SelectBaseParams(const std::string& chain);
/**
* Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
* @return CBaseChainParams::MAX_NETWORK_TYPES if an invalid combination is given. CBaseChainParams::MAIN by default.
*/
std::string ChainNameFromCommandLine();
/**
* Return true if SelectBaseParamsFromCommandLine() has been called to select
* a network.
*/
bool AreBaseParamsConfigured();
#endif // BITCOIN_CHAINPARAMSBASE_H

File diff suppressed because it is too large Load diff

2804
src/claimtrie.cpp Normal file

File diff suppressed because it is too large Load diff

655
src/claimtrie.h Normal file
View file

@ -0,0 +1,655 @@
#ifndef BITCOIN_CLAIMTRIE_H
#define BITCOIN_CLAIMTRIE_H
#include "amount.h"
#include "serialize.h"
#include "uint256.h"
#include "util.h"
#include "dbwrapper.h"
#include "chainparams.h"
#include "primitives/transaction.h"
#include <string>
#include <vector>
#include <map>
// leveldb keys
#define HASH_BLOCK 'h'
#define CURRENT_HEIGHT 't'
#define TRIE_NODE 'n'
#define CLAIM_BY_ID 'i'
#define CLAIM_QUEUE_ROW 'r'
#define CLAIM_QUEUE_NAME_ROW 'm'
#define EXP_QUEUE_ROW 'e'
#define SUPPORT 's'
#define SUPPORT_QUEUE_ROW 'u'
#define SUPPORT_QUEUE_NAME_ROW 'p'
#define SUPPORT_EXP_QUEUE_ROW 'x'
uint256 getValueHash(COutPoint outPoint, int nHeightOfLastTakeover);
// Provides pre-C++11 copy semantics of std::swap, rather than move
// semantics (available in C++11).
namespace claimtrie
{
template<typename T>
static inline void swap(T& x, T& y) {
const auto tmp = x;
y = x;
x = tmp;
}
} // namespace claimtrie
class CClaimValue
{
public:
COutPoint outPoint;
uint160 claimId;
CAmount nAmount;
CAmount nEffectiveAmount;
int nHeight;
int nValidAtHeight;
CClaimValue() {};
CClaimValue(COutPoint outPoint, uint160 claimId, CAmount nAmount, int nHeight,
int nValidAtHeight)
: outPoint(outPoint), claimId(claimId)
, nAmount(nAmount), nEffectiveAmount(nAmount)
, nHeight(nHeight), nValidAtHeight(nValidAtHeight)
{}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(outPoint);
READWRITE(claimId);
READWRITE(nAmount);
READWRITE(nHeight);
READWRITE(nValidAtHeight);
}
bool operator<(const CClaimValue& other) const
{
if (nEffectiveAmount < other.nEffectiveAmount)
return true;
else if (nEffectiveAmount == other.nEffectiveAmount)
{
if (nHeight > other.nHeight)
return true;
else if (nHeight == other.nHeight)
{
if (outPoint != other.outPoint && !(outPoint < other.outPoint))
return true;
}
}
return false;
}
bool operator==(const CClaimValue& other) const
{
return outPoint == other.outPoint && claimId == other.claimId && nAmount == other.nAmount && nHeight == other.nHeight && nValidAtHeight == other.nValidAtHeight;
}
bool operator!=(const CClaimValue& other) const
{
return !(*this == other);
}
};
class CSupportValue
{
public:
COutPoint outPoint;
uint160 supportedClaimId;
CAmount nAmount;
int nHeight;
int nValidAtHeight;
CSupportValue() {};
CSupportValue(COutPoint outPoint, uint160 supportedClaimId,
CAmount nAmount, int nHeight, int nValidAtHeight)
: outPoint(outPoint), supportedClaimId(supportedClaimId)
, nAmount(nAmount), nHeight(nHeight)
, nValidAtHeight(nValidAtHeight)
{}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(outPoint);
READWRITE(supportedClaimId);
READWRITE(nAmount);
READWRITE(nHeight);
READWRITE(nValidAtHeight);
}
bool operator==(const CSupportValue& other) const
{
return outPoint == other.outPoint && supportedClaimId == other.supportedClaimId && nAmount == other.nAmount && nHeight == other.nHeight && nValidAtHeight == other.nValidAtHeight;
}
bool operator!=(const CSupportValue& other) const
{
return !(*this == other);
}
};
class CClaimTrieNode;
class CClaimTrie;
typedef std::vector<CSupportValue> supportMapEntryType;
typedef std::map<unsigned char, CClaimTrieNode*> nodeMapType;
typedef std::pair<std::string, CClaimTrieNode> namedNodeType;
class CClaimTrieNode
{
public:
CClaimTrieNode() : nHeightOfLastTakeover(0) {}
CClaimTrieNode(uint256 hash) : hash(hash), nHeightOfLastTakeover(0) {}
uint256 hash;
nodeMapType children;
int nHeightOfLastTakeover;
std::vector<CClaimValue> claims;
bool insertClaim(CClaimValue claim);
bool removeClaim(const COutPoint& outPoint, CClaimValue& claim);
bool getBestClaim(CClaimValue& claim) const;
bool empty() const {return children.empty() && claims.empty();}
bool haveClaim(const COutPoint& outPoint) const;
void reorderClaims(supportMapEntryType& supports);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(hash);
READWRITE(claims);
READWRITE(nHeightOfLastTakeover);
}
bool operator==(const CClaimTrieNode& other) const
{
return hash == other.hash && claims == other.claims;
}
bool operator!=(const CClaimTrieNode& other) const
{
return !(*this == other);
}
};
struct nodenamecompare
{
bool operator() (const std::string& i, const std::string& j) const
{
if (i.size() == j.size())
return i < j;
return i.size() < j.size();
}
};
struct outPointHeightType
{
COutPoint outPoint;
int nHeight;
outPointHeightType() {}
outPointHeightType(COutPoint outPoint, int nHeight)
: outPoint(outPoint), nHeight(nHeight) {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(outPoint);
READWRITE(nHeight);
}
};
struct nameOutPointHeightType
{
std::string name;
COutPoint outPoint;
int nHeight;
nameOutPointHeightType() {}
nameOutPointHeightType(std::string name, COutPoint outPoint, int nHeight)
: name(name), outPoint(outPoint), nHeight(nHeight) {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(name);
READWRITE(outPoint);
READWRITE(nHeight);
}
};
struct nameOutPointType
{
std::string name;
COutPoint outPoint;
nameOutPointType() {}
nameOutPointType(std::string name, COutPoint outPoint)
: name(name), outPoint(outPoint) {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(name);
READWRITE(outPoint);
}
};
class CClaimIndexElement
{
public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(name);
READWRITE(claim);
}
std::string name;
CClaimValue claim;
};
typedef std::pair<std::string, CClaimValue> claimQueueEntryType;
typedef std::pair<std::string, CSupportValue> supportQueueEntryType;
typedef std::map<std::string, supportMapEntryType> supportMapType;
typedef std::vector<outPointHeightType> queueNameRowType;
typedef std::map<std::string, queueNameRowType> queueNameType;
typedef std::vector<nameOutPointHeightType> insertUndoType;
typedef std::vector<nameOutPointType> expirationQueueRowType;
typedef std::map<int, expirationQueueRowType> expirationQueueType;
typedef std::vector<claimQueueEntryType> claimQueueRowType;
typedef std::map<int, claimQueueRowType> claimQueueType;
typedef std::vector<supportQueueEntryType> supportQueueRowType;
typedef std::map<int, supportQueueRowType> supportQueueType;
typedef std::map<std::string, CClaimTrieNode*, nodenamecompare> nodeCacheType;
typedef std::map<std::string, uint256> hashMapType;
typedef std::set<CClaimValue> claimIndexClaimListType;
typedef std::vector<CClaimIndexElement> claimIndexElementListType;
struct claimsForNameType
{
std::vector<CClaimValue> claims;
std::vector<CSupportValue> supports;
int nLastTakeoverHeight;
claimsForNameType(std::vector<CClaimValue> claims, std::vector<CSupportValue> supports, int nLastTakeoverHeight)
: claims(claims), supports(supports), nLastTakeoverHeight(nLastTakeoverHeight) {}
};
class CClaimTrieCache;
class CClaimTrie
{
public:
CClaimTrie(bool fMemory = false, bool fWipe = false, int nProportionalDelayFactor = 32)
: db(GetDataDir() / "claimtrie", 100, fMemory, fWipe, false)
, nCurrentHeight(0), nExpirationTime(Params().GetConsensus().nOriginalClaimExpirationTime)
, nProportionalDelayFactor(nProportionalDelayFactor)
, root(uint256S("0000000000000000000000000000000000000000000000000000000000000001"))
{}
uint256 getMerkleHash();
bool empty() const;
void clear();
bool checkConsistency() const;
bool WriteToDisk();
bool ReadFromDisk(bool check = false);
std::vector<namedNodeType> flattenTrie() const;
bool getInfoForName(const std::string& name, CClaimValue& claim) const;
bool getLastTakeoverForName(const std::string& name, int& lastTakeoverHeight) const;
claimsForNameType getClaimsForName(const std::string& name) const;
CAmount getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports = nullptr) const;
CAmount getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports = nullptr) const;
bool queueEmpty() const;
bool supportEmpty() const;
bool supportQueueEmpty() const;
bool expirationQueueEmpty() const;
bool supportExpirationQueueEmpty() const;
void setExpirationTime(int t);
void addToClaimIndex(const std::string& name, const CClaimValue& claim);
void removeFromClaimIndex(const CClaimValue& claim);
bool getClaimById(const uint160 claimId, std::string& name, CClaimValue& claim) const;
bool getQueueRow(int nHeight, claimQueueRowType& row) const;
bool getQueueNameRow(const std::string& name, queueNameRowType& row) const;
bool getExpirationQueueRow(int nHeight, expirationQueueRowType& row) const;
bool getSupportNode(std::string name, supportMapEntryType& node) const;
bool getSupportQueueRow(int nHeight, supportQueueRowType& row) const;
bool getSupportQueueNameRow(const std::string& name, queueNameRowType& row) const;
bool getSupportExpirationQueueRow(int nHeight, expirationQueueRowType& row) const;
bool haveClaim(const std::string& name, const COutPoint& outPoint) const;
bool haveClaimInQueue(const std::string& name, const COutPoint& outPoint,
int& nValidAtHeight) const;
bool haveSupport(const std::string& name, const COutPoint& outPoint) const;
bool haveSupportInQueue(const std::string& name, const COutPoint& outPoint,
int& nValidAtHeight) const;
unsigned int getTotalNamesInTrie() const;
unsigned int getTotalClaimsInTrie() const;
CAmount getTotalValueOfClaimsInTrie(bool fControllingOnly) const;
friend class CClaimTrieCache;
CDBWrapper db;
int nCurrentHeight;
int nExpirationTime;
int nProportionalDelayFactor;
private:
void clear(CClaimTrieNode* current);
const CClaimTrieNode* getNodeForName(const std::string& name) const;
bool update(nodeCacheType& cache, hashMapType& hashes,
std::map<std::string, int>& takeoverHeights,
const uint256& hashBlock, claimQueueType& queueCache,
queueNameType& queueNameCache,
expirationQueueType& expirationQueueCache, int nNewHeight,
supportMapType& supportCache,
supportQueueType& supportQueueCache,
queueNameType& supportQueueNameCache,
expirationQueueType& supportExpirationQueueCache);
bool updateName(const std::string& name, CClaimTrieNode* updatedNode);
bool updateHash(const std::string& name, uint256& hash);
bool updateTakeoverHeight(const std::string& name, int nTakeoverHeight);
bool recursiveNullify(CClaimTrieNode* node, std::string& name);
bool recursiveCheckConsistency(const CClaimTrieNode* node) const;
bool InsertFromDisk(const std::string& name, CClaimTrieNode* node);
unsigned int getTotalNamesRecursive(const CClaimTrieNode* current) const;
unsigned int getTotalClaimsRecursive(const CClaimTrieNode* current) const;
CAmount getTotalValueOfClaimsRecursive(const CClaimTrieNode* current,
bool fControllingOnly) const;
bool recursiveFlattenTrie(const std::string& name,
const CClaimTrieNode* current,
std::vector<namedNodeType>& nodes) const;
void markNodeDirty(const std::string& name, CClaimTrieNode* node);
void updateQueueRow(int nHeight, claimQueueRowType& row);
void updateQueueNameRow(const std::string& name,
queueNameRowType& row);
void updateExpirationRow(int nHeight, expirationQueueRowType& row);
void updateSupportMap(const std::string& name, supportMapEntryType& node);
void updateSupportQueue(int nHeight, supportQueueRowType& row);
void updateSupportNameQueue(const std::string& name,
queueNameRowType& row);
void updateSupportExpirationQueue(int nHeight, expirationQueueRowType& row);
void BatchWriteNode(CDBBatch& batch, const std::string& name,
const CClaimTrieNode* pNode) const;
void BatchEraseNode(CDBBatch& batch, const std::string& nome) const;
void BatchWriteClaimIndex(CDBBatch& batch) const;
void BatchWriteQueueRows(CDBBatch& batch);
void BatchWriteQueueNameRows(CDBBatch& batch);
void BatchWriteExpirationQueueRows(CDBBatch& batch);
void BatchWriteSupportNodes(CDBBatch& batch);
void BatchWriteSupportQueueRows(CDBBatch& batch);
void BatchWriteSupportQueueNameRows(CDBBatch& batch);
void BatchWriteSupportExpirationQueueRows(CDBBatch& batch);
template<typename K> bool keyTypeEmpty(char key, K& dummy) const;
CClaimTrieNode root;
uint256 hashBlock;
claimQueueType dirtyQueueRows;
queueNameType dirtyQueueNameRows;
expirationQueueType dirtyExpirationQueueRows;
supportQueueType dirtySupportQueueRows;
queueNameType dirtySupportQueueNameRows;
expirationQueueType dirtySupportExpirationQueueRows;
nodeCacheType dirtyNodes;
supportMapType dirtySupportNodes;
};
class CClaimTrieProofNode
{
public:
CClaimTrieProofNode() {};
CClaimTrieProofNode(std::vector<std::pair<unsigned char, uint256> > children,
bool hasValue, uint256 valHash)
: children(children), hasValue(hasValue), valHash(valHash)
{};
std::vector<std::pair<unsigned char, uint256> > children;
bool hasValue;
uint256 valHash;
};
class CClaimTrieProof
{
public:
CClaimTrieProof() {};
CClaimTrieProof(std::vector<CClaimTrieProofNode> nodes, bool hasValue, COutPoint outPoint, int nHeightOfLastTakeover) : nodes(nodes), hasValue(hasValue), outPoint(outPoint), nHeightOfLastTakeover(nHeightOfLastTakeover) {}
std::vector<CClaimTrieProofNode> nodes;
bool hasValue;
COutPoint outPoint;
int nHeightOfLastTakeover;
};
class CClaimTrieCache
{
public:
CClaimTrieCache(CClaimTrie* base, bool fRequireTakeoverHeights = true)
: base(base),
fRequireTakeoverHeights(fRequireTakeoverHeights)
{
assert(base);
nCurrentHeight = base->nCurrentHeight;
}
uint256 getMerkleHash() const;
bool empty() const;
bool flush();
bool dirty() const { return !dirtyHashes.empty(); }
CClaimTrieNode* getRoot() const
{
const auto iter = cache.find("");
return iter == cache.end() ? &(base->root) : iter->second;
}
bool addClaim(const std::string& name, const COutPoint& outPoint,
uint160 claimId, CAmount nAmount, int nHeight) const;
bool undoAddClaim(const std::string& name, const COutPoint& outPoint) const;
bool spendClaim(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const;
bool undoSpendClaim(const std::string& name, const COutPoint& outPoint,
uint160 claimId, CAmount nAmount, int nHeight,
int nValidAtHeight) const;
bool addSupport(const std::string& name, const COutPoint& outPoint,
CAmount nAmount, uint160 supportedClaimId,
int nHeight) const;
bool undoAddSupport(const std::string& name, const COutPoint& outPoint,
int nHeight) const;
bool spendSupport(const std::string& name, const COutPoint& outPoint,
int nHeight, int& nValidAtHeight) const;
bool undoSpendSupport(const std::string& name, const COutPoint& outPoint,
uint160 supportedClaimId, CAmount nAmount,
int nHeight, int nValidAtHeight) const;
uint256 getBestBlock();
void setBestBlock(const uint256& hashBlock);
bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo,
std::vector<std::pair<std::string, int> >& takeoverHeightUndo) const;
bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo,
std::vector<std::pair<std::string, int> >& takeoverHeightUndo) const;
~CClaimTrieCache() { clear(); }
bool insertClaimIntoTrie(const std::string& name, CClaimValue claim,
bool fCheckTakeover = false) const;
bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint,
CClaimValue& claim,
bool fCheckTakeover = false) const;
bool getProofForName(const std::string& name, CClaimTrieProof& proof) const;
bool getInfoForName(const std::string& name, CClaimValue& claim) const;
bool finalizeDecrement() const;
void removeAndAddSupportToExpirationQueue(expirationQueueRowType &row, int height, bool increment) const;
void removeAndAddToExpirationQueue(expirationQueueRowType &row, int height, bool increment) const;
bool forkForExpirationChange(bool increment) const;
std::vector<namedNodeType> flattenTrie() const;
claimsForNameType getClaimsForName(const std::string& name) const;
CAmount getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports = nullptr) const;
CAmount getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports = nullptr) const;
protected:
CClaimTrie* base;
bool fRequireTakeoverHeights;
mutable nodeCacheType cache;
mutable nodeCacheType block_originals;
mutable std::set<std::string> dirtyHashes;
mutable hashMapType cacheHashes;
mutable claimQueueType claimQueueCache;
mutable queueNameType claimQueueNameCache;
mutable expirationQueueType expirationQueueCache;
mutable supportMapType supportCache;
mutable supportQueueType supportQueueCache;
mutable queueNameType supportQueueNameCache;
mutable expirationQueueType supportExpirationQueueCache;
mutable std::set<std::string> namesToCheckForTakeover;
mutable std::map<std::string, int> cacheTakeoverHeights;
mutable int nCurrentHeight; // Height of the block that is being worked on, which is
// one greater than the height of the chain's tip
mutable claimIndexElementListType claimsToAdd;
mutable claimIndexClaimListType claimsToDelete;
uint256 hashBlock;
uint256 computeHash() const;
bool reorderTrieNode(const std::string& name, bool fCheckTakeover) const;
bool recursiveComputeMerkleHash(CClaimTrieNode* tnCurrent,
std::string sPos) const;
bool recursivePruneName(CClaimTrieNode* tnCurrent, unsigned int nPos,
std::string sName,
bool* pfNullified = NULL) const;
bool clear() const;
bool removeClaim(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight, bool fCheckTakeover) const;
bool addClaimToQueues(const std::string& name, CClaimValue& claim) const;
bool removeClaimFromQueue(const std::string& name, const COutPoint& outPoint,
CClaimValue& claim) const;
void addToExpirationQueue(int nExpirationHeight, nameOutPointType& entry) const;
void removeFromExpirationQueue(const std::string& name, const COutPoint& outPoint,
int nHeight) const;
claimQueueType::iterator getQueueCacheRow(int nHeight,
bool createIfNotExists) const;
queueNameType::iterator getQueueCacheNameRow(const std::string& name,
bool createIfNotExists) const;
expirationQueueType::iterator getExpirationQueueCacheRow(int nHeight,
bool createIfNotExists) const;
bool removeSupport(const std::string& name, const COutPoint& outPoint,
int nHeight, int& nValidAtHeight,
bool fCheckTakeover) const;
bool removeSupportFromMap(const std::string& name, const COutPoint& outPoint,
CSupportValue& support,
bool fCheckTakeover) const;
bool insertSupportIntoMap(const std::string& name,
CSupportValue support,
bool fCheckTakeover) const;
supportQueueType::iterator getSupportQueueCacheRow(int nHeight, bool createIfNotExists) const;
queueNameType::iterator getSupportQueueCacheNameRow(const std::string& name, bool createIfNotExists) const;
expirationQueueType::iterator getSupportExpirationQueueCacheRow(int nHeight, bool createIfNotExists) const;
bool addSupportToQueues(const std::string& name, CSupportValue& support) const;
bool removeSupportFromQueue(const std::string& name, const COutPoint& outPoint,
CSupportValue& support) const;
void addSupportToExpirationQueue(int nExpirationHeight,
nameOutPointType& entry) const;
void removeSupportFromExpirationQueue(const std::string& name,
const COutPoint& outPoint,
int nHeight) const;
bool getSupportsForName(const std::string& name,
supportMapEntryType& node) const;
bool getLastTakeoverForName(const std::string& name, int& lastTakeoverHeight) const;
int getDelayForName(const std::string& name) const;
uint256 getLeafHashForProof(const std::string& currentPosition, unsigned char nodeChar,
const CClaimTrieNode* currentNode) const;
CClaimTrieNode* addNodeToCache(const std::string& position, CClaimTrieNode* original) const;
bool getOriginalInfoForName(const std::string& name, CClaimValue& claim) const;
int getNumBlocksOfContinuousOwnership(const std::string& name) const;
void recursiveFlattenTrie(const std::string& name, const CClaimTrieNode* current, std::vector<namedNodeType>& nodes) const;
const CClaimTrieNode* getNodeForName(const std::string& name) const;
};
#endif // BITCOIN_CLAIMTRIE_H

View file

@ -39,8 +39,8 @@ public:
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) {}
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();

View file

@ -10,9 +10,9 @@
#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;
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 8000000;
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
static const unsigned int MAX_BLOCK_WEIGHT = 8000000;
/** 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) */

View file

@ -48,7 +48,11 @@ struct BIP9Deployment {
*/
struct Params {
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
int nSubsidyLevelInterval;
/** Used to check majorities for block version upgrade */
int nMajorityEnforceBlockUpgrade;
int nMajorityRejectBlockOutdated;
int nMajorityWindow;
/* Block hash that is excepted from BIP16 enforcement */
uint256 BIP16Exception;
/** Block height and hash at which BIP34 becomes active */
@ -70,8 +74,17 @@ struct Params {
uint256 powLimit;
bool fPowAllowMinDifficultyBlocks;
bool fPowNoRetargeting;
int nNormalizedNameForkHeight;
int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan;
int64_t nOriginalClaimExpirationTime;
int64_t nExtendedClaimExpirationTime;
int64_t nExtendedClaimExpirationForkHeight;
int64_t GetExpirationTime(int64_t nHeight) const {
return nHeight < nExtendedClaimExpirationForkHeight ?
nOriginalClaimExpirationTime :
nExtendedClaimExpirationTime;
}
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
uint256 nMinimumChainWork;
uint256 defaultAssumeValid;

View file

@ -9,6 +9,8 @@
#include <script/interpreter.h>
#include <consensus/validation.h>
#include <nameclaim.h>
// TODO remove the following dependencies
#include <chain.h>
#include <coins.h>
@ -129,8 +131,9 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
assert(!coin.IsSpent());
const CTxOut &prevout = coin.out;
if (prevout.scriptPubKey.IsPayToScriptHash())
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
const CScript& scriptPubKey = StripClaimScriptPrefix(prevout.scriptPubKey);
if (scriptPubKey.IsPayToScriptHash())
nSigOps += scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
}
return nSigOps;
}
@ -178,6 +181,12 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
// check claimtrie transactions
if (ClaimScriptSize(txout.scriptPubKey) > MAX_CLAIM_SCRIPT_SIZE)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-claimscriptsize-toolarge");
if (ClaimNameSize(txout.scriptPubKey) > MAX_CLAIM_NAME_SIZE)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-claimscriptname-toolarge");
}
// Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock

View file

@ -225,7 +225,7 @@ public:
~CDBWrapper();
CDBWrapper(const CDBWrapper&) = delete;
CDBWrapper& operator=(const CDBWrapper&) = delete;
/* CDBWrapper& operator=(const CDBWrapper&) = delete; */
template <typename K, typename V>
bool Read(const K& key, V& value) const

View file

@ -12,6 +12,43 @@ inline uint32_t ROTL32(uint32_t x, int8_t r)
return (x << r) | (x >> (32 - r));
}
uint256 PoWHash(const std::vector<unsigned char>& input)
{
CHash256 h256;
CSHA512 h512;
CRIPEMD160 h160;
std::vector<unsigned char> out;
out.resize(h512.OUTPUT_SIZE);
std::vector<unsigned char> out_small;
out_small.resize(h160.OUTPUT_SIZE);
h256.Write(input.data(), input.size());
h256.Finalize(&out[0]);
h256.Reset();
h512.Write(out.data(), h256.OUTPUT_SIZE);
h512.Finalize(&out[0]);
h160.Write(out.data(), h512.OUTPUT_SIZE / 2);
h160.Finalize(&out_small[0]);
h160.Reset();
h256.Write(out_small.data(), h160.OUTPUT_SIZE);
h160.Write(out.data() + h512.OUTPUT_SIZE / 2, h512.OUTPUT_SIZE / 2);
h160.Finalize(&out_small[0]);
out.resize(h256.OUTPUT_SIZE);
h256.Write(out_small.data(), h160.OUTPUT_SIZE);
h256.Finalize(&out[0]);
uint256 result(out);
return result;
}
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash)
{
// The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp

View file

@ -190,6 +190,8 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
return ss.GetHash();
}
uint256 PoWHash(const std::vector<unsigned char>& input);
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);

View file

@ -16,31 +16,6 @@ constexpr char DB_TXINDEX_BLOCK = 'T';
std::unique_ptr<TxIndex> g_txindex;
struct CDiskTxPos : public CDiskBlockPos
{
unsigned int nTxOffset; // after header
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITEAS(CDiskBlockPos, *this);
READWRITE(VARINT(nTxOffset));
}
CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {
}
CDiskTxPos() {
SetNull();
}
void SetNull() {
CDiskBlockPos::SetNull();
nTxOffset = 0;
}
};
/**
* Access to the txindex database (indexes/txindex/)
*

View file

@ -9,6 +9,31 @@
#include <index/base.h>
#include <txdb.h>
struct CDiskTxPos : public CDiskBlockPos
{
unsigned int nTxOffset; // after header
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITEAS(CDiskBlockPos, *this);
READWRITE(VARINT(nTxOffset));
}
CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {
}
CDiskTxPos() {
SetNull();
}
void SetNull() {
CDiskBlockPos::SetNull();
nTxOffset = 0;
}
};
/**
* TxIndex is used to look up transactions included in the blockchain by hash.
* The index is written to a LevelDB database and records the filesystem

View file

@ -14,6 +14,7 @@
#include <chain.h>
#include <chainparams.h>
#include <checkpoints.h>
#include <claimtrie.h>
#include <compat/sanity.h>
#include <consensus/validation.h>
#include <fs.h>
@ -41,6 +42,7 @@
#include <txmempool.h>
#include <torcontrol.h>
#include <ui_interface.h>
#include <uint256.h>
#include <util.h>
#include <utilmoneystr.h>
#include <validationinterface.h>
@ -264,6 +266,8 @@ void Shutdown()
pcoinscatcher.reset();
pcoinsdbview.reset();
pblocktree.reset();
delete pclaimTrie;
pclaimTrie = nullptr;
}
g_wallet_init_interface.Stop();
@ -1455,6 +1459,8 @@ bool AppInitMain()
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
delete pclaimTrie;
pclaimTrie = new CClaimTrie(false, fReindex);
if (fReset) {
pblocktree->WriteReindexing(true);
@ -1496,6 +1502,12 @@ bool AppInitMain()
break;
}
if (!pclaimTrie->ReadFromDisk(true))
{
strLoadError = _("Error loading the claim trie from disk");
break;
}
// At this point we're either in reindex or we've loaded a useful
// block tree into mapBlockIndex!
@ -1688,6 +1700,9 @@ bool AppInitMain()
}
LogPrintf("nBestHeight = %d\n", chain_active_height);
const Consensus::Params& consensusParams = Params().GetConsensus();
pclaimTrie->setExpirationTime(consensusParams.GetExpirationTime(chain_active_height));
if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl();

40
src/lbry.cpp Normal file
View file

@ -0,0 +1,40 @@
#include <lbry.h>
#include <uint256.h>
#include <cstdio>
unsigned int CalculateLbryNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
if (params.fPowNoRetargeting)
return pindexLast->nBits;
const int64_t retargetTimespan = params.nPowTargetTimespan;
const int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
int64_t nModulatedTimespan = nActualTimespan;
int64_t nMaxTimespan;
int64_t nMinTimespan;
nModulatedTimespan = retargetTimespan + (nModulatedTimespan - retargetTimespan) / 8;
nMinTimespan = retargetTimespan - (retargetTimespan / 8); //(150 - 18 = 132)
nMaxTimespan = retargetTimespan + (retargetTimespan / 2); //(150 + 75 = 225)
// Limit adjustment step
if (nModulatedTimespan < nMinTimespan)
nModulatedTimespan = nMinTimespan;
else if (nModulatedTimespan > nMaxTimespan)
nModulatedTimespan = nMaxTimespan;
// Retarget
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
arith_uint256 bnNew;
bnNew.SetCompact(pindexLast->nBits);
bnNew *= nModulatedTimespan;
bnNew /= retargetTimespan;
if (bnNew > bnPowLimit)
bnNew = bnPowLimit;
return bnNew.GetCompact();
}

9
src/lbry.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef LBRY_H
#define LBRY_H
#include <chain.h>
#include <chainparams.h>
unsigned int CalculateLbryNextWorkRequired(const CBlockIndex* pindexLast, int64_t nLastRetargetTime, const Consensus::Params& params);
#endif

View file

@ -117,7 +117,12 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
CBlockIndex* pindexPrev = chainActive.Tip();
assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
if (!pclaimTrie)
{
LogPrintf("CreateNewBlock(): pclaimTrie is invalid");
return NULL;
}
CClaimTrieCache trieCache(pclaimTrie);
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
// -regtest only: allow overriding block.nVersion with
// -blockversion=N to test forking scenarios
@ -144,7 +149,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
int nPackagesSelected = 0;
int nDescendantsUpdated = 0;
addPackageTxs(nPackagesSelected, nDescendantsUpdated);
addPackageTxs(nPackagesSelected, nDescendantsUpdated, trieCache);
int64_t nTime1 = GetTimeMicros();
@ -172,6 +177,16 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblock->nNonce = 0;
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
insertUndoType dummyInsertUndo;
claimQueueRowType dummyExpireUndo;
insertUndoType dummyInsertSupportUndo;
supportQueueRowType dummyExpireSupportUndo;
std::vector<std::pair<std::string, int> > dummyTakeoverHeightUndo;
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo, dummyTakeoverHeightUndo);
pblock->hashClaimTrie = trieCache.getMerkleHash();
CValidationState state;
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
@ -303,7 +318,7 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, std::ve
// Each time through the loop, we compare the best transaction in
// mapModifiedTxs with the next transaction in the mempool to decide what
// transaction package to work on next.
void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated)
void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, CClaimTrieCache& trieCache)
{
// mapModifiedTx will store sorted packages after they are modified
// because some of their txs are already in the block
@ -413,6 +428,114 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
continue;
}
typedef std::vector<std::pair<std::string, uint160> > spentClaimsType;
spentClaimsType spentClaims;
const CTransaction& tx = iter->GetTx();
for (const CTxIn& txin: tx.vin)
{
CCoinsViewCache view(pcoinsTip.get());
const Coin& coin = view.AccessCoin(txin.prevout);
int nTxinHeight = coin.nHeight;
CScript scriptPubKey = coin.out.scriptPubKey;
std::vector<std::vector<unsigned char> > vvchParams;
int op;
if (DecodeClaimScript(scriptPubKey, op, vvchParams))
{
if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM)
{
uint160 claimId;
if (op == OP_CLAIM_NAME)
{
assert(vvchParams.size() == 2);
claimId = ClaimIdHash(txin.prevout.hash, txin.prevout.n);
}
else if (op == OP_UPDATE_CLAIM)
{
assert(vvchParams.size() == 3);
claimId = uint160(vvchParams[1]);
}
std::string name(vvchParams[0].begin(), vvchParams[0].end());
int throwaway;
if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), throwaway))
{
std::pair<std::string, uint160> entry(name, claimId);
spentClaims.push_back(entry);
}
else
{
LogPrintf("%s(): The claim was not found in the trie or queue and therefore can't be updated\n", __func__);
}
}
else if (op == OP_SUPPORT_CLAIM)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
int throwaway;
if (!trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway))
{
LogPrintf("%s(): The support was not found in the trie or queue\n", __func__);
}
}
}
}
for (unsigned int i = 0; i < tx.vout.size(); ++i)
{
const CTxOut& txout = tx.vout[i];
std::vector<std::vector<unsigned char> > vvchParams;
int op;
if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams))
{
if (op == OP_CLAIM_NAME)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), i), ClaimIdHash(tx.GetHash(), i), txout.nValue, nHeight))
{
LogPrintf("%s: Something went wrong inserting the name\n", __func__);
}
}
else if (op == OP_UPDATE_CLAIM)
{
assert(vvchParams.size() == 3);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 claimId(vvchParams[1]);
spentClaimsType::iterator itSpent;
for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent)
{
if (itSpent->first == name && itSpent->second == claimId)
break;
}
if (itSpent != spentClaims.end())
{
spentClaims.erase(itSpent);
if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), i), claimId, txout.nValue, nHeight))
{
LogPrintf("%s: Something went wrong updating a claim\n", __func__);
}
}
else
{
LogPrintf("%s(): This update refers to a claim that was not found in the trie or queue, and therefore cannot be updated. The claim may have expired or it may have never existed.\n", __func__);
}
}
else if (op == OP_SUPPORT_CLAIM)
{
assert(vvchParams.size() == 2);
std::string name(vvchParams[0].begin(), vvchParams[0].end());
uint160 supportedClaimId(vvchParams[1]);
if (!trieCache.addSupport(name, COutPoint(tx.GetHash(), i), txout.nValue, supportedClaimId, nHeight))
{
LogPrintf("%s: Something went wrong inserting the claim support\n", __func__);
}
}
}
}
// This transaction will make it in; reset the failed counter.
nConsecutiveFailed = 0;

View file

@ -170,7 +170,7 @@ private:
/** Add transactions based on feerate including unconfirmed ancestors
* Increments nPackagesSelected / nDescendantsUpdated with corresponding
* statistics from the package selection (for logging statistics). */
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs);
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, CClaimTrieCache& trieCache) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs);
// helper functions for addPackageTxs()
/** Remove confirmed (inBlock) entries from given set */

201
src/nameclaim.cpp Normal file
View file

@ -0,0 +1,201 @@
#include <boost/foreach.hpp>
#include "nameclaim.h"
#include "hash.h"
#include "util.h"
#include "claimtrie.h"
std::vector<unsigned char> uint32_t_to_vch(uint32_t n)
{
std::vector<unsigned char> vchN;
vchN.resize(4);
vchN[0] = n >> 24;
vchN[1] = n >> 16;
vchN[2] = n >> 8;
vchN[3] = n;
return vchN;
}
uint32_t vch_to_uint32_t(std::vector<unsigned char>& vchN)
{
uint32_t n;
static const size_t uint32Size = sizeof(uint32_t);
if (vchN.size() != uint32Size) {
LogPrintf("%s() : a vector<unsigned char> with size other than 4 has been given", __func__);
return 0;
}
n = vchN[0] << 24 | vchN[1] << 16 | vchN[2] << 8 | vchN[3];
return n;
}
CScript ClaimNameScript(std::string name, std::string value)
{
std::vector<unsigned char> vchName(name.begin(), name.end());
std::vector<unsigned char> vchValue(value.begin(), value.end());
return CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << OP_TRUE;
}
CScript SupportClaimScript(std::string name, uint160 claimId)
{
std::vector<unsigned char> vchName(name.begin(), name.end());
std::vector<unsigned char> vchClaimId(claimId.begin(), claimId.end());
return CScript() << OP_SUPPORT_CLAIM << vchName << vchClaimId << OP_2DROP << OP_DROP << OP_TRUE;
}
CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value)
{
std::vector<unsigned char> vchName(name.begin(), name.end());
std::vector<unsigned char> vchClaimId(claimId.begin(), claimId.end());
std::vector<unsigned char> vchValue(value.begin(), value.end());
return CScript() << OP_UPDATE_CLAIM << vchName << vchClaimId << vchValue << OP_2DROP << OP_2DROP << OP_TRUE;
}
bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams)
{
CScript::const_iterator pc = scriptIn.begin();
return DecodeClaimScript(scriptIn, op, vvchParams, pc);
}
bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, CScript::const_iterator& pc)
{
opcodetype opcode;
if (!scriptIn.GetOp(pc, opcode))
{
return false;
}
if (opcode != OP_CLAIM_NAME && opcode != OP_SUPPORT_CLAIM && opcode != OP_UPDATE_CLAIM)
{
return false;
}
op = opcode;
std::vector<unsigned char> vchParam1;
std::vector<unsigned char> vchParam2;
std::vector<unsigned char> vchParam3;
// Valid formats:
// OP_CLAIM_NAME vchName vchValue OP_2DROP OP_DROP pubkeyscript
// OP_UPDATE_CLAIM vchName vchClaimId vchValue OP_2DROP OP_2DROP pubkeyscript
// OP_SUPPORT_CLAIM vchName vchClaimId OP_2DROP OP_DROP pubkeyscript
// All others are invalid.
if (!scriptIn.GetOp(pc, opcode, vchParam1) || opcode < 0 || opcode > OP_PUSHDATA4)
{
return false;
}
if (!scriptIn.GetOp(pc, opcode, vchParam2) || opcode < 0 || opcode > OP_PUSHDATA4)
{
return false;
}
if (op == OP_UPDATE_CLAIM || op == OP_SUPPORT_CLAIM)
{
static const size_t claimIdHashSize = sizeof(uint160);
if (vchParam2.size() != claimIdHashSize) {
return false;
}
}
if (op == OP_UPDATE_CLAIM)
{
if (!scriptIn.GetOp(pc, opcode, vchParam3) || opcode < 0 || opcode > OP_PUSHDATA4)
{
return false;
}
}
if (!scriptIn.GetOp(pc, opcode) || opcode != OP_2DROP)
{
return false;
}
if (!scriptIn.GetOp(pc, opcode))
{
return false;
}
if ((op == OP_CLAIM_NAME || op == OP_SUPPORT_CLAIM) && opcode != OP_DROP)
{
return false;
}
else if ((op == OP_UPDATE_CLAIM) && opcode != OP_2DROP)
{
return false;
}
vvchParams.push_back(vchParam1);
vvchParams.push_back(vchParam2);
if (op == OP_UPDATE_CLAIM)
{
vvchParams.push_back(vchParam3);
}
return true;
}
uint160 ClaimIdHash(const uint256& txhash, uint32_t nOut)
{
std::vector<unsigned char> claimToHash(txhash.begin(), txhash.end());
std::vector<unsigned char> vchnOut = uint32_t_to_vch(nOut);
claimToHash.insert(claimToHash.end(), vchnOut.begin(), vchnOut.end());
return Hash160(claimToHash);
}
CScript StripClaimScriptPrefix(const CScript& scriptIn)
{
int op;
return StripClaimScriptPrefix(scriptIn, op);
}
CScript StripClaimScriptPrefix(const CScript& scriptIn, int& op)
{
std::vector<std::vector<unsigned char> > vvchParams;
CScript::const_iterator pc = scriptIn.begin();
if (!DecodeClaimScript(scriptIn, op, vvchParams, pc))
{
return scriptIn;
}
return CScript(pc, scriptIn.end());
}
size_t ClaimScriptSize(const CScript& scriptIn)
{
CScript strippedScript = StripClaimScriptPrefix(scriptIn);
return scriptIn.size() - strippedScript.size();
}
size_t ClaimNameSize(const CScript& scriptIn)
{
std::vector<std::vector<unsigned char> > vvchParams;
CScript::const_iterator pc = scriptIn.begin();
int op;
if (!DecodeClaimScript(scriptIn, op, vvchParams, pc))
{
return 0;
}
else
{
return vvchParams[0].size();
}
}
CAmount CalcMinClaimTrieFee(const CTransaction& tx, const CAmount &minFeePerNameClaimChar)
{
if (minFeePerNameClaimChar == 0)
{
return 0;
}
CAmount min_fee = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams))
{
if (op == OP_CLAIM_NAME)
{
int claim_name_size = vvchParams[0].size();
min_fee += claim_name_size*minFeePerNameClaimChar;
}
}
}
return min_fee;
}

45
src/nameclaim.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef BITCOIN_NAMECLAIM_H
#define BITCOIN_NAMECLAIM_H
#include "amount.h"
#include "script/script.h"
#include "primitives/transaction.h"
#include "uint256.h"
#include <vector>
// This is the minimum claim fee per character in the name of an OP_CLAIM_NAME command that must
// be attached to transactions for it to be accepted into the memory pool.
// Rationale: current implementation of the claim trie uses more memory for longer name claims
// due to the fact that each chracater is assigned a trie node regardless of whether it contains
// any claims or not. In the future, we can switch to a radix tree implementation where
// empty nodes do not take up any memory and the minimum fee can be priced on a per claim
// basis.
#define MIN_FEE_PER_NAMECLAIM_CHAR 200000
// This is the max claim script size in bytes, not including the script pubkey part of the script.
// Scripts exceeding this size are rejected in CheckTransaction in main.cpp
#define MAX_CLAIM_SCRIPT_SIZE 8192
// This is the max claim name size in bytes, for all claim trie transactions.
// Scripts exceeding this size are rejected in CheckTransaction in main.cpp
#define MAX_CLAIM_NAME_SIZE 255
CScript ClaimNameScript(std::string name, std::string value);
CScript SupportClaimScript(std::string name, uint160 claimId);
CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value);
bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams);
bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, CScript::const_iterator& pc);
CScript StripClaimScriptPrefix(const CScript& scriptIn);
CScript StripClaimScriptPrefix(const CScript& scriptIn, int& op);
uint160 ClaimIdHash(const uint256& txhash, uint32_t nOut);
std::vector<unsigned char> uint32_t_to_vch(uint32_t n);
uint32_t vch_to_uint32_t(std::vector<unsigned char>& vchN);
// get size of the claim script, minus the script pubkey part
size_t ClaimScriptSize(const CScript& scriptIn);
// get size of the name in a claim script, returns 0 if scriptin is not a claimetrie transaction
size_t ClaimNameSize(const CScript& scriptIn);
// calculate the minimum fee (mempool rule) required for transaction
CAmount CalcMinClaimTrieFee(const CTransaction& tx, const CAmount &minFeePerNameClaimChar);
#endif // BITCOIN_NAMECLAIM_H

View file

@ -1636,6 +1636,7 @@ void CConnman::ThreadDNSAddressSeed()
} else {
std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
// NOTE: After we fork, we can require additional service bits
ServiceFlags requiredServiceBits = GetDesirableServiceFlags(NODE_NONE);
std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
CNetAddr resolveSource;

View file

@ -1549,6 +1549,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
// nMinimumChainWork, even if a peer has a chain past our tip,
// as an anti-DoS measure.
if (IsOutboundDisconnectionCandidate(pfrom)) {
LogPrintf("Disconnecting outbound peer %d (%s < %s) -- headers chain has insufficient work\n", pfrom->GetId(), nodestate->pindexBestKnownBlock->nChainWork.GetHex(), nMinimumChainWork.GetHex());
LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom->GetId());
pfrom->fDisconnect = true;
}
@ -1647,6 +1648,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
nSendVersion = std::min(nVersion, PROTOCOL_VERSION);
nServices = ServiceFlags(nServiceInt);
LogPrint(BCLog::NET, "peer=%d services (%08x offered, %08x expected);\n", pfrom->GetId(), nServices, GetDesirableServiceFlags(nServices));
if (!pfrom->fInbound)
{
connman->SetServices(pfrom->addr, nServices);
@ -2014,6 +2017,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
else if (strCommand == NetMsgType::GETBLOCKS)
{
LogPrintf("%s: Got GETBLOCKS message\n", __func__);
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
@ -3516,17 +3520,24 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
std::vector<CInv> vInv;
{
LOCK(pto->cs_inventory);
vInv.reserve(std::max<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX));
/* vInv.reserve(std::max<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX)); */
// FIXME: Bitcoin bug?!
vInv.reserve(std::min<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX));
// Add blocks
size_t count = 0;
for (const uint256& hash : pto->vInventoryBlockToSend) {
vInv.push_back(CInv(MSG_BLOCK, hash));
if (vInv.size() == MAX_INV_SZ) {
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
if (++count >= INVENTORY_BROADCAST_MAX)
break;
}
pto->vInventoryBlockToSend.clear();
pto->vInventoryBlockToSend.erase(pto->vInventoryBlockToSend.begin(),
pto->vInventoryBlockToSend.begin() + count);
//pto->vInventoryBlockToSend.clear();
// Check whether periodic sends should happen
bool fSendTrickle = pto->fWhitelisted;

View file

@ -115,7 +115,8 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
unsigned int nDataOut = 0;
txnouttype whichType;
for (const CTxOut& txout : tx.vout) {
if (!::IsStandard(txout.scriptPubKey, whichType)) {
const CScript& scriptPubKey = StripClaimScriptPrefix(txout.scriptPubKey);
if (!::IsStandard(scriptPubKey, whichType)) {
reason = "scriptpubkey";
return false;
}
@ -168,7 +169,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
std::vector<std::vector<unsigned char> > vSolutions;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
const CScript& prevScript = prev.scriptPubKey;
const CScript& prevScript = StripClaimScriptPrefix(prev.scriptPubKey);
if (!Solver(prevScript, whichType, vSolutions))
return false;

View file

@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <pow.h>
#include <lbry.h>
#include <arith_uint256.h>
#include <chain.h>
@ -12,38 +13,65 @@
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
assert(pindexLast != nullptr);
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
// Genesis block
if (pindexLast == nullptr)
return nProofOfWorkLimit;
// Only change once per difficulty adjustment interval
if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
if (params.fPowAllowMinDifficultyBlocks && pindexLast->nHeight >= 277299)
{
if (params.fPowAllowMinDifficultyBlocks)
{
// Special difficulty rule for testnet:
// If the new block's timestamp is more than 2* 10 minutes
// then allow mining of a min-difficulty block.
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
return nProofOfWorkLimit;
else
{
// Return the last non-special-min-difficulty-rules-block
const CBlockIndex* pindex = pindexLast;
while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
pindex = pindex->pprev;
return pindex->nBits;
}
// Special difficulty rule for testnet:
// If the new block's timestamp is twice the target block time
// then allow mining of a min-difficulty block.
// This is to prevent the testnet from gettig stuck when a large amount
// of hashrate drops off the network.
// This rule was not implemented properly until testnet block 277299.
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2){
return nProofOfWorkLimit;
}
return pindexLast->nBits;
}
// Go back by what we want to be 14 days worth of blocks
int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
/* // Only change once per difficulty adjustment interval */
/* if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0) */
/* { */
/* if (params.fPowAllowMinDifficultyBlocks) */
/* { */
/* // Special difficulty rule for testnet: */
/* // If the new block's timestamp is more than 2* 10 minutes */
/* // then allow mining of a min-difficulty block. */
/* if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2) */
/* return nProofOfWorkLimit; */
/* else */
/* { */
/* // Return the last non-special-min-difficulty-rules-block */
/* const CBlockIndex* pindex = pindexLast; */
/* while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit) */
/* pindex = pindex->pprev; */
/* return pindex->nBits; */
/* } */
/* } */
/* return pindexLast->nBits; */
/* } */
/* // Go back by what we want to be 14 days worth of blocks */
/* int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1); */
/* assert(nHeightFirst >= 0); */
/* const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst); */
/* assert(pindexFirst); */
/* return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params); */
// Go back the full period unless it's the first retarget after genesis.
int blockstogoback = params.DifficultyAdjustmentInterval()-1;
if ((pindexLast->nHeight+1) != params.DifficultyAdjustmentInterval())
blockstogoback = params.DifficultyAdjustmentInterval();
int nHeightFirst = pindexLast->nHeight - blockstogoback;
assert(nHeightFirst >= 0);
const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
assert(pindexFirst);
return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
return CalculateLbryNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
}
unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)

View file

@ -9,20 +9,30 @@
#include <tinyformat.h>
#include <utilstrencodings.h>
#include <crypto/common.h>
#include <streams.h>
uint256 CBlockHeader::GetHash() const
{
return SerializeHash(*this);
}
uint256 CBlockHeader::GetPoWHash() const
{
CDataStream ds(SER_GETHASH, PROTOCOL_VERSION);
ds << *this;
std::vector<unsigned char> input(ds.begin(), ds.end());
return PoWHash(input);
}
std::string CBlock::ToString() const
{
std::stringstream s;
s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
GetHash().ToString(),
nVersion,
hashPrevBlock.ToString(),
hashMerkleRoot.ToString(),
hashClaimTrie.ToString(),
nTime, nBits, nNonce,
vtx.size());
for (const auto& tx : vtx) {

View file

@ -24,6 +24,7 @@ public:
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
uint256 hashClaimTrie;
uint32_t nTime;
uint32_t nBits;
uint32_t nNonce;
@ -40,6 +41,7 @@ public:
READWRITE(this->nVersion);
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(hashClaimTrie);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
@ -50,6 +52,7 @@ public:
nVersion = 0;
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
hashClaimTrie.SetNull();
nTime = 0;
nBits = 0;
nNonce = 0;
@ -62,6 +65,8 @@ public:
uint256 GetHash() const;
uint256 GetPoWHash() const;
int64_t GetBlockTime() const
{
return (int64_t)nTime;
@ -110,6 +115,7 @@ public:
block.nVersion = nVersion;
block.hashPrevBlock = hashPrevBlock;
block.hashMerkleRoot = hashMerkleRoot;
block.hashClaimTrie = hashClaimTrie;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;

View file

@ -128,12 +128,20 @@ bool CMessageHeader::IsValid(const MessageStartChars& pchMessageStartIn) const
return true;
}
// NOTE: After we fork, we can require these service bits
//
/* ServiceFlags GetDesirableServiceFlags(ServiceFlags services) { */
/* if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) { */
/* return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS); */
/* } */
/* return ServiceFlags(NODE_NETWORK | NODE_WITNESS); */
/* } */
ServiceFlags GetDesirableServiceFlags(ServiceFlags services) {
if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) {
return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);
if ((services & NODE_NETWORK) && g_initial_block_download_completed) {
return ServiceFlags(NODE_NETWORK | NODE_BLOOM);
}
return ServiceFlags(NODE_NETWORK | NODE_WITNESS);
return ServiceFlags(NODE_NETWORK | NODE_BLOOM);
}
void SetServiceFlagsIBDCache(bool state) {

View file

@ -25,6 +25,7 @@
#include <sync.h>
#include <txdb.h>
#include <txmempool.h>
#include <uint256.h>
#include <util.h>
#include <utilstrencodings.h>
#include <hash.h>
@ -66,12 +67,12 @@ double GetDifficulty(const CBlockIndex* blockindex)
double dDiff =
(double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
while (nShift < 29)
while (nShift < 31)
{
dDiff *= 256.0;
nShift++;
}
while (nShift > 29)
while (nShift > 31)
{
dDiff /= 256.0;
nShift--;
@ -94,6 +95,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.pushKV("version", blockindex->nVersion);
result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
result.pushKV("nameclaimroot", blockindex->hashClaimTrie.GetHex());
result.pushKV("time", (int64_t)blockindex->nTime);
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
result.pushKV("nonce", (uint64_t)blockindex->nNonce);
@ -127,6 +129,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
result.pushKV("version", block.nVersion);
result.pushKV("versionHex", strprintf("%08x", block.nVersion));
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
result.pushKV("nameclaimroot", block.hashClaimTrie.GetHex());
UniValue txs(UniValue::VARR);
for(const auto& tx : block.vtx)
{
@ -695,6 +698,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
" \"version\" : n, (numeric) The block version\n"
" \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n"
" \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
" \"nameclaimroot\" : \"xxxx\", (string) The hash of the root of the name claim trie\n"
" \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"nonce\" : n, (numeric) The nonce\n"
@ -780,6 +784,7 @@ static UniValue getblock(const JSONRPCRequest& request)
" \"version\" : n, (numeric) The block version\n"
" \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n"
" \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
" \"nameclaimroot\" : \"xxxx\", (string) The hash of the root of the name claim trie\n"
" \"tx\" : [ (array of string) The transaction ids\n"
" \"transactionid\" (string) The transaction id\n"
" ,...\n"

802
src/rpc/claimtrie.cpp Normal file
View file

@ -0,0 +1,802 @@
#include <claimtrie.h>
#include <coins.h>
#include <core_io.h>
#include <nameclaim.h>
#include <rpc/server.h>
#include <txdb.h>
#include <txmempool.h>
#include <univalue.h>
#include <validation.h>
// Maximum block decrement that is allowed from rpc calls
const int MAX_RPC_BLOCK_DECREMENTS = 50;
static uint160 ParseClaimtrieId(const UniValue& v, const std::string& strName)
{
static constexpr size_t claimIdHexLength = 40;
std::string strHex;
if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be a 20-character hexadecimal string (not '" + strHex + "')");
if (strHex.length() != claimIdHexLength)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, claimIdHexLength, strHex.length()));
uint160 result;
result.SetHex(strHex);
return result;
}
static CBlockIndex* BlockHashIndex(const uint256& blockHash)
{
AssertLockHeld(cs_main);
if (mapBlockIndex.count(blockHash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlockIndex* pblockIndex = mapBlockIndex[blockHash];
if (!chainActive.Contains(pblockIndex))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not in main chain");
if (chainActive.Tip()->nHeight > (pblockIndex->nHeight + MAX_RPC_BLOCK_DECREMENTS))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block is too deep");
return pblockIndex;
}
static std::string encodeValue(const std::string& value)
{
// FIXME: match old encoding??
return SanitizeString(value);
}
static UniValue getclaimsintrie(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
"getclaimsintrie\n"
"Return all claims in the name trie.\n"
"Arguments:\n"
"None\n"
"Result: \n"
"[\n"
" {\n"
" \"name\" (string) the name claimed\n"
" \"claims\": [ (array of object) the claims for this name\n"
" {\n"
" \"claimId\" (string) the claimId of the claim\n"
" \"txid\" (string) the txid of the claim\n"
" \"n\" (numeric) the vout value of the claim\n"
" \"amount\" (numeric) txout amount\n"
" \"height\" (numeric) the height of the block in which this transaction is located\n"
" \"value\" (string) the value of this claim\n"
" }\n"
" ]\n"
" }\n"
"]\n"
);
LOCK(cs_main);
CCoinsViewCache coinsCache(pcoinsTip.get());
CClaimTrieCache trieCache(pclaimTrie);
if (!request.params.empty()) {
CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(request.params[0], "blockhash (optional parameter 1)"));
if (!RollBackTo(blockIndex, coinsCache, trieCache))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Rollback failure");
}
UniValue ret(UniValue::VARR);
std::vector<namedNodeType> nodes = pclaimTrie->flattenTrie();
for (std::vector<namedNodeType>::iterator it = nodes.begin(); it != nodes.end(); ++it)
{
if (!it->second.claims.empty())
{
UniValue node(UniValue::VOBJ);
node.pushKV("name", encodeValue(it->first));
UniValue claims(UniValue::VARR);
for (std::vector<CClaimValue>::iterator itClaims = it->second.claims.begin(); itClaims != it->second.claims.end(); ++itClaims)
{
UniValue claim(UniValue::VOBJ);
claim.pushKV("claimId", itClaims->claimId.GetHex());
claim.pushKV("txid", itClaims->outPoint.hash.GetHex());
claim.pushKV("n", (int)itClaims->outPoint.n);
claim.pushKV("amount", ValueFromAmount(itClaims->nAmount));
claim.pushKV("height", itClaims->nHeight);
const Coin& coin = coinsCache.AccessCoin(itClaims->outPoint);
if (coin.IsSpent())
{
LogPrintf("%s: the specified txout of %s appears to have been spent\n", __func__, itClaims->outPoint.hash.GetHex());
claim.pushKV("error", "Txout spent");
}
else
{
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (!DecodeClaimScript(coin.out.scriptPubKey, op, vvchParams))
{
LogPrintf("%s: the specified txout of %s does not have an claim command\n", __func__, itClaims->outPoint.hash.GetHex());
}
std::string sValue(vvchParams[1].begin(), vvchParams[1].end());
claim.pushKV("value", encodeValue(sValue));
}
claims.push_back(claim);
}
node.pushKV("claims", claims);
ret.push_back(node);
}
}
return ret;
}
static UniValue getclaimtrie(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
"getclaimtrie\n"
"Return the entire claim trie.\n"
"Arguments:\n"
"None\n"
"Result: \n"
"{\n"
" \"name\" (string) the name of the node\n"
" \"hash\" (string) the hash of the node\n"
" \"txid\" (string) (if value exists) the hash of the transaction which has successfully claimed this name\n"
" \"n\" (numeric) (if value exists) vout value\n"
" \"value\" (numeric) (if value exists) txout value\n"
" \"height\" (numeric) (if value exists) the height of the block in which this transaction is located\n"
"}\n"
);
LOCK(cs_main);
UniValue ret(UniValue::VARR);
std::vector<namedNodeType> nodes = pclaimTrie->flattenTrie();
for (std::vector<namedNodeType>::iterator it = nodes.begin(); it != nodes.end(); ++it)
{
UniValue node(UniValue::VOBJ);
node.pushKV("name", encodeValue(it->first));
node.pushKV("hash", it->second.hash.GetHex());
CClaimValue claim;
if (it->second.getBestClaim(claim))
{
node.pushKV("txid", claim.outPoint.hash.GetHex());
node.pushKV("n", (int)claim.outPoint.n);
node.pushKV("value", ValueFromAmount(claim.nAmount));
node.pushKV("height", claim.nHeight);
}
ret.push_back(node);
}
return ret;
}
static bool getValueForClaim(const CCoinsViewCache& coinsCache, const COutPoint& out, std::string& sValue)
{
const Coin& coin = coinsCache.AccessCoin(out);
if (coin.IsSpent())
{
LogPrintf("%s: the specified txout of %s appears to have been spent\n", __func__, out.hash.GetHex());
return true;
}
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (!DecodeClaimScript(coin.out.scriptPubKey, op, vvchParams))
{
LogPrintf("%s: the specified txout of %s does not have a name claim command\n", __func__, out.hash.GetHex());
return false;
}
if (op == OP_CLAIM_NAME)
{
sValue = std::string(vvchParams[1].begin(), vvchParams[1].end());
}
else if (op == OP_UPDATE_CLAIM)
{
sValue = std::string(vvchParams[2].begin(), vvchParams[2].end());
}
return true;
}
static UniValue getvalueforname(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"getvalueforname \"name\"\n"
"Return the value associated with a name, if one exists\n"
"Arguments:\n"
"1. \"name\" (string) the name to look up\n"
"2. \"blockhash\" (string, optional) get the value\n"
" associated with the name\n"
" at the block specified\n"
" by this block hash.\n"
" If none is given,\n"
" the latest active\n"
" block will be used.\n"
"Result: \n"
"\"value\" (string) the value of the name, if it exists\n"
"\"claimId\" (string) the claimId for this name claim\n"
"\"txid\" (string) the hash of the transaction which successfully claimed the name\n"
"\"n\" (numeric) vout value\n"
"\"amount\" (numeric) txout amount\n"
"\"effective amount\" (numeric) txout amount plus amount from all supports associated with the claim\n"
"\"height\" (numeric) the height of the block in which this transaction is located\n");
LOCK(cs_main);
CCoinsViewCache coinsCache(pcoinsTip.get());
CClaimTrieCache trieCache(pclaimTrie);
if (request.params.size() > 1) {
CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(request.params[1], "blockhash (optional parameter 2)"));
if (!RollBackTo(blockIndex, coinsCache, trieCache))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Rollback failure");
}
const auto& name = request.params[0].get_str();
UniValue ret(UniValue::VOBJ);
CClaimValue claim;
if (!trieCache.getInfoForName(name, claim))
return ret; // they may have asked for a name that doesn't exist (which is not an error)
std::string sValue;
if (!getValueForClaim(coinsCache, claim.outPoint, sValue))
return ret;
const auto nEffectiveAmount = trieCache.getEffectiveAmountForClaim(name, claim.claimId);
ret.pushKV("value", encodeValue(sValue));
ret.pushKV("claimId", claim.claimId.GetHex());
ret.pushKV("txid", claim.outPoint.hash.GetHex());
ret.pushKV("n", (int)claim.outPoint.n);
ret.pushKV("amount", claim.nAmount);
ret.pushKV("effective amount", nEffectiveAmount);
ret.pushKV("height", claim.nHeight);
return ret;
}
typedef std::pair<CClaimValue, std::vector<CSupportValue> > claimAndSupportsType;
typedef std::map<uint160, claimAndSupportsType> claimSupportMapType;
UniValue supportToJSON(const CSupportValue& support)
{
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("txid", support.outPoint.hash.GetHex()));
ret.push_back(Pair("n", (int)support.outPoint.n));
ret.push_back(Pair("nHeight", support.nHeight));
ret.push_back(Pair("nValidAtHeight", support.nValidAtHeight));
ret.push_back(Pair("nAmount", support.nAmount));
return ret;
}
UniValue claimAndSupportsToJSON(CAmount nEffectiveAmount, claimSupportMapType::const_iterator itClaimsAndSupports)
{
const CClaimValue& claim = itClaimsAndSupports->second.first;
const std::vector<CSupportValue>& supports = itClaimsAndSupports->second.second;
UniValue supportObjs(UniValue::VARR);
for (const auto& support: supports)
supportObjs.push_back(supportToJSON(support));
UniValue result(UniValue::VOBJ);
result.pushKV("claimId", itClaimsAndSupports->first.GetHex());
result.pushKV("txid", claim.outPoint.hash.GetHex());
result.pushKV("n", (int)claim.outPoint.n);
result.pushKV("nHeight", claim.nHeight);
result.pushKV("nValidAtHeight", claim.nValidAtHeight);
result.pushKV("nAmount", claim.nAmount);
result.pushKV("nEffectiveAmount", nEffectiveAmount);
result.pushKV("supports", supportObjs);
return result;
}
UniValue getclaimsforname(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"getclaimsforname\n"
"Return all claims and supports for a name\n"
"Arguments: \n"
"1. \"name\" (string) the name for which to get claims and supports\n"
"Result:\n"
"{\n"
" \"nLastTakeoverheight\" (numeric) the last height at which ownership of the name changed\n"
" \"claims\": [ (array of object) claims for this name\n"
" {\n"
" \"claimId\" (string) the claimId of this claim\n"
" \"txid\" (string) the txid of this claim\n"
" \"n\" (numeric) the index of the claim in the transaction's list of outputs\n"
" \"nHeight\" (numeric) the height at which the claim was included in the blockchain\n"
" \"nValidAtHeight\" (numeric) the height at which the claim became/becomes valid\n"
" \"nAmount\" (numeric) the amount of the claim\n"
" \"nEffectiveAmount\" (numeric) the total effective amount of the claim, taking into effect whether the claim or support has reached its nValidAtHeight\n"
" \"supports\" : [ (array of object) supports for this claim\n"
" \"txid\" (string) the txid of the support\n"
" \"n\" (numeric) the index of the support in the transaction's list of outputs\n"
" \"nHeight\" (numeric) the height at which the support was included in the blockchain\n"
" \"nValidAtHeight\" (numeric) the height at which the support became/becomes valid\n"
" \"nAmount\" (numeric) the amount of the support\n"
" ]\n"
" }\n"
" ],\n"
" \"unmatched supports\": [ (array of object) supports that did not match a claim for this name\n"
" {\n"
" \"txid\" (string) the txid of the support\n"
" \"n\" (numeric) the index of the support in the transaction's list of outputs\n"
" \"nHeight\" (numeric) the height at which the support was included in the blockchain\n"
" \"nValidAtHeight\" (numeric) the height at which the support became/becomes valid\n"
" \"nAmount\" (numeric) the amount of the support\n"
" }\n"
" ]\n"
"}\n"
);
LOCK(cs_main);
CCoinsViewCache coinsCache(pcoinsTip.get());
CClaimTrieCache trieCache(pclaimTrie);
if (request.params.size() > 1) {
CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(request.params[1], "blockhash (optional parameter 2)"));
if (!RollBackTo(blockIndex, coinsCache, trieCache))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Rollback failure");
}
std::string name = request.params[0].get_str();
claimsForNameType claimsForName = pclaimTrie->getClaimsForName(name);
UniValue claimObjs(UniValue::VARR);
claimSupportMapType claimSupportMap;
UniValue unmatchedSupports(UniValue::VARR);
for (std::vector<CClaimValue>::const_iterator itClaims = claimsForName.claims.begin(); itClaims != claimsForName.claims.end(); ++itClaims)
{
claimAndSupportsType claimAndSupports = std::make_pair(*itClaims, std::vector<CSupportValue>());
claimSupportMap.insert(std::pair<uint160, claimAndSupportsType>(itClaims->claimId, claimAndSupports));
}
for (std::vector<CSupportValue>::const_iterator itSupports = claimsForName.supports.begin(); itSupports != claimsForName.supports.end(); ++itSupports)
{
claimSupportMapType::iterator itClaimAndSupports = claimSupportMap.find(itSupports->supportedClaimId);
if (itClaimAndSupports == claimSupportMap.end())
unmatchedSupports.push_back(supportToJSON(*itSupports));
else
itClaimAndSupports->second.second.push_back(*itSupports);
}
UniValue result(UniValue::VOBJ);
result.pushKV("nLastTakeoverHeight", claimsForName.nLastTakeoverHeight);
for (claimSupportMapType::const_iterator itClaimsAndSupports = claimSupportMap.begin(); itClaimsAndSupports != claimSupportMap.end(); ++itClaimsAndSupports)
{
const auto nEffectiveAmount = trieCache.getEffectiveAmountForClaim(claimsForName, itClaimsAndSupports->first);
claimObjs.push_back(claimAndSupportsToJSON(nEffectiveAmount, itClaimsAndSupports));
}
result.pushKV("claims", claimObjs);
result.pushKV("unmatched supports", unmatchedSupports);
return result;
}
UniValue getclaimbyid(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"getclaimbyid\n"
"Get a claim by claim id\n"
"Arguments: \n"
"1. \"claimId\" (string) the claimId of this claim\n"
"Result:\n"
"{\n"
" \"name\" (string) the name of the claim\n"
" \"value\" (string) claim metadata\n"
" \"claimId\" (string) the claimId of this claim\n"
" \"txid\" (string) the hash of the transaction which has successfully claimed this name\n"
" \"n\" (numeric) vout value\n"
" \"amount\" (numeric) txout value\n"
" \"effective amount\" (numeric) txout amount plus amount from all supports associated with the claim\n"
" \"supports\" (array of object) supports for this claim\n"
" [\n"
" \"txid\" (string) the txid of the support\n"
" \"n\" (numeric) the index of the support in the transaction's list of outputs\n"
" \"height\" (numeric) the height at which the support was included in the blockchain\n"
" \"valid at height\" (numeric) the height at which the support is valid\n"
" \"amount\" (numeric) the amount of the support\n"
" ]\n"
" \"height\" (numeric) the height of the block in which this claim transaction is located\n"
" \"valid at height\" (numeric) the height at which the claim is valid\n"
"}\n");
LOCK(cs_main);
uint160 claimId = ParseClaimtrieId(request.params[0], "Claim-id (parameter 1)");
UniValue claim(UniValue::VOBJ);
std::string name;
CClaimValue claimValue;
pclaimTrie->getClaimById(claimId, name, claimValue);
if (claimValue.claimId == claimId)
{
std::vector<CSupportValue> supports;
CAmount effectiveAmount = pclaimTrie->getEffectiveAmountForClaim(name, claimValue.claimId, &supports);
std::string sValue;
claim.pushKV("name", name);
CCoinsViewCache coinsCache(pcoinsTip.get());
if (getValueForClaim(coinsCache, claimValue.outPoint, sValue))
claim.pushKV("value", encodeValue(sValue));
claim.pushKV("claimId", claimValue.claimId.GetHex());
claim.pushKV("txid", claimValue.outPoint.hash.GetHex());
claim.pushKV("n", (int) claimValue.outPoint.n);
claim.pushKV("amount", claimValue.nAmount);
claim.pushKV("effective amount", effectiveAmount);
UniValue supportList(UniValue::VARR);
for(const CSupportValue& support: supports) {
UniValue supportEntry(UniValue::VOBJ);
supportEntry.pushKV("txid", support.outPoint.hash.GetHex());
supportEntry.pushKV("n", (int)support.outPoint.n);
supportEntry.pushKV("height", support.nHeight);
supportEntry.pushKV("valid at height", support.nValidAtHeight);
supportEntry.pushKV("amount", support.nAmount);
supportList.pushKVs(supportEntry);
}
claim.pushKV("supports", supportList);
claim.pushKV("height", claimValue.nHeight);
claim.pushKV("valid at height", claimValue.nValidAtHeight);
}
return claim;
}
UniValue gettotalclaimednames(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
"gettotalclaimednames\n"
"Return the total number of names that have been\n"
"successfully claimed, and therefore exist in the trie\n"
"Arguments:\n"
"Result:\n"
"\"total names\" (numeric) the total number of\n"
" names in the trie\n"
);
LOCK(cs_main);
if (!pclaimTrie)
{
return -1;
}
unsigned int num_names = pclaimTrie->getTotalNamesInTrie();
return int(num_names);
}
UniValue gettotalclaims(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
"gettotalclaims\n"
"Return the total number of active claims in the trie\n"
"Arguments:\n"
"Result:\n"
"\"total claims\" (numeric) the total number\n"
" of active claims\n"
);
LOCK(cs_main);
if (!pclaimTrie)
{
return -1;
}
unsigned int num_claims = pclaimTrie->getTotalClaimsInTrie();
return int(num_claims);
}
UniValue gettotalvalueofclaims(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
throw std::runtime_error(
"gettotalvalueofclaims\n"
"Return the total value of the claims in the trie\n"
"Arguments:\n"
"1. \"controlling_only\" (boolean) only include the value\n"
" of controlling claims\n"
"Result:\n"
"\"total value\" (numeric) the total value of the\n"
" claims in the trie\n"
);
LOCK(cs_main);
if (!pclaimTrie)
{
return -1;
}
bool controlling_only = false;
if (request.params.size() == 1)
controlling_only = request.params[0].get_bool();
CAmount total_amount = pclaimTrie->getTotalValueOfClaimsInTrie(controlling_only);
return ValueFromAmount(total_amount);
}
UniValue getclaimsfortx(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"getclaimsfortx\n"
"Return any claims or supports found in a transaction\n"
"Arguments:\n"
"1. \"txid\" (string) the txid of the transaction to check for unspent claims\n"
"Result:\n"
"[\n"
" {\n"
" \"nOut\" (numeric) the index of the claim or support in the transaction's list of outputs\n"
" \"claim type\" (string) 'claim' or 'support'\n"
" \"name\" (string) the name claimed or supported\n"
" \"value\" (string) if a name claim, the value of the claim\n"
" \"supported txid\" (string) if a support, the txid of the supported claim\n"
" \"supported nout\" (numeric) if a support, the index of the supported claim in its transaction\n"
" \"depth\" (numeric) the depth of the transaction in the main chain\n"
" \"in claim trie\" (boolean) if a name claim, whether the claim is active, i.e. has made it into the trie\n"
" \"is controlling\" (boolean) if a name claim, whether the claim is the current controlling claim for the name\n"
" \"in support map\" (boolean) if a support, whether the support is active, i.e. has made it into the support map\n"
" \"in queue\" (boolean) whether the claim is in a queue waiting to be inserted into the trie or support map\n"
" \"blocks to valid\" (numeric) if in a queue, the number of blocks until it's inserted into the trie or support map\n"
" }\n"
"]\n"
);
LOCK(cs_main);
uint256 hash;
hash.SetHex(request.params[0].get_str());
UniValue ret(UniValue::VARR);
int op;
std::vector<std::vector<unsigned char> > vvchParams;
CCoinsViewCache &view = *pcoinsTip;
const Coin& coin = AccessByTxid(view, hash);
std::vector<CTxOut> txouts{ coin.out };
int nHeight = coin.nHeight;
for (unsigned int i = 0; i < txouts.size(); ++i)
{
if (!txouts[i].IsNull())
{
vvchParams.clear();
const CTxOut& txout = txouts[i];
UniValue o(UniValue::VOBJ);
if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams))
{
o.pushKV("nOut", static_cast<int64_t>(i));
std::string sName(vvchParams[0].begin(), vvchParams[0].end());
o.pushKV("name", sName);
if (op == OP_CLAIM_NAME)
{
std::string sValue(vvchParams[1].begin(), vvchParams[1].end());
uint160 claimId = ClaimIdHash(hash, i);
o.pushKV("claimId", claimId.GetHex());
o.pushKV("value", encodeValue(sValue));
}
else if (op == OP_UPDATE_CLAIM)
{
uint160 claimId(vvchParams[1]);
std::string sValue(vvchParams[2].begin(), vvchParams[2].end());
o.pushKV("claimId", claimId.GetHex());
o.pushKV("value", encodeValue(sValue));
}
else if (op == OP_SUPPORT_CLAIM)
{
uint160 supportedClaimId(vvchParams[1]);
o.pushKV("supported claimId", supportedClaimId.GetHex());
}
if (nHeight > 0)
{
o.pushKV("depth", chainActive.Height() - nHeight);
if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM)
{
bool inClaimTrie = pclaimTrie->haveClaim(sName, COutPoint(hash, i));
o.pushKV("in claim trie", inClaimTrie);
if (inClaimTrie)
{
CClaimValue claim;
if (!pclaimTrie->getInfoForName(sName, claim))
{
LogPrintf("HaveClaim was true but getInfoForName returned false.");
}
o.pushKV("is controlling", (claim.outPoint.hash == hash && claim.outPoint.n == i));
}
else
{
int nValidAtHeight;
if (pclaimTrie->haveClaimInQueue(sName, COutPoint(hash, i), nValidAtHeight))
{
o.pushKV("in queue", true);
o.pushKV("blocks to valid", nValidAtHeight - chainActive.Height());
}
else
{
o.pushKV("in queue", false);
}
}
}
else if (op == OP_SUPPORT_CLAIM)
{
bool inSupportMap = pclaimTrie->haveSupport(sName, COutPoint(hash, i));
o.pushKV("in support map", inSupportMap);
if (!inSupportMap)
{
int nValidAtHeight;
if (pclaimTrie->haveSupportInQueue(sName, COutPoint(hash, i), nValidAtHeight))
{
o.pushKV("in queue", true);
o.pushKV("blocks to valid", nValidAtHeight - chainActive.Height());
}
else
{
o.pushKV("in queue", false);
}
}
}
}
else
{
o.pushKV("depth", 0);
if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM)
{
o.pushKV("in claim trie", false);
}
else if (op == OP_SUPPORT_CLAIM)
{
o.pushKV("in support map", false);
}
o.pushKV("in queue", false);
}
ret.push_back(o);
}
}
}
return ret;
}
UniValue proofToJSON(const CClaimTrieProof& proof)
{
UniValue result(UniValue::VOBJ);
UniValue nodes(UniValue::VARR);
for (std::vector<CClaimTrieProofNode>::const_iterator itNode = proof.nodes.begin(); itNode != proof.nodes.end(); ++itNode)
{
UniValue node(UniValue::VOBJ);
UniValue children(UniValue::VARR);
for (std::vector<std::pair<unsigned char, uint256> >::const_iterator itChildren = itNode->children.begin(); itChildren != itNode->children.end(); ++itChildren)
{
UniValue child(UniValue::VOBJ);
child.pushKV("character", itChildren->first);
if (!itChildren->second.IsNull())
{
child.pushKV("nodeHash", itChildren->second.GetHex());
}
children.push_back(child);
}
node.pushKV("children", children);
if (itNode->hasValue && !itNode->valHash.IsNull())
{
node.pushKV("valueHash", itNode->valHash.GetHex());
}
nodes.push_back(node);
}
result.pushKV("nodes", nodes);
if (proof.hasValue)
{
result.pushKV("txhash", proof.outPoint.hash.GetHex());
result.pushKV("nOut", (int)proof.outPoint.n);
result.pushKV("last takeover height", (int)proof.nHeightOfLastTakeover);
}
return result;
}
UniValue getnameproof(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
throw std::runtime_error(
"getnameproof\n"
"Return the cryptographic proof that a name maps to a value\n"
"or doesn't.\n"
"Arguments:\n"
"1. \"name\" (string) the name to get a proof for\n"
"2. \"blockhash\" (string, optional) the hash of the block\n"
" which is the basis\n"
" of the proof. If\n"
" none is given, \n"
" the latest block\n"
" will be used.\n"
"Result: \n"
"{\n"
" \"nodes\" : [ (array of object) full nodes (i.e.\n"
" those which lead to\n"
" the requested name)\n"
" \"children\" : [ (array of object) the children of\n"
" this node\n"
" \"child\" : { (object) a child node, either leaf or\n"
" reference to a full node\n"
" \"character\" : \"char\" (string) the character which\n"
" leads from the parent\n"
" to this child node\n"
" \"nodeHash\" : \"hash\" (string, if exists) the hash of\n"
" the node if\n"
" this is a \n"
" leaf node\n"
" }\n"
" ]\n"
" \"valueHash\" (string, if exists) the hash of this\n"
" node's value, if\n"
" it has one. If \n"
" this is the\n"
" requested name\n"
" this will not\n"
" exist whether\n"
" the node has a\n"
" value or not\n"
" ]\n"
" \"txhash\" : \"hash\" (string, if exists) the txid of the\n"
" claim which controls\n"
" this name, if there\n"
" is one.\n"
" \"nOut\" : n, (numeric) the nOut of the claim which\n"
" controls this name, if there\n"
" is one.\n"
" \"last takeover height\" (numeric) the most recent height at\n"
" which the value of a name\n"
" changed other than through\n"
" an update to the winning\n"
" bid\n"
" }\n"
"}\n");
LOCK(cs_main);
std::string strName = request.params[0].get_str();
uint256 blockHash;
if (request.params.size() == 2)
{
std::string strBlockHash = request.params[1].get_str();
blockHash = uint256S(strBlockHash);
}
else
{
blockHash = chainActive.Tip()->GetBlockHash();
}
if (mapBlockIndex.count(blockHash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlockIndex* pblockIndex = mapBlockIndex[blockHash];
if (!chainActive.Contains(pblockIndex))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not in main chain");
if (chainActive.Tip()->nHeight > (pblockIndex->nHeight + MAX_RPC_BLOCK_DECREMENTS))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block too deep to generate proof");
CClaimTrieProof proof;
if (!GetProofForName(pblockIndex, strName, proof))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed to generate proof");
return proofToJSON(proof);
}
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
{ "Claimtrie", "getclaimsintrie", &getclaimsintrie, { "" } },
{ "Claimtrie", "getclaimtrie", &getclaimtrie, { "" } },
{ "Claimtrie", "getvalueforname", &getvalueforname, { "name" } },
{ "Claimtrie", "getclaimsforname", &getclaimsforname, { "name" } },
{ "Claimtrie", "gettotalclaimednames", &gettotalclaimednames, { "" } },
{ "Claimtrie", "gettotalclaims", &gettotalclaims, { "" } },
{ "Claimtrie", "gettotalvalueofclaims", &gettotalvalueofclaims, { "controlling_only" } },
{ "Claimtrie", "getclaimsfortx", &getclaimsfortx, { "txid" } },
{ "Claimtrie", "getnameproof", &getnameproof, { "name","blockhash"} },
{ "Claimtrie", "getclaimbyid", &getclaimbyid, {"claimId"} },
};
void RegisterClaimTrieRPCCommands(CRPCTable &tableRPC)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
}

View file

@ -19,6 +19,8 @@ void RegisterMiscRPCCommands(CRPCTable &tableRPC);
void RegisterMiningRPCCommands(CRPCTable &tableRPC);
/** Register raw transaction RPC commands */
void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
/** Register claim trie RPC commands */
void RegisterClaimTrieRPCCommands(CRPCTable &tableRPC);
static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
{
@ -27,6 +29,8 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
RegisterMiscRPCCommands(t);
RegisterMiningRPCCommands(t);
RegisterRawTransactionRPCCommands(t);
RegisterRawTransactionRPCCommands(t);
RegisterClaimTrieRPCCommands(t);
}
#endif // BITCOIN_RPC_REGISTER_H

View file

@ -285,7 +285,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
// static const CScriptNum bnFalse(0);
// static const CScriptNum bnTrue(1);
static const valtype vchFalse(0);
// static const valtype vchZero(0);
static const valtype vchZero(0);
static const valtype vchTrue(1, 1);
CScript::const_iterator pc = script.begin();
@ -423,6 +423,13 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
break;
}
case OP_CLAIM_NAME: case OP_SUPPORT_CLAIM: case OP_UPDATE_CLAIM:
{
CScriptNum n(OP_0);
stack.push_back(vchZero);
}
break;
case OP_CHECKSEQUENCEVERIFY:
{
if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
@ -458,7 +465,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
}
case OP_NOP1: case OP_NOP4: case OP_NOP5:
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
case OP_NOP9: case OP_NOP10:
{
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);

View file

@ -20,7 +20,8 @@
#include <vector>
// Maximum number of bytes pushable to the stack
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;
/* static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; */
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 20000; // bytes
// Maximum number of non-push operations per script
static const int MAX_OPS_PER_SCRIPT = 201;
@ -176,8 +177,11 @@ enum opcodetype
OP_NOP4 = 0xb3,
OP_NOP5 = 0xb4,
OP_NOP6 = 0xb5,
OP_CLAIM_NAME = OP_NOP6,
OP_NOP7 = 0xb6,
OP_SUPPORT_CLAIM = OP_NOP7,
OP_NOP8 = 0xb7,
OP_UPDATE_CLAIM = OP_NOP8,
OP_NOP9 = 0xb8,
OP_NOP10 = 0xb9,

View file

@ -37,56 +37,48 @@ struct TestVector {
};
TestVector test1 =
TestVector("000102030405060708090a0b0c0d0e0f")
("xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
TestVector("000102030405060708090a0b0c0d0e0f")
("Lpub2hkYkGHXktBhLCamCogeqGV7fQatCHyAe3LstjaUdvp6syZNaSGjdxf68TZG1hmc4Dz1dnMnZad1HHiS3DopTy4QxrMcSbiGir5nXrU2xFd",
"LprvXPsFZUGgrX1X8fNGTeYQawgXAMnj4SeUu4SpYk4vfQ5MtF16HTUVzFEmFmfM4D4JQ66TyH2y3X1SAkMtYvV455cRn2EPLb1DyK21SWCtZac",
0x80000000)
("xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw",
"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
("Lpub2k1xjyazr9JgUoiUQZZHiJbDzE9EaNTBKemmrpxbc81PFFrYzfopm71Vuj7xm1g94SGaW1uDJDh6FggZzFYCXrX9AV9sMucVEnDLqVLA3bY",
"LprvXS8fZBa9wn8WHGVyfQR3TyndVBM5SX8VafsiWqT3dbGeFXJGhh1b7PbB331gTvSG78zALaMqRsrJtWPcCWmEs9gwqtuXaYi7gKersfwXWn8",
1)
("xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ",
"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
("Lpub2nC5wm8tErBkKFkv8pTAK3Ut3c8LaQBUFyScT6jQYkobUoMgiUE8ifujKoaYAxPV29tdHSMKQpBZqzRPTai6DWM5TgziqYcksWk88PnCeej",
"LprvXUJnky83LV1a7iYRPfJv4igHYZLBSYrnWzYZ77DraE4rV4oQRVRu4xVQT6Ck4rDJZDjr9PxGWaoj2SuqKrZDeKBPMfsFeJUyM7yEQc2m5F9",
0x80000002)
("xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
("Lpub2poMzHxjwj3ABRZ1PQrXg3X2GkzrqwmTbWgHhS2ZidB2teYoXE4Zd7TespmNcppoNfzMtpKvnkkYJKZgAgFdGxVv3axrvVgSbCfGDgJ2VpS",
"LprvXWv4oVwu3MryytLWeFiHRiiRmiChi6SmrXnEMSX1k6SHtuzXEFGKyQ3L18RN35io4gmEjruBvzddFeeausUQmQd3iHRooEiuxPiT3AByBL9",
2)
("xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV",
"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
("Lpub2s2kpj5h8Ci9Fu2j5g4cZYgLMaHbUY5f2zZaxPZ334jeFkBAazkvpgvaZ9km2cyXqz7Y2posqVeerjugFygpzYyAxNX3kgaGbta7NFjbxNP",
"LprvXZ9Tdw4rDqXy4MpELWvNKDsjrXVSLgkyJ1fXcQ3V4XzuG1ctJ1xhAyWFgSppVk8E8UtwMn8kqp5niqZ37J1kxoD67XWuMKYd7NBcYeJ6jSm",
1000000000)
("xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy",
"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
("Lpub2tkXJQgwFL6LnEpBCDdLsFgL9oruJ2tgqEx9CfwBF988xsaZ7R1b5o5eByfhst4FKgQ5YAjgNhMFTAJhMqBfqp8Hpuw8ZA9uQrC2cTHvMov",
"LprvXasE7cg6LxvAahbgT4V6cvsjem4kABa16G45rgRdGcPPy92GpSDMS5fKKJc2QfFJjtJC997hgrcuj1ZQeN2V5krdT2H8UEJLPhjyHjdGM3u",
0);
TestVector test2 =
TestVector("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542")
("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
TestVector("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484\
542")
("Lpub2hkYkGHXktBhKp66JxkwHUCsubjJsvDzKd8cBgKJcJvyAxaZkb3g4rpgUZeEix8ZxnDoYT1wxf8G15SfAQiybt4MpnZ5H6Cw3DktojFA2uq",
"LprvXPsFZUGgrX1X8GsbZoch39QHQYw9k4uJaeEYqgokdnCEBE2HTcFSR9QMbqSQEicPe8qtiZVRKd3dGH5zbLskgSwCESJdUvuxYZeEoQkoij6",
0)
("xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
("Lpub2m2J1yyVEu1mr5gPSk8pMGcQGZUZatiGsnsyMVLkginvrw2YKrPkDhPw42c8X391B6hyQg1hMjyEAEsM3ZRPwUie6qHkBSMKAhsZEyWPpRJ",
"LprvXT8zqBxeLXqbeYTthaza6woomWgQT3Pb8oyv1VqCiC4BsCUG2sbWZyycBLiCsnTE3o5icZu9knTkcnip9dNocg6bEcigsR5hfyYoAmjDmEw",
0xFFFFFFFF)
("xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
("Lpub2nBMGb11coBt1wtZsC8TpcHxfJhU8NsxxwxWGtFXLTZKKEFzwjp4RmBXfQrFGmk6xcdX4WsJexPppujgpTuWfdBGduuoYAcL369A5mJaAUR",
"LprvXUJ45nzAiS1hpQg582zDaHVNAFuJzXZHDy4SvtjyMvpaKVhiem1pn3mCnhCBc3Bhx2QcPb6nonxs42TaszywByY9fLx2dvoxTktKw75RfhE",
1)
("xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon",
"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
("Lpub2pzKgbywnSV57ZZhvrH2nZEBzqZyEZoEHPTN7wureLukz48AFFLmKfZuWD3P4eSPYo64u9xYJ5heuhzhjNLTvxeBEC7eki3Xxrp7LFdK9GD",
"LprvXX72Voy6t5Jtv2MDBh8nYERbVnmp6iUYYQZJmxQJfpB1zKZsxGYXfx9adVPodkPQFymK8tBBDLe5NjEjvtWKCTMSo7UqV2nLwZK4Qns6Jan",
0xFFFFFFFE)
("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",
"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
("Lpub2rAMbZvJPqSnQWoJfL6aA4vNua3LHYRjK6BFefcGV7B1SQT6LvGmrBw18sAtG1xqWEjhhf2FLh2WZMA6RFSyeKLdW6S9K18wq5tgsCMpiS8",
"LprvXYH4QmuTVUGcCyaovAxKuk7nQXFB9h73a7HCJg6iWaSGSftp3wUYCUWgGC8CGAmgoZ41ShxAbiDfBrL7SqQotJ2cd429dEoyH9KaUbZHRAn",
2)
("xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
("Lpub2sXPZ18ov1m29mzCPQEG8pJMJdaSXsLoyFo94Sxm7u2bWbnfWZCY2kt1DGFAPbKY2HwvyaXfEQ3W3nDbFM8sxaCD9GGEFNRgWP5sXmFVSUv",
"LprvXZe6ND7y1eaqxEmheF61tVVkoanHQ228EGu5iTTD9NHrWsEPDaQJP3TgLboCRBrkqrujjTaz3p4MEQDdB9n2wGmLRuXegewgyWf8ZANdd3A",
0);
TestVector test3 =
TestVector("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be")
("xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13",
"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6",
0x80000000)
("xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y",
"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L",
0);
static void RunTest(const TestVector &test) {
std::vector<unsigned char> seed = ParseHex(test.strHexMaster);
CExtKey key;
@ -147,8 +139,4 @@ BOOST_AUTO_TEST_CASE(bip32_test2) {
RunTest(test2);
}
BOOST_AUTO_TEST_CASE(bip32_test3) {
RunTest(test3);
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -24,7 +24,7 @@ static CBlockIndex* CreateBlockIndexWithNbits(uint32_t nbits)
static void RejectDifficultyMismatch(double difficulty, double expected_difficulty) {
BOOST_CHECK_MESSAGE(
DoubleEquals(difficulty, expected_difficulty, 0.00001),
DoubleEquals(difficulty, expected_difficulty, 0.058593),
"Difficulty was " + std::to_string(difficulty)
+ " but was expected to be " + std::to_string(expected_difficulty));
}
@ -45,12 +45,12 @@ BOOST_FIXTURE_TEST_SUITE(blockchain_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(get_difficulty_for_very_low_target)
{
TestDifficulty(0x1f111111, 0.000001);
TestDifficulty(0x1f00ffff, 0.058593);
}
BOOST_AUTO_TEST_CASE(get_difficulty_for_low_target)
{
TestDifficulty(0x1ef88f6f, 0.000016);
TestDifficulty(0x1ef88f6f, 1.029916);
}
BOOST_AUTO_TEST_CASE(get_difficulty_for_mid_target)

File diff suppressed because one or more lines are too long

View file

@ -16,7 +16,7 @@
#include <boost/test/unit_test.hpp>
int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out);
int ApplyTxInUndo(unsigned int index, const CTxUndo& txUndo, CCoinsViewCache& view, CClaimTrieCache& trieCache, const COutPoint& out);
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
namespace
@ -407,7 +407,8 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
if (!tx.IsCoinBase()) {
const COutPoint &out = tx.vin[0].prevout;
Coin coin = undo.vprevout[0];
ApplyTxInUndo(std::move(coin), *(stack.back()), out);
CClaimTrieCache trieCache(pclaimTrie);
ApplyTxInUndo(0, undo, *(stack.back()), trieCache, out);
}
// Store as a candidate for reconnection
disconnected_coins.insert(utxod->first);
@ -740,35 +741,35 @@ static void CheckAddCoin(Args&&... args)
CheckAddCoinBase(base_value, std::forward<Args>(args)...);
}
BOOST_AUTO_TEST_CASE(ccoins_add)
{
/* Check AddCoin behavior, requesting a new coin from a cache view,
* writing a modification to the coin, and then checking the resulting
* entry in the cache after the modification. Verify behavior with the
* with the AddCoin potential_overwrite argument set to false, and to true.
*
* Cache Write Result Cache Result potential_overwrite
* Value Value Value Flags Flags
*/
CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH, false);
CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY , true );
CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY|FRESH, false);
CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY , true );
CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, false);
CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , false);
CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , true );
CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false);
CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
CheckAddCoin(VALUE2, VALUE3, FAIL , 0 , NO_ENTRY , false);
CheckAddCoin(VALUE2, VALUE3, VALUE3, 0 , DIRTY , true );
CheckAddCoin(VALUE2, VALUE3, FAIL , FRESH , NO_ENTRY , false);
CheckAddCoin(VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
CheckAddCoin(VALUE2, VALUE3, FAIL , DIRTY , NO_ENTRY , false);
CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY , DIRTY , true );
CheckAddCoin(VALUE2, VALUE3, FAIL , DIRTY|FRESH, NO_ENTRY , false);
CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
}
/* BOOST_AUTO_TEST_CASE(ccoins_add) */
/* { */
/* /\* Check AddCoin behavior, requesting a new coin from a cache view, */
/* * writing a modification to the coin, and then checking the resulting */
/* * entry in the cache after the modification. Verify behavior with the */
/* * with the AddCoin potential_overwrite argument set to false, and to true. */
/* * */
/* * Cache Write Result Cache Result potential_overwrite */
/* * Value Value Value Flags Flags */
/* *\/ */
/* CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH, false); */
/* CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY , true ); */
/* CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY|FRESH, false); */
/* CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY , true ); */
/* CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, false); */
/* CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true ); */
/* CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , false); */
/* CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , true ); */
/* CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false); */
/* CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true ); */
/* CheckAddCoin(VALUE2, VALUE3, FAIL , 0 , NO_ENTRY , false); */
/* CheckAddCoin(VALUE2, VALUE3, VALUE3, 0 , DIRTY , true ); */
/* CheckAddCoin(VALUE2, VALUE3, FAIL , FRESH , NO_ENTRY , false); */
/* CheckAddCoin(VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true ); */
/* CheckAddCoin(VALUE2, VALUE3, FAIL , DIRTY , NO_ENTRY , false); */
/* CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY , DIRTY , true ); */
/* CheckAddCoin(VALUE2, VALUE3, FAIL , DIRTY|FRESH, NO_ENTRY , false); */
/* CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true ); */
/* } */
void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)
{

View file

@ -13,49 +13,67 @@
BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)
static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
static void TestBlockSubsidyReductions(const Consensus::Params& consensusParams)
{
int maxHalvings = 64;
CAmount nInitialSubsidy = 50 * COIN;
int nHeight = 0;
BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight, consensusParams), 400000000*COIN);
CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0
BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);
for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {
int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;
CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
BOOST_CHECK(nSubsidy <= nInitialSubsidy);
BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
nPreviousSubsidy = nSubsidy;
// Verify that block reward is 1 until block 5100
nHeight += 25;
for (; nHeight < 5100; nHeight += 80)
{
BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight, consensusParams), 1*COIN);
}
BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);
nHeight = 5100;
// Verify it increases by 1 coin every 100 blocks
for (int i = 1; nHeight < 55000; nHeight += 100, i++)
{
BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight, consensusParams), i*COIN);
}
int maxReductions = 500;
CAmount nInitialSubsidy = 500 * COIN;
int nReductions;
for (nReductions = 0; nReductions < maxReductions; nReductions++)
{
nHeight = (((nReductions * nReductions + nReductions) >> 1) * consensusParams.nSubsidyLevelInterval) + 55001;
CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
BOOST_CHECK_EQUAL(nSubsidy, nInitialSubsidy - nReductions * COIN);
}
nHeight = (((nReductions * nReductions + nReductions) >> 1) * consensusParams.nSubsidyLevelInterval) + 55001;
BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight, consensusParams), 0);
}
static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
static void TestBlockSubsidyReductions(int nSubsidyLevelInterval)
{
Consensus::Params consensusParams;
consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;
TestBlockSubsidyHalvings(consensusParams);
consensusParams.nSubsidyLevelInterval = nSubsidyLevelInterval;
TestBlockSubsidyReductions(consensusParams);
}
BOOST_AUTO_TEST_CASE(block_subsidy_test)
{
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
TestBlockSubsidyHalvings(chainParams->GetConsensus()); // As in main
TestBlockSubsidyHalvings(150); // As in regtest
TestBlockSubsidyHalvings(1000); // Just another interval
TestBlockSubsidyReductions(chainParams->GetConsensus()); // As in main
TestBlockSubsidyReductions(1); // As in regtest
TestBlockSubsidyReductions(5); // Just another interval
}
BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
const auto& consensusParams = chainParams->GetConsensus();
CAmount nSum = 0;
for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {
CAmount nSubsidy = GetBlockSubsidy(nHeight, chainParams->GetConsensus());
BOOST_CHECK(nSubsidy <= 50 * COIN);
nSum += GetBlockSubsidy(0, consensusParams);
for (int nHeight = 1; nHeight < 5000001; nHeight += 1000) {
CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
BOOST_CHECK(nSubsidy <= 500 * COIN);
nSum += nSubsidy * 1000;
BOOST_CHECK(MoneyRange(nSum));
}
BOOST_CHECK_EQUAL(nSum, CAmount{2099999997690000});
BOOST_CHECK_EQUAL(nSum, 108322100000000000LL);
}
static bool ReturnFalse() { return false; }

View file

@ -335,6 +335,25 @@ BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress)
BOOST_CHECK_EQUAL(result[2].get_int(), 9);
}
BOOST_AUTO_TEST_CASE(rpc_claimtrie_validation)
{
// std::runtime_error: parameter 2 must be hexadecimal string (not 'not_hex')
BOOST_CHECK_THROW(RPCConvertValues("getnameproof", {"test", "not_hex"}), std::runtime_error);
// std::runtime_error: Block not found
BOOST_CHECK_THROW(RPCConvertValues("getnameproof", {"test", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}), std::runtime_error);
// Generate a block to validate the NO_THROW case.
UniValue result = CallRPC("generate 1");
BOOST_CHECK_NO_THROW(result = RPCConvertValues("getnameproof", {"test", result[0].get_str()}));
/* BOOST_CHECK_THROW(CallRPC("getclaimsfortx not_hex"), runtime_error); */
/* BOOST_CHECK_NO_THROW(CallRPC("getclaimsfortx aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); */
/* BOOST_CHECK_THROW(CallRPC("getclaimbyid not_hex"), runtime_error); */
/* // Wrong length. */
/* BOOST_CHECK_THROW(CallRPC("getclaimbyid a"), runtime_error); */
/* BOOST_CHECK_NO_THROW(CallRPC("getclaimbyid aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); */
}
BOOST_AUTO_TEST_CASE(rpc_getblockstats_calculate_percentiles_by_weight)
{
int64_t total_weight = 200;

View file

@ -1285,6 +1285,51 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_CHECK(combined.scriptSig == partial3c);
}
BOOST_AUTO_TEST_CASE(script_claimScript)
{
// Test the claim scripts
// Outline:
// Spend normal tx to make claim
// Spend claim to update claim
// Spend updated claim to abandon name
CBasicKeyStore keystore;
std::vector<CKey> keys;
std::vector<CPubKey> pubkeys;
for (int i = 0; i < 4; i++)
{
CKey key;
key.MakeNewKey(false);
keys.push_back(key);
pubkeys.push_back(key.GetPubKey());
keystore.AddKey(key);
}
CScriptWitness wit;
std::string sName = "testname";
std::string sValue = "testvalue";
std::vector<unsigned char> vchName(sName.begin(), sName.end());
std::vector<unsigned char> vchValue(sValue.begin(), sValue.end());
CMutableTransaction txOrig = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));
CMutableTransaction txClaim0 = BuildSpendingTransaction(CScript(), wit, txOrig);
CScript txClaimOut0 = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP;
txClaimOut0 = txClaimOut0 + GetScriptForDestination(keys[1].GetPubKey().GetID());
txClaim0.vout[0].scriptPubKey = txClaimOut0;
SignSignature(keystore, txOrig, txClaim0, 0, SIGHASH_ALL);
CMutableTransaction txClaim1 = BuildSpendingTransaction(CScript(), wit, txClaim0);
CScript txClaimOut1 = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP;
txClaimOut1 = txClaimOut1 + GetScriptForDestination(keys[2].GetPubKey().GetID());
txClaim1.vout[0].scriptPubKey = txClaimOut1;
SignSignature(keystore, txClaim0, txClaim1, 0, SIGHASH_ALL);
CMutableTransaction txFinal = BuildSpendingTransaction(CScript(), wit, txClaim1);
txFinal.vout[0].scriptPubKey = GetScriptForDestination(keys[3].GetPubKey().GetID());
SignSignature(keystore, txClaim1, txFinal, 0, SIGHASH_ALL);
}
BOOST_AUTO_TEST_CASE(script_standard_push)
{
ScriptError err;

View file

@ -93,6 +93,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
pclaimTrie = new CClaimTrie(true, false, 1);
if (!LoadGenesisBlock(chainparams)) {
throw std::runtime_error("LoadGenesisBlock failed.");
}
@ -122,6 +123,7 @@ TestingSetup::~TestingSetup()
pcoinsTip.reset();
pcoinsdbview.reset();
pblocktree.reset();
delete pclaimTrie;
}
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
@ -175,6 +177,16 @@ TestChain100Setup::~TestChain100Setup()
{
}
RegTestingSetup::RegTestingSetup() : TestingSetup(CBaseChainParams::REGTEST)
{
minRelayTxFee = CFeeRate(0);
minFeePerNameClaimChar = 0;
}
RegTestingSetup::~RegTestingSetup()
{
minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
}
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
return FromTx(MakeTransactionRef(tx));

View file

@ -95,6 +95,11 @@ struct TestChain100Setup : public TestingSetup {
CKey coinbaseKey; // private/public key needed to spend coinbase transactions
};
struct RegTestingSetup: public TestingSetup {
RegTestingSetup();
~RegTestingSetup();
};
class CTxMemPoolEntry;
struct TestMemPoolEntryHelper

View file

@ -7,6 +7,7 @@
#include <chainparams.h>
#include <hash.h>
#include <index/txindex.h>
#include <random.h>
#include <pow.h>
#include <shutdown.h>
@ -22,6 +23,7 @@ static const char DB_COIN = 'C';
static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_BLOCK_INDEX = 'b';
static const char DB_TX_INDEX = 't';
static const char DB_BEST_BLOCK = 'B';
static const char DB_HEAD_BLOCKS = 'H';
@ -234,6 +236,17 @@ bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockF
return WriteBatch(batch, true);
}
bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
return Read(std::make_pair(DB_TX_INDEX, txid), pos);
}
bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
CDBBatch batch(*this);
for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
batch.Write(std::make_pair(DB_TX_INDEX, it->first), it->second);
return WriteBatch(batch);
}
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
}
@ -268,14 +281,19 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
pindexNew->nUndoPos = diskindex.nUndoPos;
pindexNew->nVersion = diskindex.nVersion;
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
pindexNew->hashClaimTrie = diskindex.hashClaimTrie;
pindexNew->nTime = diskindex.nTime;
pindexNew->nBits = diskindex.nBits;
pindexNew->nNonce = diskindex.nNonce;
pindexNew->nStatus = diskindex.nStatus;
pindexNew->nTx = diskindex.nTx;
if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams))
if (!CheckProofOfWork(pindexNew->GetBlockPoWHash(), pindexNew->nBits, consensusParams))
{
LogPrintf("%s: CheckProofOfWorkFailed: %s\n", __func__, pindexNew->ToString());
LogPrintf("%s: CheckProofOfWorkFailed: %s (hash %s, nBits=%x, nTime=%d)\n", __func__, pindexNew->GetBlockPoWHash().GetHex(), pindexNew->GetBlockHash().GetHex(), pindexNew->nBits, pindexNew->nTime);
return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
}
pcursor->Next();
} else {

View file

@ -21,6 +21,8 @@ class CBlockIndex;
class CCoinsViewDBCursor;
class uint256;
struct CDiskTxPos;
//! No need to periodic flush if at least this much space still available.
static constexpr int MAX_BLOCK_COINSDB_USAGE = 10;
//! -dbcache default (MiB)
@ -93,6 +95,8 @@ public:
bool ReadLastBlockFile(int &nFile);
bool WriteReindexing(bool fReindexing);
void ReadReindexing(bool &fReindexing);
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex);

View file

@ -6,6 +6,8 @@
#ifndef BITCOIN_UNDO_H
#define BITCOIN_UNDO_H
#include <unordered_map>
#include <claimtrie.h>
#include <compressor.h>
#include <consensus/consensus.h>
#include <primitives/transaction.h>
@ -21,16 +23,24 @@
class TxInUndoSerializer
{
const Coin* txout;
// whether the outpoint was the last unspent
bool fLastUnspent;
// if the outpoint was the last unspent: its version
unsigned int nVersion;
// If the outpoint was a claim or support, the height at which the claim or support should be inserted into the trie
unsigned int nClaimValidHeight;
// if the outpoint was a claim or support
bool fIsClaim;
public:
template<typename Stream>
void Serialize(Stream &s) const {
::Serialize(s, VARINT(txout->nHeight * 2 + (txout->fCoinBase ? 1u : 0u)));
if (txout->nHeight > 0) {
// Required to maintain compatibility with older undo format.
::Serialize(s, (unsigned char)0);
}
::Serialize(s, VARINT(txout->nHeight * 4 + (txout->fCoinBase ? 2u : 0u) + (fLastUnspent ? 1u : 0u)));
if (fLastUnspent)
::Serialize(s, VARINT(this->nVersion));
::Serialize(s, CTxOutCompressor(REF(txout->out)));
::Serialize(s, VARINT(nClaimValidHeight));
::Serialize(s, fIsClaim);
}
explicit TxInUndoSerializer(const Coin* coin) : txout(coin) {}
@ -39,22 +49,28 @@ public:
class TxInUndoDeserializer
{
Coin* txout;
// whether the outpoint was the last unspent
bool fLastUnspent;
// if the outpoint was the last unspent: its version
unsigned int nVersion;
// If the outpoint was a claim or support, the height at which the claim or support should be inserted into the trie
unsigned int nClaimValidHeight;
// if the outpoint was a claim or support
bool fIsClaim;
public:
template<typename Stream>
void Unserialize(Stream &s) {
unsigned int nCode = 0;
::Unserialize(s, VARINT(nCode));
txout->nHeight = nCode / 2;
txout->fCoinBase = nCode & 1;
if (txout->nHeight > 0) {
// Old versions stored the version number for the last spend of
// a transaction's outputs. Non-final spends were indicated with
// height = 0.
unsigned int nVersionDummy;
::Unserialize(s, VARINT(nVersionDummy));
}
txout->nHeight = nCode / 4;
txout->fCoinBase = nCode & 2;
fLastUnspent = nCode & 1;
if (fLastUnspent)
::Unserialize(s, VARINT(this->nVersion));
::Unserialize(s, CTxOutCompressor(REF(txout->out)));
::Unserialize(s, VARINT(nClaimValidHeight));
::Unserialize(s, fIsClaim);
}
explicit TxInUndoDeserializer(Coin* coin) : txout(coin) {}
@ -66,32 +82,39 @@ static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_IN
/** Undo information for a CTransaction */
class CTxUndo
{
struct claimState
{
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nClaimValidHeight);
READWRITE(fIsClaim);
};
// If the outpoint was a claim or support, the height at which the
// claim or support should be inserted into the trie; indexed by Coin index
unsigned int nClaimValidHeight;
// if the outpoint was a claim or support; indexed by Coin index
bool fIsClaim;
};
using claimStateMap = std::map<unsigned int, claimState>;
public:
// undo information for all txins
std::vector<Coin> vprevout;
claimStateMap claimInfo;
template <typename Stream>
void Serialize(Stream& s) const {
// TODO: avoid reimplementing vector serializer
uint64_t count = vprevout.size();
::Serialize(s, COMPACTSIZE(REF(count)));
for (const auto& prevout : vprevout) {
::Serialize(s, TxInUndoSerializer(&prevout));
}
CTxUndo() {
}
template <typename Stream>
void Unserialize(Stream& s) {
// TODO: avoid reimplementing vector deserializer
uint64_t count = 0;
::Unserialize(s, COMPACTSIZE(count));
if (count > MAX_INPUTS_PER_BLOCK) {
throw std::ios_base::failure("Too many input undo records");
}
vprevout.resize(count);
for (auto& prevout : vprevout) {
::Unserialize(s, TxInUndoDeserializer(&prevout));
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vprevout);
READWRITE(claimInfo);
}
};
@ -100,12 +123,22 @@ class CBlockUndo
{
public:
std::vector<CTxUndo> vtxundo; // for all but the coinbase
insertUndoType insertUndo; // any claims that went from the queue to the trie
claimQueueRowType expireUndo; // any claims that expired
insertUndoType insertSupportUndo; // any supports that went from the support queue to the support map
supportQueueRowType expireSupportUndo; // any supports that expired
std::vector<std::pair<std::string, int> > takeoverHeightUndo; // for any name that was taken over, the previous time that name was taken over
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vtxundo);
READWRITE(insertUndo);
READWRITE(expireUndo);
READWRITE(insertSupportUndo);
READWRITE(expireSupportUndo);
READWRITE(takeoverHeightUndo);
}
};

View file

@ -81,8 +81,8 @@
// Application startup time (used for uptime calculation)
const int64_t nStartupTime = GetTime();
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
const char * const BITCOIN_CONF_FILENAME = "lbrycrd.conf";
const char * const BITCOIN_PID_FILENAME = "lbrycrd.pid";
ArgsManager gArgs;
@ -713,10 +713,10 @@ fs::path GetDefaultDataDir()
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
// Unix: ~/.bitcoin
// Unix: ~/.lbrycrd
#ifdef WIN32
// Windows
return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
return GetSpecialFolderPath(CSIDL_APPDATA) / "lbrycrd";
#else
fs::path pathRet;
char* pszHome = getenv("HOME");
@ -726,10 +726,10 @@ fs::path GetDefaultDataDir()
pathRet = fs::path(pszHome);
#ifdef MAC_OSX
// Mac
return pathRet / "Library/Application Support/Bitcoin";
return pathRet / "Library/Application Support/lbrycrd";
#else
// Unix
return pathRet / ".bitcoin";
return pathRet / ".lbrycrd";
#endif
#endif
}

File diff suppressed because it is too large Load diff

View file

@ -11,12 +11,16 @@
#endif
#include <amount.h>
#include <claimtrie.h>
#include <coins.h>
#include <fs.h>
#include <index/txindex.h>
#include <nameclaim.h>
#include <protocol.h> // For CMessageHeader::MessageStartChars
#include <policy/feerate.h>
#include <script/script_error.h>
#include <sync.h>
#include <txmempool.h>
#include <versionbits.h>
#include <algorithm>
@ -166,6 +170,8 @@ extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */
extern CAmount maxTxFee;
/** Used to calculate minimum fee for claim trie transactions **/
extern CAmount minFeePerNameClaimChar;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
extern int64_t nMaxTipAge;
extern bool fEnableReplacement;
@ -249,6 +255,10 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0, bool blocks_dir = false);
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Translation to a filesystem path */
fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix);
/** Utility method for going back to a previous state **/
bool RollBackTo(const CBlockIndex* targetIndex, CCoinsViewCache& coinsCache, CClaimTrieCache& trieCache);
/** Get a cryptographic proof that a name maps to a value **/
bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CClaimTrieProof& proof);
/** Import blocks from an external file */
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = nullptr);
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
@ -349,6 +359,172 @@ bool TestLockPointValidity(const LockPoints* lp);
*/
bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false);
/************************************************************
* LBRY moved these from validation.cpp, for testcase usage
* BEGIN
************************************************************/
/**
* Global state
*/
namespace {
struct CBlockIndexWorkComparator
{
bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
// First sort by most total work, ...
if (pa->nChainWork > pb->nChainWork) return false;
if (pa->nChainWork < pb->nChainWork) return true;
// ... then by earliest time received, ...
if (pa->nSequenceId < pb->nSequenceId) return false;
if (pa->nSequenceId > pb->nSequenceId) return true;
// Use pointer address as tie breaker (should only happen with blocks
// loaded from disk, as those all have id 0).
if (pa < pb) return false;
if (pa > pb) return true;
// Identical blocks.
return false;
}
};
} // anon namespace
class ConnectTrace;
enum DisconnectResult
{
DISCONNECT_OK, // All good.
DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
DISCONNECT_FAILED // Something else went wrong.
};
/**
* CChainState stores and provides an API to update our local knowledge of the
* current best chain and header tree.
*
* It generally provides access to the current block tree, as well as functions
* to provide new data, which it will appropriately validate and incorporate in
* its state as necessary.
*
* Eventually, the API here is targeted at being exposed externally as a
* consumable libconsensus library, so any functions added must only call
* other class member functions, pure functions in other parts of the consensus
* library, callbacks via the validation interface, or read/write-to-disk
* functions (eventually this will also be via callbacks).
*/
class CChainState {
private:
/**
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
* as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
* missing the data for the block.
*/
std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
/**
* Every received block is assigned a unique and increasing identifier, so we
* know which one to give priority in case of a fork.
*/
CCriticalSection cs_nBlockSequenceId;
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
int32_t nBlockSequenceId = 1;
/** Decreasing counter (used by subsequent preciousblock calls). */
int32_t nBlockReverseSequenceId = -1;
/** chainwork for the last block that preciousblock has been applied to. */
arith_uint256 nLastPreciousChainwork = 0;
/** In order to efficiently track invalidity of headers, we keep the set of
* blocks which we tried to connect and found to be invalid here (ie which
* were set to BLOCK_FAILED_VALID since the last restart). We can then
* walk this set and check if a new header is a descendant of something in
* this set, preventing us from having to walk mapBlockIndex when we try
* to connect a bad block and fail.
*
* While this is more complicated than marking everything which descends
* from an invalid block as invalid at the time we discover it to be
* invalid, doing so would require walking all of mapBlockIndex to find all
* descendants. Since this case should be very rare, keeping track of all
* BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
* well.
*
* Because we already walk mapBlockIndex in height-order at startup, we go
* ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
* instead of putting things in this set.
*/
std::set<CBlockIndex*> m_failed_blocks;
/**
* the ChainState CriticalSection
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
*/
CCriticalSection m_cs_chainstate;
public:
CChain chainActive;
BlockMap mapBlockIndex;
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CBlockIndex *pindexBestInvalid = nullptr;
bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock);
/**
* If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
* that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
*/
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Block (dis)connection on a given view:
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view, CClaimTrieCache& trieCache);
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
CCoinsViewCache& view, CClaimTrieCache& trieCache, const CChainParams& chainparams, bool fJustCheck = false);
// Block disconnection on our pcoinsTip:
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool);
// Manual block validity manipulation:
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
bool RewindBlockIndex(const CChainParams& params);
bool LoadGenesisBlock(const CChainParams& chainparams);
void PruneBlockIndexCandidates();
void UnloadBlockIndex();
private:
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace);
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool);
CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Make various assertions about the state of the block index.
*
* By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
*/
void CheckBlockIndex(const Consensus::Params& consensusParams);
void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state);
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
};
/************************************************************
* LBRY moved these from validation.cpp, for testcase usage
* END
************************************************************/
/**
* Closure representing one script verification
* Note that this stores references to the spending transaction
@ -460,9 +636,13 @@ extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
/** Global variable that points to the active CCoinsView (protected by cs_main) */
extern std::unique_ptr<CCoinsViewCache> pcoinsTip;
/** Global variable that points to the active CClaimTrie (protected by cs_main) */
extern CClaimTrie *pclaimTrie;
/** Global variable that points to the active block tree (protected by cs_main) */
extern std::unique_ptr<CBlockTreeDB> pblocktree;
/**
* Return the spend height, which is one more than the inputs.GetBestBlock().
* While checking, GetBestBlock() refers to the parent block. (protected by cs_main)