diff --git a/.gitignore b/.gitignore index 2f85c6d195f..f875a16f921 100644 --- a/.gitignore +++ b/.gitignore @@ -161,5 +161,5 @@ Makefile.in configure doc/man/Makefile.in src/Makefile.in -src/cc/customcc.so +src/cc/libcc.so src/libcc.so diff --git a/Makefile.am b/Makefile.am index 51d0430aca4..71a0d5f53b3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -344,3 +344,6 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-man clean-local: rm -rf test_bitcoin.coverage/ zcash-gtest.coverage/ total.coverage/ + +clean-all: clean-local + $(MAKE) -C src clean-all diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 7be744aebc0..43a4c88f2ab 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -8,10 +8,10 @@ darwin_CXX=g++-8 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysro darwin_CFLAGS=-pipe darwin_CXXFLAGS=$(darwin_CFLAGS) -darwin_release_CFLAGS=-O1 +darwin_release_CFLAGS=-g -O2 darwin_release_CXXFLAGS=$(darwin_release_CFLAGS) -darwin_debug_CFLAGS=-O1 +darwin_debug_CFLAGS=-g -O0 darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS) darwin_native_toolchain=native_cctools diff --git a/depends/hosts/linux.mk b/depends/hosts/linux.mk index 31748d66226..857fe783079 100644 --- a/depends/hosts/linux.mk +++ b/depends/hosts/linux.mk @@ -1,12 +1,11 @@ linux_CFLAGS=-pipe linux_CXXFLAGS=$(linux_CFLAGS) -linux_release_CFLAGS=-O1 +linux_release_CFLAGS=-g -O2 linux_release_CXXFLAGS=$(linux_release_CFLAGS) -linux_debug_CFLAGS=-O1 +linux_debug_CFLAGS=-g -O0 linux_debug_CXXFLAGS=$(linux_debug_CFLAGS) - linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC ifeq (86,$(findstring 86,$(build_arch))) diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk index b217bfdb547..857850b05b1 100644 --- a/depends/hosts/mingw32.mk +++ b/depends/hosts/mingw32.mk @@ -1,12 +1,11 @@ mingw32_CC=x86_64-w64-mingw32-gcc-posix mingw32_CXX=x86_64-w64-mingw32-g++-posix mingw32_CFLAGS=-pipe -std=c11 -mingw32_CXXFLAGS=$(mingw32_CFLAGS) -std=c++11 +mingw32_CXXFLAGS=-pipe -std=c++11 -mingw32_release_CFLAGS=-O1 -mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS) - -mingw32_debug_CFLAGS=-O1 -mingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS) +mingw32_release_CFLAGS=-g -O2 +mingw32_release_CXXFLAGS=$(mingw32_CXXFLAGS) $(mingw32_release_CFLAGS) +mingw32_debug_CFLAGS=-g -O0 mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC +mingw32_debug_CXXFLAGS=$(mingw32_CXXFLAGS) $(mingw32_debug_CFLAGS) diff --git a/qa/pytest_komodo/chainconfig.json b/qa/pytest_komodo/chainconfig.json index 47f376e425f..7fea510b364 100644 --- a/qa/pytest_komodo/chainconfig.json +++ b/qa/pytest_komodo/chainconfig.json @@ -2,10 +2,10 @@ "TONYCI": { "rpc_user": "test", "rpcpassword": "test", - "rpcallowip": "0.0.0.0/0", + "rpcallowip": "127.0.0.1", "rpcport": 7000, "port": 6000, - "rpcbind": "0.0.0.0", + "rpcbind": "127.0.0.1", "ac_name": "TONYCI", "ac_reward": "100000000000", "ac_supply": "10000000000", diff --git a/qa/pytest_komodo/ci_cleanup.sh b/qa/pytest_komodo/ci_cleanup.sh new file mode 100755 index 00000000000..a15baf38427 --- /dev/null +++ b/qa/pytest_komodo/ci_cleanup.sh @@ -0,0 +1,5 @@ +#!/bin/bash +rm -Rf node_0 +rm -Rf node_1 +rm -Rf __pycache__/ +rm TONYCI_7776 diff --git a/src/Makefile.am b/src/Makefile.am index c2bf7cb55b1..2e36b21fe50 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ -DIST_SUBDIRS = secp256k1 univalue cryptoconditions - +DIST_SUBDIRS = secp256k1 univalue +SUBDIRS = cryptoconditions AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(SAN_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) AM_CPPFLAGS = $(HARDENED_CPPFLAGS) @@ -15,7 +15,7 @@ LIBMEMENV += $(builddir)/leveldb/libmemenv.a $(LIBLEVELDB): $(LIBMEMENV) $(LIBLEVELDB) $(LIBMEMENV): - @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ + $(AM_V_at)$(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" endif @@ -38,11 +38,11 @@ LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBSECP256K1=secp256k1/libsecp256k1.la -LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions_core.la +LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions_core.a LIBSNARK=snark/libsnark.a LIBUNIVALUE=univalue/libunivalue.la +LIBCC=libcc.a LIBZCASH=libzcash.a -LIBCJSON=libcjson.a if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a @@ -53,15 +53,10 @@ endif if BUILD_BITCOIN_LIBS LIBZCASH_CONSENSUS=libzcashconsensus.la endif -if ENABLE_WALLET -LIBBITCOIN_WALLET=libbitcoin_wallet.a -endif - -$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g " LIBSNARK_CXXFLAGS = $(AM_CXXFLAGS) $(PIC_FLAGS) -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -fstack-protector-all LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1 +LIBSNARK_OPTFLAGS = $(CPPFLAGS) -march=x86-64 if HAVE_OPENMP LIBSNARK_CONFIG_FLAGS += MULTICORE=1 endif @@ -69,23 +64,17 @@ if TARGET_DARWIN LIBSNARK_CONFIG_FLAGS += PLATFORM=darwin endif +$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="$(LIBSNARK_OPTFLAGS) " + $(LIBSNARK): $(wildcard snark/src/*) - $(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at)CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="$(LIBSNARK_OPTFLAGS)" libsnark-tests: $(wildcard snark/src/*) - $(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at)CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="$(LIBSNARK_OPTFLAGS)" $(LIBUNIVALUE): $(wildcard univalue/lib/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g " - -$(LIBCRYPTOCONDITIONS): $(wildcard cryptoconditions/src/*) $(wildcard cryptoconditions/include/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g " - -#%.o: %.c -# $(CC) -c -o $@ $< - -#$(LIBCJSON): cJSON.o komodo_cJSON.o komodo_cutils.o -# $(AR) cr $(LIBCJSON) $^ + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="$(LIBSNARK_OPTFLAGS)" # libcjson build LIBCJSON=libcjson.a @@ -114,7 +103,7 @@ if ENABLE_PROTON EXTRA_LIBRARIES += $(LIBBITCOIN_PROTON) endif -lib_LTLIBRARIES = $(LIBZCASH_CONSENSUS) +lib_LTLIBRARIES = $(LIBZCASH_CONSENSUS) $(LIBCC) bin_PROGRAMS = noinst_PROGRAMS = @@ -398,6 +387,11 @@ libbitcoin_wallet_a_SOURCES = \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) +# a shared library for cryptoconditions +libcc_a_SOURCES = cc/cclib.cpp +libcc_a_CXXFLAGS = -DBUILD_CUSTOMCC -I../secp256k1/include -I../depends/$(shell echo `../depends/config.guess`/include) -I./univalue/include -I./cryptoconditions/include -I./cryptoconditions/src -I./cryptoconditions/src/asn -I. -I./cc +libcc_a_LDFLAGS = -version-info 0:0:0 + # crypto primitives library crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES) crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) @@ -463,12 +457,13 @@ libbitcoin_common_a_SOURCES = \ komodo_events.cpp \ komodo_gateway.cpp \ komodo_globals.cpp \ + komodo_hardfork.cpp \ komodo_interest.cpp \ komodo_jumblr.cpp \ komodo_kv.cpp \ komodo_notary.cpp \ komodo_pax.cpp \ - komodo_utils.cpp \ + komodo_utils.cpp \ netbase.cpp \ metrics.cpp \ primitives/block.cpp \ @@ -575,18 +570,9 @@ komodod_LDADD += \ $(PROTON_LIBS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBZCASH_LIBS) \ + $(LIBCC) \ -lcurl -if TARGET_DARWIN -komodod_LDADD += libcc.dylib $(LIBSECP256K1) -endif -if TARGET_WINDOWS -komodod_LDADD += libcc.dll $(LIBSECP256K1) -endif -if TARGET_LINUX -komodod_LDADD += libcc.so $(LIBSECP256K1) -endif - if ENABLE_PROTON komodod_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS) endif @@ -668,7 +654,6 @@ komodo_tx_LDADD = \ $(LIBCRYPTOCONDITIONS) komodo_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) -# # zcash protocol primitives # libzcash_a_SOURCES = \ @@ -688,12 +673,11 @@ libzcash_a_SOURCES = \ zcash/circuit/prfs.tcc \ zcash/circuit/utils.tcc -libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) $(HARDENED_CXXFLAGS) $(HARDENED_LDFLAGS) -pipe $(SAN_LDFLAGS) -O1 -g -Wstack-protector $(SAN_CXXFLAGS) -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES) - -#libzcash_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -#libzcash_a_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -#libzcash_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMONTGOMERY_OUTPUT - +libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 \ + -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) \ + $(HARDENED_CXXFLAGS) $(HARDENED_LDFLAGS) -pipe $(SAN_LDFLAGS) \ + -Wstack-protector $(SAN_CXXFLAGS) -fstack-protector-all -fPIE -fvisibility=hidden \ + -DSTATIC $(BITCOIN_INCLUDES) libzcash_a_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing libzcash_a_LDFLAGS = $(SAN_LDFLAGS) $(HARDENED_LDFLAGS) libzcash_a_CPPFLAGS += -DMONTGOMERY_OUTPUT @@ -742,6 +726,13 @@ clean-local: -$(MAKE) -C univalue clean rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno -rm -f config.h + -$(RM) *.a + -$(RM) crypto/*.a + -$(RM) cryptoconditions/.libs/*.a + +clean-all: clean-local + -$(MAKE) -C snark clean-all + -$(MAKE) -C univalue clean-all .rc.o: @test -f $(WINDRES) @@ -769,6 +760,6 @@ endif if ENABLE_TESTS include Makefile.ktest.include -#include Makefile.test.include -#include Makefile.gtest.include +#include Makefile.test.include # bitcoin tests +#include Makefile.gtest.include # zcash tests endif diff --git a/src/Makefile.gtest.include b/src/Makefile.gtest.include index a0a2971fa2f..9c226fc7f31 100644 --- a/src/Makefile.gtest.include +++ b/src/Makefile.gtest.include @@ -2,39 +2,36 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or https://www.opensource.org/licenses/mit-license.php . -TESTS += komodo-gtest -bin_PROGRAMS += komodo-gtest +TESTS += zcash-gtest +bin_PROGRAMS += zcash-gtest # tool for generating our public parameters -komodo_gtest_SOURCES = \ +zcash_gtest_SOURCES = \ gtest/main.cpp \ gtest/utils.cpp \ gtest/test_checktransaction.cpp \ gtest/json_test_vectors.cpp \ - gtest/json_test_vectors.h \ - # gtest/test_foundersreward.cpp \ - gtest/test_wallet_zkeys.cpp \ + gtest/json_test_vectors.h + # These tests are order-dependent, because they # depend on global state (see #1539) if ENABLE_WALLET zcash_gtest_SOURCES += \ wallet/gtest/test_wallet_zkeys.cpp endif + zcash_gtest_SOURCES += \ gtest/test_tautology.cpp \ gtest/test_deprecation.cpp \ - gtest/test_equihash.cpp \ gtest/test_httprpc.cpp \ gtest/test_joinsplit.cpp \ gtest/test_keys.cpp \ gtest/test_keystore.cpp \ gtest/test_noteencryption.cpp \ - gtest/test_mempool.cpp \ gtest/test_merkletree.cpp \ gtest/test_metrics.cpp \ gtest/test_miner.cpp \ gtest/test_pow.cpp \ - gtest/test_random.cpp \ gtest/test_rpc.cpp \ gtest/test_sapling_note.cpp \ gtest/test_transaction.cpp \ @@ -42,7 +39,6 @@ zcash_gtest_SOURCES += \ gtest/test_upgrades.cpp \ gtest/test_validation.cpp \ gtest/test_circuit.cpp \ - gtest/test_txid.cpp \ gtest/test_libzcash_utils.cpp \ gtest/test_proofs.cpp \ gtest/test_paymentdisclosure.cpp \ @@ -54,22 +50,24 @@ zcash_gtest_SOURCES += \ wallet/gtest/test_wallet.cpp endif -komodo_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES) -komodo_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +zcash_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES) +zcash_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) komodo_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) + if ENABLE_ZMQ zcash_gtest_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif + if ENABLE_WALLET -komodo_gtest_LDADD += $(LIBBITCOIN_WALLET) +zcash_gtest_LDADD += $(LIBBITCOIN_WALLET) endif -komodo_gtest_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS) +zcash_gtest_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS) if ENABLE_PROTON -komodo_gtest_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS) +zcash_gtest_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS) endif diff --git a/src/Makefile.ktest.include b/src/Makefile.ktest.include index 2525ad3d01f..55eba4ef49a 100644 --- a/src/Makefile.ktest.include +++ b/src/Makefile.ktest.include @@ -18,7 +18,17 @@ bin_PROGRAMS += komodo-test test-komodo/test_netbase_tests.cpp \ test-komodo/test_events.cpp \ test-komodo/test_hex.cpp \ - test-komodo/test_haraka_removal.cpp + test-komodo/test_alerts.cpp \ + test-komodo/test_equihash.cpp \ + test-komodo/test_random.cpp \ + test-komodo/test_block.cpp \ + test-komodo/test_mempool.cpp \ + test-komodo/test_notary.cpp \ + test-komodo/test_pow.cpp \ + test-komodo/test_txid.cpp \ + test-komodo/test_coins.cpp \ + test-komodo/test_haraka_removal.cpp \ + main.cpp komodo_test_CPPFLAGS = $(komodod_CPPFLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 82b6f0d506a..a4e106c77d0 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -62,7 +62,6 @@ BITCOIN_TESTS =\ test/bloom_tests.cpp \ test/checkblock_tests.cpp \ test/Checkpoints_tests.cpp \ - test/coins_tests.cpp \ test/compress_tests.cpp \ test/convertbits_tests.cpp \ test/crypto_tests.cpp \ diff --git a/src/addrman.h b/src/addrman.h index 28e07a82b13..93c3692a5da 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -258,6 +258,33 @@ friend class CAddrManTest; //! Wraps GetRandInt to allow tests to override RandomInt and make it deterministic. virtual int RandomInt(int nMax); + /*** + * @brief Clears the internal collections and fills them again + * @note the mutex should be held before this method is called + * @note the constructor calls this directly with no lock + */ + void Clear_() + { + std::vector().swap(vRandom); + nKey = GetRandHash(); + for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { + for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) { + vvNew[bucket][entry] = -1; + } + } + for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) { + for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) { + vvTried[bucket][entry] = -1; + } + } + + nIdCount = 0; + nTried = 0; + nNew = 0; + mapInfo.clear(); + mapAddr.clear(); + } + #ifdef DEBUG_ADDRMAN //! Perform consistency check. Returns an error code or zero. int Check_(); @@ -502,29 +529,12 @@ friend class CAddrManTest; void Clear() { LOCK(cs); - std::vector().swap(vRandom); - nKey = GetRandHash(); - for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { - for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) { - vvNew[bucket][entry] = -1; - } - } - for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) { - for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) { - vvTried[bucket][entry] = -1; - } - } - - nIdCount = 0; - nTried = 0; - nNew = 0; - mapInfo.clear(); - mapAddr.clear(); + Clear_(); } CAddrMan() { - Clear(); + Clear_(); } ~CAddrMan() diff --git a/src/alert.cpp b/src/alert.cpp index e76f6a41108..4991e36058e 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -261,8 +261,7 @@ bool CAlert::ProcessAlert(const std::vector& alertKey, bool fThre return true; } -void -CAlert::Notify(const std::string& strMessage, bool fThread) +void CAlert::Notify(const std::string& strMessage, bool fThread) { std::string strCmd = GetArg("-alertnotify", ""); if (strCmd.empty()) return; diff --git a/src/alertkeys.h b/src/alertkeys.h index 106576add2a..82bdd680dfc 100644 --- a/src/alertkeys.h +++ b/src/alertkeys.h @@ -1,3 +1,4 @@ +#pragma once /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -13,13 +14,8 @@ * * ******************************************************************************/ -#ifndef BITCOIN_ALERTKEYS_H -#define BITCOIN_ALERTKEYS_H - // REMINDER: DO NOT COMMIT YOUR PRIVATE KEYS TO THE GIT REPOSITORY! const char* pszPrivKey = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; const char* pszTestNetPrivKey = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; -#endif - diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 5f689f7a5f1..35a5e72163e 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -266,10 +266,13 @@ static uint256 ignoretxid; static int32_t ignorevin; /// \endcond -/// myGetTransaction is non-locking version of GetTransaction -/// @param hash hash of transaction to get (txid) -/// @param[out] txOut returned transaction object -/// @param[out] hashBlock hash of the block where the tx resides +/***** + * @brief get a transaction by its hash (without locks) + * @param[in] hash what to look for + * @param[out] txOut the found transaction + * @param[out] hashBlock the hash of the block (all zeros if still in mempool) + * @returns true if found + */ bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock); /// NSPV_myGetTransaction is called in NSPV mode @@ -290,7 +293,14 @@ int64_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag,int32_t lockfla /// \cond INTERNAL bool myIsutxo_spentinmempool(uint256 &spenttxid,int32_t &spentvini,uint256 txid,int32_t vout); -bool myAddtomempool(CTransaction &tx, CValidationState *pstate = NULL, bool fSkipExpiry = false); +/**** + * @brief add a transaction to the mempool + * @param[in] tx the transaction + * @param pstate where to store any error (can be nullptr) + * @param fSkipExpiry + * @returns true on success + */ +bool myAddtomempool(const CTransaction &tx, CValidationState *pstate = nullptr, bool fSkipExpiry = false); bool mytxid_inmempool(uint256 txid); int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout); int32_t myGet_mempool_txs(std::vector &txs,uint8_t evalcode,uint8_t funcid); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index e82f205ff79..99b1a483eb8 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -160,7 +160,7 @@ bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_ int64_t interest; uint64_t valuein; CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); view.SetBackend(viewMemPool); - valuein = view.GetValueIn(height,&interest,tx,blocktime); + valuein = view.GetValueIn(height,interest,tx); actualtxfee = valuein-tx.GetValueOut(); if ( actualtxfee > txfee ) { diff --git a/src/cc/Makefile_custom b/src/cc/Makefile_custom index 79219ec96c1..364f9f4a121 100755 --- a/src/cc/Makefile_custom +++ b/src/cc/Makefile_custom @@ -10,9 +10,9 @@ RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program $(info $(OS)) OS := $(shell uname -s) $(info $(OS)) -TARGET = customcc.so -TARGET_DARWIN = customcc.dylib -TARGET_WIN = customcc.dll +TARGET = ../libcc.so +TARGET_DARWIN = ../libcc.dylib +TARGET_WIN = ../libcc.dll SOURCES = cclib.cpp #HEADERS = $(shell echo ../cryptoconditions/include/*.h) -I/usr/local/Cellar/gcc\@8/8.3.0/include/c++/8.3.0/ @@ -22,16 +22,13 @@ $(TARGET): $(SOURCES) $(info Building cclib to src/) ifeq ($(OS),Darwin) $(CC_DARWIN) $(CFLAGS_DARWIN) $(DEBUGFLAGS) -o $(TARGET_DARWIN) -c $(SOURCES) - cp $(TARGET_DARWIN) ../libcc.dylib else ifeq ($(HOST),x86_64-w64-mingw32) $(info WINDOWS) $(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) -c $(SOURCES) - cp $(TARGET_WIN) ../libcc.dll #else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host else $(info LINUX) $(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) -c $(SOURCES) - cp $(TARGET) ../libcc.so endif clean: diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7d54ffc4269..993a97034d9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -134,9 +134,6 @@ class CMainParams : public CChainParams { consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; - // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000281b32ff3198a1"); - /** * 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 @@ -291,9 +288,6 @@ class CTestNetParams : public CChainParams { consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 280000; - // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000001d0c4d9cd"); - pchMessageStart[0] = 0x5A; pchMessageStart[1] = 0x1F; pchMessageStart[2] = 0x7E; @@ -396,9 +390,8 @@ class CRegTestParams : public CChainParams { consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170006; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; - - // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00"); + originalCoinbaseMaturity = 1; + coinbaseMaturity = 1; pchMessageStart[0] = 0xaa; pchMessageStart[1] = 0x8e; @@ -416,8 +409,6 @@ class CRegTestParams : public CChainParams { 1296688602, uint256S("0x0000000000000000000000000000000000000000000000000000000000000009"), ParseHex("01936b7db1eb4ac39f151b8704642d0a8bda13ec547d54cd5e43ba142fc6d8877cab07b3"), - - KOMODO_MINDIFF_NBITS, 4, 0); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x029f11d80ef9765602235e1bc9727e3eb6ba20839319f761fee920d63401e327")); diff --git a/src/chainparams.h b/src/chainparams.h index daa16af8c40..db94db5a75b 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -122,6 +122,9 @@ class CChainParams void SetNValue(uint64_t n) { nEquihashN = n; } void SetKValue(uint64_t k) { nEquihashK = k; } void SetMiningRequiresPeers(bool flag) { fMiningRequiresPeers = flag; } + uint32_t CoinbaseMaturity() const { return coinbaseMaturity; } + void SetCoinbaseMaturity(uint32_t in) const { coinbaseMaturity = in; } + void ResetCoinbaseMaturity() const { coinbaseMaturity = originalCoinbaseMaturity; } //void setnonce(uint32_t nonce) { memcpy(&genesis.nNonce,&nonce,sizeof(nonce)); } //void settimestamp(uint32_t timestamp) { genesis.nTime = timestamp; } @@ -156,6 +159,8 @@ class CChainParams bool fTestnetToBeDeprecatedFieldRPC = false; CCheckpointData checkpointData; std::vector vFoundersRewardAddress; + mutable uint32_t coinbaseMaturity = 100; + uint32_t originalCoinbaseMaturity = 100; }; /** diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index 94e3a42380d..dae6ff19d17 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -38,6 +38,10 @@ class CBaseChainParams MAX_NETWORK_TYPES }; + /*** + * @brief returns the subdirectory for the network + * @return the data subdirectory ( nothing, or "testnet3" or "regtest" ) + */ const std::string& DataDir() const { return strDataDir; } int RPCPort() const { return nRPCPort; } diff --git a/src/coins.cpp b/src/coins.cpp index eac89c030be..d4be328e4e1 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -581,11 +581,19 @@ const CScript &CCoinsViewCache::GetSpendFor(const CTxIn& input) const return GetSpendFor(coins, input); } -CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t tiptime) const +/** + * @brief get amount of bitcoins coming in to a transaction + * @note lightweight clients may not know anything besides the hash of previous transactions, + * so may not be able to calculate this. + * @param[in] nHeight the chain height + * @param[out] interestp the interest found + * @param[in] tx transaction for which we are checking input total + * @returns Sum of value of all inputs (scriptSigs), (positive valueBalance or zero) and JoinSplit vpub_new + */ +CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t &interestp,const CTransaction& tx) const { CAmount value,nResult = 0; - if ( interestp != 0 ) - *interestp = 0; + interestp = 0; if ( tx.IsCoinImport() ) return GetCoinImportValue(tx); if ( tx.IsCoinBase() != 0 ) @@ -604,12 +612,13 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr { if ( value >= 10*COIN ) { - int64_t interest; int32_t txheight; uint32_t locktime; - interest = komodo_accrued_interest(&txheight,&locktime,tx.vin[i].prevout.hash,tx.vin[i].prevout.n,0,value,(int32_t)nHeight); - //printf("nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime); - //fprintf(stderr,"nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime); + int64_t interest; + int32_t txheight; + uint32_t locktime; + interest = komodo_accrued_interest(&txheight,&locktime,tx.vin[i].prevout.hash, + tx.vin[i].prevout.n,0,value,nHeight); nResult += interest; - (*interestp) += interest; + interestp += interest; } } #endif diff --git a/src/coins.h b/src/coins.h index 0aace435f5c..6d1b22806ca 100644 --- a/src/coins.h +++ b/src/coins.h @@ -555,14 +555,15 @@ class CCoinsViewCache : public CCoinsViewBacked size_t DynamicMemoryUsage() const; /** - * Amount of bitcoins coming in to a transaction - * Note that lightweight clients may not know anything besides the hash of previous transactions, + * @brief get amount of bitcoins coming in to a transaction + * @note lightweight clients may not know anything besides the hash of previous transactions, * so may not be able to calculate this. - * - * @param[in] tx transaction for which we are checking input total - * @return Sum of value of all inputs (scriptSigs), (positive valueBalance or zero) and JoinSplit vpub_new + * @param[in] nHeight the chain height + * @param[out] interestp the interest found + * @param[in] tx transaction for which we are checking input total + * @returns Sum of value of all inputs (scriptSigs), (positive valueBalance or zero) and JoinSplit vpub_new */ - CAmount GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t prevblocktime) const; + CAmount GetValueIn(int32_t nHeight,int64_t &interestp,const CTransaction& tx) const; //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view bool HaveInputs(const CTransaction& tx) const; diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index eba39b64422..32b340325ae 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -40,8 +40,6 @@ extern unsigned int MAX_BLOCK_SIGOPS; /** The maximum size of a transaction (network rule) */ static const unsigned int MAX_TX_SIZE_BEFORE_SAPLING = 100000; static const unsigned int MAX_TX_SIZE_AFTER_SAPLING = (2 * MAX_TX_SIZE_BEFORE_SAPLING); //MAX_BLOCK_SIZE; -/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ -extern int COINBASE_MATURITY; /** The minimum value which is invalid for expiry height, used by CTransaction and CMutableTransaction */ static constexpr uint32_t TX_EXPIRY_HEIGHT_THRESHOLD = 500000000; diff --git a/src/consensus/params.h b/src/consensus/params.h index ba122098fba..63b1ca10bbd 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -109,16 +109,16 @@ struct Params { NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES]; /** Proof of work parameters */ - uint256 powLimit; - uint256 powAlternate; + uint256 powLimit; // minimum dificulty limit if EQUIHASH used + uint256 powAlternate; // minimum dificulty limit if EQUIHASH not used boost::optional nPowAllowMinDifficultyBlocksAfterHeight; boost::optional nHF22Height; uint32_t nHF22NotariesPriorityRotateDelta; - int64_t nPowAveragingWindow; - int64_t nPowMaxAdjustDown; - int64_t nPowMaxAdjustUp; - int64_t nPowTargetSpacing; - int64_t nLwmaAjustedWeight; + int64_t nPowAveragingWindow; // lookback window to determine block production speed averages + int64_t nPowMaxAdjustDown; // max percentage difficulty level should be lowered + int64_t nPowMaxAdjustUp; // max percentage difficulty level should be raised + int64_t nPowTargetSpacing; // the target block production speed (in seconds) + int64_t nLwmaAjustedWeight; // k value for work calculation (for non-staked, non-equihash chains) /* Proof of stake parameters */ uint256 posLimit; @@ -129,13 +129,22 @@ struct Params { /* applied to all block times */ int64_t nMaxFutureBlockTime; + /***** + * @returns How long the entire lookback window should take given target values + */ int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; } + /**** + * @returns the minimum time the lookback window should take before difficulty should be raised + */ int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; } + /***** + * @returns the maximum time the lookback window should take before the difficulty should be lowered + */ int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; } void SetSaplingHeight(int32_t height) { vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = height; } void SetOverwinterHeight(int32_t height) { vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = height; } - uint256 nMinimumChainWork; }; + } // namespace Consensus #endif // BITCOIN_CONSENSUS_PARAMS_H diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am index 787b11ac6f1..eab77eeff0f 100644 --- a/src/cryptoconditions/Makefile.am +++ b/src/cryptoconditions/Makefile.am @@ -1,25 +1,16 @@ -lib_LTLIBRARIES=libcryptoconditions.la -noinst_LTLIBRARIES=$(CRYPTOCONDITIONS_CORE) +noinst_LIBRARIES=libcryptoconditions_core.a SUBDIRS = src/include/secp256k1 include_HEADERS = include/cryptoconditions.h # Have a separate build target for cryptoconditions that does not contain secp256k1 -libcryptoconditions_la_SOURCES = include/cryptoconditions.h -libcryptoconditions_la_LIBADD = $(CRYPTOCONDITIONS_CORE) $(LIBSECP256K1) - -AM_CFLAGS = -I$(top_srcdir)/src/asn -I$(top_srcdir)/include -I$(top_srcdir)/src/include \ - -Wall -Wno-pointer-sign -Wno-discarded-qualifiers - LIBSECP256K1=src/include/secp256k1/libsecp256k1.la $(LIBSECP256K1): $(wildcard src/secp256k1/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) -march:x86-64 -g -CRYPTOCONDITIONS_CORE=libcryptoconditions_core.la - -libcryptoconditions_core_la_SOURCES = \ +libcryptoconditions_core_a_SOURCES = \ src/cryptoconditions.c \ src/utils.c \ src/include/cJSON.c \ @@ -74,6 +65,7 @@ libcryptoconditions_core_la_SOURCES = \ src/asn/per_decoder.c \ src/asn/per_encoder.c \ src/asn/per_opentype.c +libcryptoconditions_core_a_CPPFLAGS=-I. -I./src/include -I./src/asn test: bash -c '[ -d .env ] || virtualenv .env -p python3' diff --git a/src/gtest/test_block.cpp b/src/gtest/test_block.cpp deleted file mode 100644 index a0cdc11622b..00000000000 --- a/src/gtest/test_block.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include - -#include "primitives/block.h" - - -TEST(block_tests, header_size_is_expected) { - // Dummy header with an empty Equihash solution. - CBlockHeader header; - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << header; - - ASSERT_EQ(ss.size(), CBlockHeader::HEADER_SIZE); -} diff --git a/src/komodo.cpp b/src/komodo.cpp index 319d78ed162..d396ed67790 100644 --- a/src/komodo.cpp +++ b/src/komodo.cpp @@ -57,7 +57,7 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char throw komodo::parse_error("Unable to read height from file"); if ( func == 'P' ) { - std::shared_ptr pk = std::make_shared(fp, ht); + komodo::event_pubkeys pk(fp, ht); if ( (KOMODO_EXTERNAL_NOTARIES && matched ) || (strcmp(symbol,"KMD") == 0 && !KOMODO_EXTERNAL_NOTARIES) ) { komodo_eventadd_pubkeys(sp, symbol, ht, pk); @@ -65,23 +65,23 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char } else if ( func == 'N' || func == 'M' ) { - std::shared_ptr evt = std::make_shared(fp, ht, dest, func == 'M'); + komodo::event_notarized evt(fp, ht, dest, func == 'M'); komodo_eventadd_notarized(sp, symbol, ht, evt); } else if ( func == 'U' ) // deprecated { - std::shared_ptr evt = std::make_shared(fp, ht); + komodo::event_u evt(fp, ht); } else if ( func == 'K' || func == 'T') { - std::shared_ptr evt = std::make_shared(fp, ht, func == 'T'); + komodo::event_kmdheight evt(fp, ht, func == 'T'); komodo_eventadd_kmdheight(sp, symbol, ht, evt); } else if ( func == 'R' ) { - std::shared_ptr evt = std::make_shared(fp, ht); + komodo::event_opreturn evt(fp, ht); // check for oversized opret - if ( evt->opret.size() < 16384*4 ) + if ( evt.opret.size() < 16384*4 ) komodo_eventadd_opreturn(sp, symbol, ht, evt); } else if ( func == 'D' ) @@ -90,7 +90,7 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char } else if ( func == 'V' ) { - std::shared_ptr evt = std::make_shared(fp, ht); + komodo::event_pricefeed evt(fp, ht); komodo_eventadd_pricefeed(sp, symbol, ht, evt); } } // retrieved the func @@ -125,7 +125,7 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long throw komodo::parse_error("Unable to parse height from file data"); if ( func == 'P' ) { - std::shared_ptr pk = std::make_shared(filedata, fpos, datalen, ht); + komodo::event_pubkeys pk(filedata, fpos, datalen, ht); if ( (KOMODO_EXTERNAL_NOTARIES && matched ) || (strcmp(symbol,"KMD") == 0 && !KOMODO_EXTERNAL_NOTARIES) ) { komodo_eventadd_pubkeys(sp, symbol, ht, pk); @@ -133,25 +133,21 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long } else if ( func == 'N' || func == 'M' ) { - std::shared_ptr ntz = - std::make_shared(filedata, fpos, datalen, ht, dest, func == 'M'); + komodo::event_notarized ntz(filedata, fpos, datalen, ht, dest, func == 'M'); komodo_eventadd_notarized(sp, symbol, ht, ntz); } else if ( func == 'U' ) // deprecated { - std::shared_ptr u = - std::make_shared(filedata, fpos, datalen, ht); + komodo::event_u u(filedata, fpos, datalen, ht); } else if ( func == 'K' || func == 'T' ) { - std::shared_ptr kmd_ht = - std::make_shared(filedata, fpos, datalen, ht, func == 'T'); + komodo::event_kmdheight kmd_ht(filedata, fpos, datalen, ht, func == 'T'); komodo_eventadd_kmdheight(sp, symbol, ht, kmd_ht); } else if ( func == 'R' ) { - std::shared_ptr opret = - std::make_shared(filedata, fpos, datalen, ht); + komodo::event_opreturn opret(filedata, fpos, datalen, ht); komodo_eventadd_opreturn(sp, symbol, ht, opret); } else if ( func == 'D' ) @@ -160,8 +156,7 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long } else if ( func == 'V' ) { - std::shared_ptr pf = - std::make_shared(filedata, fpos, datalen, ht); + komodo::event_pricefeed pf(filedata, fpos, datalen, ht); komodo_eventadd_pricefeed(sp, symbol, ht, pf); } *fposp = fpos; @@ -181,7 +176,8 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long * @param fp the file * @returns the number of bytes written */ -size_t write_event(std::shared_ptr evt, FILE *fp) +template +size_t write_event(T& evt, FILE *fp) { std::stringstream ss; ss << evt; @@ -238,38 +234,38 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar { if ( KMDheight != 0 ) { - std::shared_ptr kmd_ht = std::make_shared(height); - kmd_ht->kheight = KMDheight; - kmd_ht->timestamp = KMDtimestamp; + komodo::event_kmdheight kmd_ht(height); + kmd_ht.kheight = KMDheight; + kmd_ht.timestamp = KMDtimestamp; write_event(kmd_ht, fp); komodo_eventadd_kmdheight(sp,symbol,height,kmd_ht); } else if ( opretbuf != 0 && opretlen > 0 ) { - std::shared_ptr evt = std::make_shared(height); - evt->txid = txhash; - evt->vout = vout; - evt->value = opretvalue; + komodo::event_opreturn evt(height); + evt.txid = txhash; + evt.vout = vout; + evt.value = opretvalue; for(uint16_t i = 0; i < opretlen; ++i) - evt->opret.push_back(opretbuf[i]); + evt.opret.push_back(opretbuf[i]); write_event(evt, fp); komodo_eventadd_opreturn(sp,symbol,height,evt); } else if ( notarypubs != 0 && numnotaries > 0 ) { - std::shared_ptr pk = std::make_shared(height); - pk->num = numnotaries; - memcpy(pk->pubkeys, notarypubs, 33 * 64); + komodo::event_pubkeys pk(height); + pk.num = numnotaries; + memcpy(pk.pubkeys, notarypubs, 33 * 64); write_event(pk, fp); komodo_eventadd_pubkeys(sp,symbol,height,pk); } else if ( voutmask != 0 && numvouts > 0 ) { - std::shared_ptr evt = std::make_shared(height); - evt->n = numvouts; - evt->nid = notaryid; - memcpy(evt->mask, &voutmask, sizeof(voutmask)); - memcpy(evt->hash, &txhash, sizeof(txhash)); + komodo::event_u evt(height); + evt.n = numvouts; + evt.nid = notaryid; + memcpy(evt.mask, &voutmask, sizeof(voutmask)); + memcpy(evt.hash, &txhash, sizeof(txhash)); write_event(evt, fp); } else if ( pvals != 0 && numpvals > 0 ) @@ -280,10 +276,10 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar nonz++; if ( nonz >= 32 ) { - std::shared_ptr evt = std::make_shared(height); - evt->num = numpvals; - for( uint8_t i = 0; i < evt->num; ++i) - evt->prices[i] = pvals[i]; + komodo::event_pricefeed evt(height); + evt.num = numpvals; + for( uint8_t i = 0; i < evt.num; ++i) + evt.prices[i] = pvals[i]; write_event(evt, fp); komodo_eventadd_pricefeed(sp,symbol,height,evt); } @@ -292,12 +288,12 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar { if ( sp != nullptr ) { - std::shared_ptr evt = std::make_shared(height, dest); - evt->blockhash = sp->LastNotarizedHash(); - evt->desttxid = sp->LastNotarizedDestTxId(); - evt->notarizedheight = sp->LastNotarizedHeight(); - evt->MoM = sp->LastNotarizedMoM(); - evt->MoMdepth = sp->LastNotarizedMoMDepth(); + komodo::event_notarized evt(height, dest); + evt.blockhash = sp->LastNotarizedHash(); + evt.desttxid = sp->LastNotarizedDestTxId(); + evt.notarizedheight = sp->LastNotarizedHeight(); + evt.MoM = sp->LastNotarizedMoM(); + evt.MoMdepth = sp->LastNotarizedMoMDepth(); write_event(evt, fp); komodo_eventadd_notarized(sp,symbol,height,evt); } @@ -601,9 +597,16 @@ int32_t komodo_notarycmp(uint8_t *scriptPubKey,int32_t scriptlen,uint8_t pubkeys /* read blackjok3rtt comments in main.cpp */ +/* + JMJ: Moved hwmheight out of komodo_connectblock to allow testing. + Adjusting this should only be done by komodo_connectblock or a unit test +*/ +static int32_t hwmheight; + +void adjust_hwmheight(int32_t newHeight) { hwmheight = newHeight; } + int32_t komodo_connectblock(bool fJustCheck, CBlockIndex *pindex,CBlock& block) { - static int32_t hwmheight; int32_t staked_era; static int32_t lastStakedEra; std::vector notarisations; uint64_t signedmask,voutmask; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; diff --git a/src/komodo_bitcoind.cpp b/src/komodo_bitcoind.cpp index 43f06c2200d..e0b86defa8b 100644 --- a/src/komodo_bitcoind.cpp +++ b/src/komodo_bitcoind.cpp @@ -500,7 +500,7 @@ int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t { if ( (json= cJSON_Parse(jsonstr)) != 0 ) { - if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) != 0 ) + if ( (txjson= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,txjson,(char *)"vout")) != nullptr ) { vout = jitem(vouts,n-1); if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) @@ -705,18 +705,6 @@ int32_t komodo_isPoS(CBlock *pblock, int32_t height,CTxDestination *addressout) return(0); } -void komodo_disconnect(CBlockIndex *pindex,CBlock& block) -{ - char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; - //fprintf(stderr,"disconnect ht.%d\n",pindex->nHeight); - komodo_init(pindex->nHeight); - if ( (sp= komodo_stateptr(symbol,dest)) != 0 ) - { - //sp->rewinding = pindex->nHeight; - //fprintf(stderr,"-%d ",pindex->nHeight); - } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->nHeight,ASSETCHAINS_SYMBOL); -} - int32_t komodo_is_notarytx(const CTransaction& tx) { uint8_t *ptr; static uint8_t crypto777[33]; diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 29174c2b92c..8928a52eb33 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -129,8 +129,6 @@ uint256 komodo_calcmerkleroot(CBlock *pblock, uint256 prevBlockHash, int32_t nHe int32_t komodo_isPoS(CBlock *pblock, int32_t height,CTxDestination *addressout); -void komodo_disconnect(CBlockIndex *pindex,CBlock& block); - int32_t komodo_is_notarytx(const CTransaction& tx); int32_t komodo_block2height(CBlock *block); diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 451c1a38af4..3f34cbb20c3 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -19,6 +19,8 @@ #include "chain.h" #include "komodo_nk.h" +#define NUM_KMD_NOTARIES 64 + #define KOMODO_EARLYTXID_HEIGHT 100 //#define ADAPTIVEPOW_CHANGETO_DEFAULTON 1572480000 #define ASSETCHAINS_MINHEIGHT 128 @@ -35,7 +37,6 @@ #define ASSETCHAINS_STAKED_BLOCK_FUTURE_MAX 57 #define ASSETCHAINS_STAKED_BLOCK_FUTURE_HALF 27 #define ASSETCHAINS_STAKED_MIN_POW_DIFF 536900000 // 537000000 537300000 -#define _COINBASE_MATURITY 100 #define _ASSETCHAINS_TIMELOCKOFF 0xffffffffffffffff // KMD Notary Seasons @@ -46,7 +47,6 @@ // 7113400 = 5x current KMD blockheight. // to add 4th season, change NUM_KMD_SEASONS to 4, and add timestamp and height of activation to these arrays. - #define SETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] |= (1 << ((bitoffset) & 7))) #define GETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] & (1 << ((bitoffset) & 7))) #define CLEARBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] &= ~(1 << ((bitoffset) & 7))) @@ -85,6 +85,7 @@ extern std::vector ASSETCHAINS_PRICES,ASSETCHAINS_STOCKS; extern uint256 KOMODO_EARLYTXID; +extern bool IS_KOMODO_TESTNODE; extern bool IS_KOMODO_DEALERNODE; extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE; extern uint32_t ASSETCHAINS_CC; diff --git a/src/komodo_events.cpp b/src/komodo_events.cpp index e9c4b68aff1..97175643d7a 100644 --- a/src/komodo_events.cpp +++ b/src/komodo_events.cpp @@ -26,24 +26,24 @@ * @param height * @param ntz the event */ -void komodo_eventadd_notarized( komodo_state *sp, char *symbol, int32_t height, std::shared_ptr ntz) +void komodo_eventadd_notarized( komodo_state *sp, char *symbol, int32_t height, komodo::event_notarized& ntz) { char *coin = (ASSETCHAINS_SYMBOL[0] == 0) ? (char *)"KMD" : ASSETCHAINS_SYMBOL; if ( IS_KOMODO_NOTARY - && komodo_verifynotarization(symbol,ntz->dest,height,ntz->notarizedheight,ntz->blockhash, ntz->desttxid) < 0 ) + && komodo_verifynotarization(symbol,ntz.dest,height,ntz.notarizedheight,ntz.blockhash, ntz.desttxid) < 0 ) { static uint32_t counter; if ( counter++ < 100 ) printf("[%s] error validating notarization ht.%d notarized_height.%d, if on a pruned %s node this can be ignored\n", - ASSETCHAINS_SYMBOL,height,ntz->notarizedheight, ntz->dest); + ASSETCHAINS_SYMBOL,height,ntz.notarizedheight, ntz.dest); } else if ( strcmp(symbol,coin) == 0 ) { if ( sp != nullptr ) { sp->add_event(symbol, height, ntz); - komodo_notarized_update(sp,height, ntz->notarizedheight, ntz->blockhash, ntz->desttxid, ntz->MoM, ntz->MoMdepth); + komodo_notarized_update(sp,height, ntz.notarizedheight, ntz.blockhash, ntz.desttxid, ntz.MoM, ntz.MoMdepth); } } } @@ -55,12 +55,12 @@ void komodo_eventadd_notarized( komodo_state *sp, char *symbol, int32_t height, * @param height * @param pk the event */ -void komodo_eventadd_pubkeys(komodo_state *sp, char *symbol, int32_t height, std::shared_ptr pk) +void komodo_eventadd_pubkeys(komodo_state *sp, char *symbol, int32_t height, komodo::event_pubkeys& pk) { if (sp != nullptr) { sp->add_event(symbol, height, pk); - komodo_notarysinit(height, pk->pubkeys, pk->num); + komodo_notarysinit(height, pk.pubkeys, pk.num); } } @@ -71,12 +71,12 @@ void komodo_eventadd_pubkeys(komodo_state *sp, char *symbol, int32_t height, std * @param height * @param pf the event */ -void komodo_eventadd_pricefeed( komodo_state *sp, char *symbol, int32_t height, std::shared_ptr pf) +void komodo_eventadd_pricefeed( komodo_state *sp, char *symbol, int32_t height, komodo::event_pricefeed& pf) { if (sp != nullptr) { sp->add_event(symbol, height, pf); - komodo_pvals(height,pf->prices, pf->num); + komodo_pvals(height,pf.prices, pf.num); } } @@ -87,12 +87,12 @@ void komodo_eventadd_pricefeed( komodo_state *sp, char *symbol, int32_t height, * @param height * @param opret the event */ -void komodo_eventadd_opreturn( komodo_state *sp, char *symbol, int32_t height, std::shared_ptr opret) +void komodo_eventadd_opreturn( komodo_state *sp, char *symbol, int32_t height, komodo::event_opreturn& opret) { if ( sp != nullptr && ASSETCHAINS_SYMBOL[0] != 0) { sp->add_event(symbol, height, opret); - komodo_opreturn(height, opret->value, opret->opret.data(), opret->opret.size(), opret->txid, opret->vout, symbol); + komodo_opreturn(height, opret.value, opret.opret.data(), opret.opret.size(), opret.txid, opret.vout, symbol); } } @@ -102,28 +102,19 @@ void komodo_eventadd_opreturn( komodo_state *sp, char *symbol, int32_t height, s * @param sp the state object * @param ev the event to undo */ -void komodo_event_undo(komodo_state *sp, std::shared_ptr ev) +template +void komodo_event_undo(komodo_state *sp, T& ev) { - switch ( ev->type ) - { - case KOMODO_EVENT_RATIFY: - printf("rewind of ratify, needs to be coded.%d\n",ev->height); - break; - case KOMODO_EVENT_NOTARIZED: - break; - case KOMODO_EVENT_KMDHEIGHT: - if ( ev->height <= sp->SAVEDHEIGHT ) - sp->SAVEDHEIGHT = ev->height; - break; - case KOMODO_EVENT_PRICEFEED: - // backtrack prices; - break; - case KOMODO_EVENT_OPRETURN: - // backtrack opreturns - break; - } } +template<> +void komodo_event_undo(komodo_state* sp, komodo::event_kmdheight& ev) +{ + if ( ev.height <= sp->SAVEDHEIGHT ) + sp->SAVEDHEIGHT = ev.height; +} + + void komodo_event_rewind(komodo_state *sp, char *symbol, int32_t height) { @@ -138,9 +129,9 @@ void komodo_event_rewind(komodo_state *sp, char *symbol, int32_t height) while ( sp->events.size() > 0) { auto ev = sp->events.back(); - if (ev-> height < height) + if (ev->height < height) break; - komodo_event_undo(sp, ev); + komodo_event_undo(sp, *ev); sp->events.pop_back(); } } @@ -167,19 +158,20 @@ void komodo_setkmdheight(struct komodo_state *sp,int32_t kmdheight,uint32_t time * @param height * @param kmdht the event */ -void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t height, std::shared_ptr kmdht) +void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t height, + komodo::event_kmdheight& kmdht) { if (sp != nullptr) { - if ( kmdht->kheight > 0 ) // height is advancing + if ( kmdht.kheight > 0 ) // height is advancing { sp->add_event(symbol, height, kmdht); - komodo_setkmdheight(sp, kmdht->kheight, kmdht->timestamp); + komodo_setkmdheight(sp, kmdht.kheight, kmdht.timestamp); } else // rewinding { - std::shared_ptr e = std::make_shared(height); + komodo::event_rewind e(height); sp->add_event(symbol, height, e); komodo_event_rewind(sp,symbol,height); } diff --git a/src/komodo_events.h b/src/komodo_events.h index 31cd2407dfc..3098e1b31f2 100644 --- a/src/komodo_events.h +++ b/src/komodo_events.h @@ -16,17 +16,15 @@ #include "komodo_defs.h" #include "komodo_structs.h" -void komodo_eventadd_notarized(komodo_state *sp,char *symbol,int32_t height, std::shared_ptr ntz); +void komodo_eventadd_notarized(komodo_state *sp,char *symbol,int32_t height, komodo::event_notarized& ntz); -void komodo_eventadd_pubkeys(komodo_state *sp,char *symbol,int32_t height, std::shared_ptr pk); +void komodo_eventadd_pubkeys(komodo_state *sp,char *symbol,int32_t height, komodo::event_pubkeys& pk); -void komodo_eventadd_pricefeed(komodo_state *sp,char *symbol,int32_t height, std::shared_ptr pf); +void komodo_eventadd_pricefeed(komodo_state *sp,char *symbol,int32_t height, komodo::event_pricefeed& pf); -void komodo_eventadd_opreturn(komodo_state *sp,char *symbol,int32_t height, std::shared_ptr opret); +void komodo_eventadd_opreturn(komodo_state *sp,char *symbol,int32_t height, komodo::event_opreturn& opret); -void komodo_eventadd_kmdheight(komodo_state *sp,char *symbol,int32_t height,std::shared_ptr kmd_ht); - -void komodo_event_undo(komodo_state *sp, std::shared_ptr ep); +void komodo_eventadd_kmdheight(komodo_state *sp,char *symbol,int32_t height, komodo::event_kmdheight& kmd_ht); void komodo_event_rewind(komodo_state *sp,char *symbol,int32_t height); diff --git a/src/komodo_globals.h b/src/komodo_globals.h index ecb85b0d46a..432f4e7ede3 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -42,21 +42,7 @@ int32_t NUM_PRICES; uint32_t *PVALS; struct knotaries_entry *Pubkeys; struct komodo_state KOMODO_STATES[34]; -const uint32_t nStakedDecemberHardforkTimestamp = 1576840000; //December 2019 hardfork 12/20/2019 @ 11:06am (UTC) -const int32_t nDecemberHardforkHeight = 1670000; //December 2019 hardfork -const uint32_t nS4Timestamp = 1592146800; //dPoW Season 4 2020 hardfork Sunday, June 14th, 2020 03:00:00 PM UTC -const int32_t nS4HardforkHeight = 1922000; //dPoW Season 4 2020 hardfork Sunday, June 14th, 2020 - -const uint32_t nS5Timestamp = 1623682800; //dPoW Season 5 Monday, June 14th, 2021 (03:00:00 PM UTC) -const int32_t nS5HardforkHeight = 2437300; //dPoW Season 5 Monday, June 14th, 2021 - -const uint32_t nS6Timestamp = 1656077853; // dPoW Season 6, Fri Jun 24 2022 13:37:33 GMT+0000 -const int32_t nS6HardforkHeight = 2963330; // dPoW Season 6, Fri Jun 24 2022 - -#define _COINBASE_MATURITY 100 -int COINBASE_MATURITY = _COINBASE_MATURITY;//100; -unsigned int WITNESS_CACHE_SIZE = _COINBASE_MATURITY+10; uint256 KOMODO_EARLYTXID; bool IS_KOMODO_NOTARY; @@ -116,7 +102,9 @@ int32_t ASSETCHAINS_STAKED; uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY = 10,ASSETCHAINS_FOUNDERS_REWARD; uint32_t KOMODO_INITDONE; -char KMDUSERPASS[8192+512+1],BTCUSERPASS[8192]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771, DEST_PORT; +char KMDUSERPASS[8192+512+1],BTCUSERPASS[8192]; +uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771; +uint16_t DEST_PORT = 0; // port to communicate with LTC for notarization verification uint64_t PENDING_KOMODO_TX; extern int32_t KOMODO_LOADINGBLOCKS; // defined in pow.cpp, boolean, 1 if currently loading the block index, 0 if not unsigned int MAX_BLOCK_SIGOPS = 20000; diff --git a/src/komodo_hardfork.cpp b/src/komodo_hardfork.cpp new file mode 100644 index 00000000000..eded0a18347 --- /dev/null +++ b/src/komodo_hardfork.cpp @@ -0,0 +1,484 @@ +#include "komodo_hardfork.h" + +const uint32_t nStakedDecemberHardforkTimestamp = 1576840000; //December 2019 hardfork 12/20/2019 @ 11:06am (UTC) +const int32_t nDecemberHardforkHeight = 1670000; //December 2019 hardfork + +const uint32_t nS4Timestamp = 1592146800; //dPoW Season 4 2020 hardfork Sunday, June 14th, 2020 03:00:00 PM UTC +const int32_t nS4HardforkHeight = 1922000; //dPoW Season 4 2020 hardfork Sunday, June 14th, 2020 + +const uint32_t nS5Timestamp = 1623682800; //dPoW Season 5 Monday, June 14th, 2021 (03:00:00 PM UTC) +const int32_t nS5HardforkHeight = 2437300; //dPoW Season 5 Monday, June 14th, 2021 + +const uint32_t nS6Timestamp = 1656077853; // dPoW Season 6, Fri Jun 24 2022 13:37:33 GMT+0000 +const int32_t nS6HardforkHeight = 2963330; // dPoW Season 6, Fri Jun 24 2022 + +// Era array of pubkeys. Add extra seasons to bottom as requried, after adding appropriate info above. +const char *notaries_elected[NUM_KMD_SEASONS][NUM_KMD_NOTARIES][2] = +{ + { + { "0_jl777_testA", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, + { "0_jl777_testB", "02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344" }, + { "0_kolo_testA", "0287aa4b73988ba26cf6565d815786caf0d2c4af704d7883d163ee89cd9977edec" }, + { "artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, + { "artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, + { "artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, + { "artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, + { "badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, + { "badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, + { "badass_SH", "026b49dd3923b78a592c1b475f208e23698d3f085c4c3b4906a59faf659fd9530b" }, + { "crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, // 10 + { "crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, + { "crackers_SH", "02be28310e6312d1dd44651fd96f6a44ccc269a321f907502aae81d246fabdb03e" }, + { "durerus_EU", "02bcbd287670bdca2c31e5d50130adb5dea1b53198f18abeec7211825f47485d57" }, + { "etszombi_AR", "031c79168d15edabf17d9ec99531ea9baa20039d0cdc14d9525863b83341b210e9" }, + { "etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, // 15 + { "etszombi_SH", "025d7a193c0757f7437fad3431f027e7b5ed6c925b77daba52a8755d24bf682dde" }, + { "farl4web_EU", "0300ecf9121cccf14cf9423e2adb5d98ce0c4e251721fa345dec2e03abeffbab3f" }, + { "farl4web_SH", "0396bb5ed3c57aa1221d7775ae0ff751e4c7dc9be220d0917fa8bbdf670586c030" }, + { "fullmoon_AR", "0254b1d64840ce9ff6bec9dd10e33beb92af5f7cee628f999cb6bc0fea833347cc" }, + { "fullmoon_NA", "031fb362323b06e165231c887836a8faadb96eda88a79ca434e28b3520b47d235b" }, // 20 + { "fullmoon_SH", "030e12b42ec33a80e12e570b6c8274ce664565b5c3da106859e96a7208b93afd0d" }, + { "grewal_NA", "03adc0834c203d172bce814df7c7a5e13dc603105e6b0adabc942d0421aefd2132" }, + { "grewal_SH", "03212a73f5d38a675ee3cdc6e82542a96c38c3d1c79d25a1ed2e42fcf6a8be4e68" }, + { "indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + { "indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + { "indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, + { "indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + { "jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, + { "jsgalt_NA", "027b3fb6fede798cd17c30dbfb7baf9332b3f8b1c7c513f443070874c410232446" }, + { "karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, // 30 + { "kashifali_EU", "033777c52a0190f261c6f66bd0e2bb299d30f012dcb8bfff384103211edb8bb207" }, + { "kolo_AR", "03016d19344c45341e023b72f9fb6e6152fdcfe105f3b4f50b82a4790ff54e9dc6" }, + { "kolo_SH", "02aa24064500756d9b0959b44d5325f2391d8e95c6127e109184937152c384e185" }, + { "metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + { "movecrypto_AR", "022783d94518e4dc77cbdf1a97915b29f427d7bc15ea867900a76665d3112be6f3" }, + { "movecrypto_EU", "021ab53bc6cf2c46b8a5456759f9d608966eff87384c2b52c0ac4cc8dd51e9cc42" }, + { "movecrypto_NA", "02efb12f4d78f44b0542d1c60146738e4d5506d27ec98a469142c5c84b29de0a80" }, + { "movecrypto_SH", "031f9739a3ebd6037a967ce1582cde66e79ea9a0551c54731c59c6b80f635bc859" }, + { "muros_AR", "022d77402fd7179335da39479c829be73428b0ef33fb360a4de6890f37c2aa005e" }, + { "noashh_AR", "029d93ef78197dc93892d2a30e5a54865f41e0ca3ab7eb8e3dcbc59c8756b6e355" }, // 40 + { "noashh_EU", "02061c6278b91fd4ac5cab4401100ffa3b2d5a277e8f71db23401cc071b3665546" }, + { "noashh_NA", "033c073366152b6b01535e15dd966a3a8039169584d06e27d92a69889b720d44e1" }, + { "nxtswe_EU", "032fb104e5eaa704a38a52c126af8f67e870d70f82977e5b2f093d5c1c21ae5899" }, + { "polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, + { "pondsea_AR", "032e1c213787312099158f2d74a89e8240a991d162d4ce8017d8504d1d7004f735" }, + { "pondsea_EU", "0225aa6f6f19e543180b31153d9e6d55d41bc7ec2ba191fd29f19a2f973544e29d" }, + { "pondsea_NA", "031bcfdbb62268e2ff8dfffeb9ddff7fe95fca46778c77eebff9c3829dfa1bb411" }, + { "pondsea_SH", "02209073bc0943451498de57f802650311b1f12aa6deffcd893da198a544c04f36" }, + { "popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, + { "popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, // 50 + { "ptytrader_NA", "0328c61467148b207400b23875234f8a825cce65b9c4c9b664f47410b8b8e3c222" }, + { "ptytrader_SH", "0250c93c492d8d5a6b565b90c22bee07c2d8701d6118c6267e99a4efd3c7748fa4" }, + { "rnr_AR", "029bdb08f931c0e98c2c4ba4ef45c8e33a34168cb2e6bf953cef335c359d77bfcd" }, + { "rnr_EU", "03f5c08dadffa0ffcafb8dd7ffc38c22887bd02702a6c9ac3440deddcf2837692b" }, + { "rnr_NA", "02e17c5f8c3c80f584ed343b8dcfa6d710dfef0889ec1e7728ce45ce559347c58c" }, + { "rnr_SH", "037536fb9bdfed10251f71543fb42679e7c52308bcd12146b2568b9a818d8b8377" }, + { "titomane_AR", "03cda6ca5c2d02db201488a54a548dbfc10533bdc275d5ea11928e8d6ab33c2185" }, + { "titomane_EU", "02e41feded94f0cc59f55f82f3c2c005d41da024e9a805b41105207ef89aa4bfbd" }, + { "titomane_SH", "035f49d7a308dd9a209e894321f010d21b7793461b0c89d6d9231a3fe5f68d9960" }, + { "vanbreuk_EU", "024f3cad7601d2399c131fd070e797d9cd8533868685ddbe515daa53c2e26004c3" }, // 60 + { "xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, + { "xxspot1_XX", "02ef445a392fcaf3ad4176a5da7f43580e8056594e003eba6559a713711a27f955" }, + { "xxspot2_XX", "03d85b221ea72ebcd25373e7961f4983d12add66a92f899deaf07bab1d8b6f5573" } + }, + { + {"0dev1_jl777", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, + {"0dev2_kolo", "030f34af4b908fb8eb2099accb56b8d157d49f6cfb691baa80fdd34f385efed961" }, + {"0dev3_kolo", "025af9d2b2a05338478159e9ac84543968fd18c45fd9307866b56f33898653b014" }, + {"0dev4_decker", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, + {"a-team_SH", "03b59ad322b17cb94080dc8e6dc10a0a865de6d47c16fb5b1a0b5f77f9507f3cce" }, + {"artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, + {"artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, + {"artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, + {"artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, + {"badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, + {"badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, // 10 + {"batman_AR", "033ecb640ec5852f42be24c3bf33ca123fb32ced134bed6aa2ba249cf31b0f2563" }, + {"batman_SH", "02ca5898931181d0b8aafc75ef56fce9c43656c0b6c9f64306e7c8542f6207018c" }, + {"ca333_EU", "03fc87b8c804f12a6bd18efd43b0ba2828e4e38834f6b44c0bfee19f966a12ba99" }, + {"chainmakers_EU", "02f3b08938a7f8d2609d567aebc4989eeded6e2e880c058fdf092c5da82c3bc5ee" }, + {"chainmakers_NA", "0276c6d1c65abc64c8559710b8aff4b9e33787072d3dda4ec9a47b30da0725f57a" }, + {"chainstrike_SH", "0370bcf10575d8fb0291afad7bf3a76929734f888228bc49e35c5c49b336002153" }, + {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, + {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, + {"crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, + {"crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, // 20 + {"dwy_EU", "0259c646288580221fdf0e92dbeecaee214504fdc8bbdf4a3019d6ec18b7540424" }, + {"emmanux_SH", "033f316114d950497fc1d9348f03770cd420f14f662ab2db6172df44c389a2667a" }, + {"etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, + {"fullmoon_AR", "03380314c4f42fa854df8c471618751879f9e8f0ff5dbabda2bd77d0f96cb35676" }, + {"fullmoon_NA", "030216211d8e2a48bae9e5d7eb3a42ca2b7aae8770979a791f883869aea2fa6eef" }, + {"fullmoon_SH", "03f34282fa57ecc7aba8afaf66c30099b5601e98dcbfd0d8a58c86c20d8b692c64" }, + {"goldenman_EU", "02d6f13a8f745921cdb811e32237bb98950af1a5952be7b3d429abd9152f8e388d" }, + {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, // 30 + {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + {"jackson_AR", "038ff7cfe34cb13b524e0941d5cf710beca2ffb7e05ddf15ced7d4f14fbb0a6f69" }, + {"jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, + {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, + {"komodoninja_EU", "038e567b99806b200b267b27bbca2abf6a3e8576406df5f872e3b38d30843cd5ba" }, + {"komodoninja_SH", "033178586896915e8456ebf407b1915351a617f46984001790f0cce3d6f3ada5c2" }, + {"komodopioneers_SH", "033ace50aedf8df70035b962a805431363a61cc4e69d99d90726a2d48fb195f68c" }, + {"libscott_SH", "03301a8248d41bc5dc926088a8cf31b65e2daf49eed7eb26af4fb03aae19682b95" }, + {"lukechilds_AR", "031aa66313ee024bbee8c17915cf7d105656d0ace5b4a43a3ab5eae1e14ec02696" }, + {"madmax_AR", "03891555b4a4393d655bf76f0ad0fb74e5159a615b6925907678edc2aac5e06a75" }, // 40 + {"meshbits_AR", "02957fd48ae6cb361b8a28cdb1b8ccf5067ff68eb1f90cba7df5f7934ed8eb4b2c" }, + {"meshbits_SH", "025c6e94877515dfd7b05682b9cc2fe4a49e076efe291e54fcec3add78183c1edb" }, + {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, + {"patchkez_SH", "0296270f394140640f8fa15684fc11255371abb6b9f253416ea2734e34607799c4" }, + {"pbca26_NA", "0276aca53a058556c485bbb60bdc54b600efe402a8b97f0341a7c04803ce204cb5" }, + {"peer2cloud_AR", "034e5563cb885999ae1530bd66fab728e580016629e8377579493b386bf6cebb15" }, + {"peer2cloud_SH", "03396ac453b3f23e20f30d4793c5b8ab6ded6993242df4f09fd91eb9a4f8aede84" }, + {"polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, + {"hyper_AR", "020f2f984d522051bd5247b61b080b4374a7ab389d959408313e8062acad3266b4" }, // 50 + {"hyper_EU", "03d00cf9ceace209c59fb013e112a786ad583d7de5ca45b1e0df3b4023bb14bf51" }, + {"hyper_SH", "0383d0b37f59f4ee5e3e98a47e461c861d49d0d90c80e9e16f7e63686a2dc071f3" }, + {"hyper_NA", "03d91c43230336c0d4b769c9c940145a8c53168bf62e34d1bccd7f6cfc7e5592de" }, + {"popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, + {"popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, + {"alien_AR", "0348d9b1fc6acf81290405580f525ee49b4749ed4637b51a28b18caa26543b20f0" }, + {"alien_EU", "020aab8308d4df375a846a9e3b1c7e99597b90497efa021d50bcf1bbba23246527" }, + {"thegaltmines_NA", "031bea28bec98b6380958a493a703ddc3353d7b05eb452109a773eefd15a32e421" }, + {"titomane_AR", "029d19215440d8cb9cc6c6b7a4744ae7fb9fb18d986e371b06aeb34b64845f9325" }, + {"titomane_EU", "0360b4805d885ff596f94312eed3e4e17cb56aa8077c6dd78d905f8de89da9499f" }, // 60 + {"titomane_SH", "03573713c5b20c1e682a2e8c0f8437625b3530f278e705af9b6614de29277a435b" }, + {"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" }, + {"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, + }, + { + {"madmax_NA", "0237e0d3268cebfa235958808db1efc20cc43b31100813b1f3e15cc5aa647ad2c3" }, // 0 + {"alright_AR", "020566fe2fb3874258b2d3cf1809a5d650e0edc7ba746fa5eec72750c5188c9cc9" }, + {"strob_NA", "0206f7a2e972d9dfef1c424c731503a0a27de1ba7a15a91a362dc7ec0d0fb47685" }, + {"dwy_EU", "021c7cf1f10c4dc39d13451123707ab780a741feedab6ac449766affe37515a29e" }, + {"phm87_SH", "021773a38db1bc3ede7f28142f901a161c7b7737875edbb40082a201c55dcf0add" }, + {"chainmakers_NA", "02285d813c30c0bf7eefdab1ff0a8ad08a07a0d26d8b95b3943ce814ac8e24d885" }, + {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + {"blackjok3r_SH", "021eac26dbad256cbb6f74d41b10763183ee07fb609dbd03480dd50634170547cc" }, + {"chainmakers_EU", "03fdf5a3fce8db7dee89724e706059c32e5aa3f233a6b6cc256fea337f05e3dbf7" }, + {"titomane_AR", "023e3aa9834c46971ff3e7cb86a200ec9c8074a9566a3ea85d400d5739662ee989" }, + {"fullmoon_SH", "023b7252968ea8a955cd63b9e57dee45a74f2d7ba23b4e0595572138ad1fb42d21" }, // 10 + {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, + {"chmex_EU", "0281304ebbcc39e4f09fda85f4232dd8dacd668e20e5fc11fba6b985186c90086e" }, + {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, + {"ca333_DEV", "02856843af2d9457b5b1c907068bef6077ea0904cc8bd4df1ced013f64bf267958" }, + {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, + {"pungocloud_SH", "024dfc76fa1f19b892be9d06e985d0c411e60dbbeb36bd100af9892a39555018f6" }, + {"voskcoin_EU", "034190b1c062a04124ad15b0fa56dfdf34aa06c164c7163b6aec0d654e5f118afb" }, + {"decker_DEV", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, + {"cryptoeconomy_EU", "0290ab4937e85246e048552df3e9a66cba2c1602db76e03763e16c671e750145d1" }, + {"etszombi_EU", "0293ea48d8841af7a419a24d9da11c34b39127ef041f847651bae6ab14dcd1f6b4" }, // 20 + {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, + {"pirate_AR", "03e29c90354815a750db8ea9cb3c1b9550911bb205f83d0355a061ac47c4cf2fde" }, + {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + {"zatjum_SH", "02d6b0c89cacd58a0af038139a9a90c9e02cd1e33803a1f15fceabea1f7e9c263a" }, + {"madmax_AR", "03c5941fe49d673c094bc8e9bb1a95766b4670c88be76d576e915daf2c30a454d3" }, + {"lukechilds_NA", "03f1051e62c2d280212481c62fe52aab0a5b23c95de5b8e9ad5f80d8af4277a64b" }, + {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, + {"tonyl_AR", "02cc8bc862f2b65ad4f99d5f68d3011c138bf517acdc8d4261166b0be8f64189e1" }, + {"infotech_DEV", "0345ad4ab5254782479f6322c369cec77a7535d2f2162d103d666917d5e4f30c4c" }, + {"fullmoon_NA", "032c716701fe3a6a3f90a97b9d874a9d6eedb066419209eed7060b0cc6b710c60b" }, // 30 + {"etszombi_AR", "02e55e104aa94f70cde68165d7df3e162d4410c76afd4643b161dea044aa6d06ce" }, + {"node-9_EU", "0372e5b51e86e2392bb15039bac0c8f975b852b45028a5e43b324c294e9f12e411" }, + {"phba2061_EU", "03f6bd15dba7e986f0c976ea19d8a9093cb7c989d499f1708a0386c5c5659e6c4e" }, + {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + {"and1-89_EU", "02736cbf8d7b50835afd50a319f162dd4beffe65f2b1dc6b90e64b32c8e7849ddd" }, + {"komodopioneers_SH", "032a238a5747777da7e819cfa3c859f3677a2daf14e4dce50916fc65d00ad9c52a" }, + {"komodopioneers_EU", "036d02425916444fff8cc7203fcbfc155c956dda5ceb647505836bef59885b6866" }, + {"d0ct0r_NA", "0303725d8525b6f969122faf04152653eb4bf34e10de92182263321769c334bf58" }, + {"kolo_DEV", "02849e12199dcc27ba09c3902686d2ad0adcbfcee9d67520e9abbdda045ba83227" }, + {"peer2cloud_AR", "02acc001fe1fe8fd68685ba26c0bc245924cb592e10cec71e9917df98b0e9d7c37" }, // 40 + {"webworker01_SH", "031e50ba6de3c16f99d414bb89866e578d963a54bde7916c810608966fb5700776" }, + {"webworker01_NA", "032735e9cad1bb00eaababfa6d27864fa4c1db0300c85e01e52176be2ca6a243ce" }, + {"pbca26_NA", "03a97606153d52338bcffd1bf19bb69ef8ce5a7cbdc2dbc3ff4f89d91ea6bbb4dc" }, + {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + {"pirate_NA", "0255e32d8a56671dee8aa7f717debb00efa7f0086ee802de0692f2d67ee3ee06ee" }, + {"lukechilds_AR", "025c6a73ff6d750b9ddf6755b390948cffdd00f344a639472d398dd5c6b4735d23" }, + {"dragonhound_NA", "0224a9d951d3a06d8e941cc7362b788bb1237bb0d56cc313e797eb027f37c2d375" }, + {"fullmoon_AR", "03da64dd7cd0db4c123c2f79d548a96095a5a103e5b9d956e9832865818ffa7872" }, + {"chainzilla_SH", "0360804b8817fd25ded6e9c0b50e3b0782ac666545b5416644198e18bc3903d9f9" }, + {"titomane_EU", "03772ac0aad6b0e9feec5e591bff5de6775d6132e888633e73d3ba896bdd8e0afb" }, // 50 + {"jeezy_EU", "037f182facbad35684a6e960699f5da4ba89e99f0d0d62a87e8400dd086c8e5dd7" }, + {"titomane_SH", "03850fdddf2413b51790daf51dd30823addb37313c8854b508ea6228205047ef9b" }, + {"alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f" }, + {"pirate_EU", "03fff24efd5648870a23badf46e26510e96d9e79ce281b27cfe963993039dd1351" }, + {"thegaltmines_NA", "02db1a16c7043f45d6033ccfbd0a51c2d789b32db428902f98b9e155cf0d7910ed" }, + {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4" }, + {"nutellalicka_SH", "02f7d90d0510c598ce45915e6372a9cd0ba72664cb65ce231f25d526fc3c5479fc" }, + {"chainstrike_SH", "03b806be3bf7a1f2f6290ec5c1ea7d3ea57774dcfcf2129a82b2569e585100e1cb" }, + {"dwy_SH", "036536d2d52d85f630b68b050f29ea1d7f90f3b42c10f8c5cdf3dbe1359af80aff" }, + {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd" }, // 60 + {"gt_AR", "0348430538a4944d3162bb4749d8c5ed51299c2434f3ee69c11a1f7815b3f46135" }, + {"patchkez_SH", "03f45e9beb5c4cd46525db8195eb05c1db84ae7ef3603566b3d775770eba3b96ee" }, + {"decker_AR", "03ffdf1a116300a78729608d9930742cd349f11a9d64fcc336b8f18592dd9c91bc" }, // 63 + }, + { + // Season 3.5 + {"madmax_NA", "0237e0d3268cebfa235958808db1efc20cc43b31100813b1f3e15cc5aa647ad2c3" }, // 0 + {"alright_AR", "020566fe2fb3874258b2d3cf1809a5d650e0edc7ba746fa5eec72750c5188c9cc9" }, + {"strob_NA", "0206f7a2e972d9dfef1c424c731503a0a27de1ba7a15a91a362dc7ec0d0fb47685" }, + {"hunter_EU", "0378224b4e9d8a0083ce36f2963ec0a4e231ec06b0c780de108e37f41181a89f6a" }, // FIXME verify this, kolo. Change name if you want + {"phm87_SH", "021773a38db1bc3ede7f28142f901a161c7b7737875edbb40082a201c55dcf0add" }, + {"chainmakers_NA", "02285d813c30c0bf7eefdab1ff0a8ad08a07a0d26d8b95b3943ce814ac8e24d885" }, + {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + {"blackjok3r_SH", "021eac26dbad256cbb6f74d41b10763183ee07fb609dbd03480dd50634170547cc" }, + {"chainmakers_EU", "03fdf5a3fce8db7dee89724e706059c32e5aa3f233a6b6cc256fea337f05e3dbf7" }, + {"titomane_AR", "023e3aa9834c46971ff3e7cb86a200ec9c8074a9566a3ea85d400d5739662ee989" }, + {"fullmoon_SH", "023b7252968ea8a955cd63b9e57dee45a74f2d7ba23b4e0595572138ad1fb42d21" }, // 10 + {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, + {"chmex_EU", "0281304ebbcc39e4f09fda85f4232dd8dacd668e20e5fc11fba6b985186c90086e" }, + {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, + {"ca333_DEV", "02856843af2d9457b5b1c907068bef6077ea0904cc8bd4df1ced013f64bf267958" }, + {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, + {"pungocloud_SH", "024dfc76fa1f19b892be9d06e985d0c411e60dbbeb36bd100af9892a39555018f6" }, + {"voskcoin_EU", "034190b1c062a04124ad15b0fa56dfdf34aa06c164c7163b6aec0d654e5f118afb" }, + {"decker_DEV", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, + {"cryptoeconomy_EU", "0290ab4937e85246e048552df3e9a66cba2c1602db76e03763e16c671e750145d1" }, + {"etszombi_EU", "0293ea48d8841af7a419a24d9da11c34b39127ef041f847651bae6ab14dcd1f6b4" }, // 20 + {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, + {"pirate_AR", "03e29c90354815a750db8ea9cb3c1b9550911bb205f83d0355a061ac47c4cf2fde" }, + {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + {"zatjum_SH", "02d6b0c89cacd58a0af038139a9a90c9e02cd1e33803a1f15fceabea1f7e9c263a" }, + {"madmax_AR", "03c5941fe49d673c094bc8e9bb1a95766b4670c88be76d576e915daf2c30a454d3" }, + {"lukechilds_NA", "03f1051e62c2d280212481c62fe52aab0a5b23c95de5b8e9ad5f80d8af4277a64b" }, + {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, + {"tonyl_AR", "02cc8bc862f2b65ad4f99d5f68d3011c138bf517acdc8d4261166b0be8f64189e1" }, + {"infotech_DEV", "0345ad4ab5254782479f6322c369cec77a7535d2f2162d103d666917d5e4f30c4c" }, + {"fullmoon_NA", "032c716701fe3a6a3f90a97b9d874a9d6eedb066419209eed7060b0cc6b710c60b" }, // 30 + {"etszombi_AR", "02e55e104aa94f70cde68165d7df3e162d4410c76afd4643b161dea044aa6d06ce" }, + {"node-9_EU", "0372e5b51e86e2392bb15039bac0c8f975b852b45028a5e43b324c294e9f12e411" }, + {"phba2061_EU", "03f6bd15dba7e986f0c976ea19d8a9093cb7c989d499f1708a0386c5c5659e6c4e" }, + {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + {"and1-89_EU", "02736cbf8d7b50835afd50a319f162dd4beffe65f2b1dc6b90e64b32c8e7849ddd" }, + {"komodopioneers_SH", "032a238a5747777da7e819cfa3c859f3677a2daf14e4dce50916fc65d00ad9c52a" }, + {"komodopioneers_EU", "036d02425916444fff8cc7203fcbfc155c956dda5ceb647505836bef59885b6866" }, + {"d0ct0r_NA", "0303725d8525b6f969122faf04152653eb4bf34e10de92182263321769c334bf58" }, + {"kolo_DEV", "02849e12199dcc27ba09c3902686d2ad0adcbfcee9d67520e9abbdda045ba83227" }, + {"peer2cloud_AR", "02acc001fe1fe8fd68685ba26c0bc245924cb592e10cec71e9917df98b0e9d7c37" }, // 40 + {"webworker01_SH", "031e50ba6de3c16f99d414bb89866e578d963a54bde7916c810608966fb5700776" }, + {"webworker01_NA", "032735e9cad1bb00eaababfa6d27864fa4c1db0300c85e01e52176be2ca6a243ce" }, + {"pbca26_NA", "03a97606153d52338bcffd1bf19bb69ef8ce5a7cbdc2dbc3ff4f89d91ea6bbb4dc" }, + {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + {"pirate_NA", "0255e32d8a56671dee8aa7f717debb00efa7f0086ee802de0692f2d67ee3ee06ee" }, + {"lukechilds_AR", "025c6a73ff6d750b9ddf6755b390948cffdd00f344a639472d398dd5c6b4735d23" }, + {"dragonhound_NA", "0224a9d951d3a06d8e941cc7362b788bb1237bb0d56cc313e797eb027f37c2d375" }, + {"fullmoon_AR", "03da64dd7cd0db4c123c2f79d548a96095a5a103e5b9d956e9832865818ffa7872" }, + {"chainzilla_SH", "0360804b8817fd25ded6e9c0b50e3b0782ac666545b5416644198e18bc3903d9f9" }, + {"titomane_EU", "03772ac0aad6b0e9feec5e591bff5de6775d6132e888633e73d3ba896bdd8e0afb" }, // 50 + {"jeezy_EU", "037f182facbad35684a6e960699f5da4ba89e99f0d0d62a87e8400dd086c8e5dd7" }, + {"titomane_SH", "03850fdddf2413b51790daf51dd30823addb37313c8854b508ea6228205047ef9b" }, + {"alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f" }, + {"pirate_EU", "03fff24efd5648870a23badf46e26510e96d9e79ce281b27cfe963993039dd1351" }, + {"thegaltmines_NA", "02db1a16c7043f45d6033ccfbd0a51c2d789b32db428902f98b9e155cf0d7910ed" }, + {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4" }, + {"nutellalicka_SH", "02f7d90d0510c598ce45915e6372a9cd0ba72664cb65ce231f25d526fc3c5479fc" }, + {"chainstrike_SH", "03b806be3bf7a1f2f6290ec5c1ea7d3ea57774dcfcf2129a82b2569e585100e1cb" }, + {"hunter_SH", "02407db70ad30ce4dfaee8b4ae35fae88390cad2b0ba0373fdd6231967537ccfdf" }, + {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd" }, // 60 + {"gt_AR", "0348430538a4944d3162bb4749d8c5ed51299c2434f3ee69c11a1f7815b3f46135" }, + {"patchkez_SH", "03f45e9beb5c4cd46525db8195eb05c1db84ae7ef3603566b3d775770eba3b96ee" }, + {"decker_AR", "03ffdf1a116300a78729608d9930742cd349f11a9d64fcc336b8f18592dd9c91bc" }, // 63 + }, + { + // Season 4 + { "alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f" }, + { "alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd" }, + { "strob_NA", "02a1c0bd40b294f06d3e44a52d1b2746c260c475c725e9351f1312e49e01c9a405" }, + { "titomane_SH", "020014ad4eedf6b1aeb0ad3b101a58d0a2fc570719e46530fd98d4e585f63eb4ae" }, + { "fullmoon_AR", "03b251095e747f759505ec745a4bbff9a768b8dce1f65137300b7c21efec01a07a" }, + { "phba2061_EU", "03a9492d2a1601d0d98cfe94d8adf9689d1bb0e600088127a4f6ca937761fb1c66" }, + { "fullmoon_NA", "03931c1d654a99658998ce0ddae108d825943a821d1cddd85e948ac1d483f68fb6" }, + { "fullmoon_SH", "03c2a1ed9ddb7bb8344328946017b9d8d1357b898957dd6aaa8c190ae26740b9ff" }, + { "madmax_AR", "022be5a2829fa0291f9a51ff7aeceef702eef581f2611887c195e29da49092e6de" }, + { "titomane_EU", "0285cf1fdba761daf6f1f611c32d319cd58214972ef822793008b69dde239443dd" }, + { "cipi_NA", "022c6825a24792cc3b010b1531521eba9b5e2662d640ed700fd96167df37e75239" }, + { "indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + { "decker_AR", "03ffdf1a116300a78729608d9930742cd349f11a9d64fcc336b8f18592dd9c91bc" }, + { "indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + { "madmax_NA", "02997b7ab21b86bbea558ae79acc35d62c9cedf441578f78112f986d72e8eece08" }, + { "chainzilla_SH", "02288ba6dc57936b59d60345e397d62f5d7e7d975f34ed5c2f2e23288325661563" }, + { "peer2cloud_AR", "0250e7e43a3535731b051d1bcc7dc88fbb5163c3fe41c5dee72bd973bcc4dca9f2" }, + { "pirate_EU", "0231c0f50a06655c3d2edf8d7e722d290195d49c78d50de7786b9d196e8820c848" }, + { "webworker01_NA", "02dfd5f3cef1142879a7250752feb91ddd722c497fb98c7377c0fcc5ccc201bd55" }, + { "zatjum_SH", "036066fd638b10e555597623e97e032b28b4d1fa5a13c2b0c80c420dbddad236c2" }, + { "titomane_AR", "0268203a4c80047edcd66385c22e764ea5fb8bc42edae389a438156e7dca9a8251" }, + { "chmex_EU", "025b7209ba37df8d9695a23ea706ea2594863ab09055ca6bf485855937f3321d1d" }, + { "indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, + { "patchkez_SH", "02cabd6c5fc0b5476c7a01e9d7b907e9f0a051d7f4f731959955d3f6b18ee9a242" }, + { "metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + { "etszombi_EU", "0341adbf238f33a33cc895633db996c3ad01275313ac6641e046a3db0b27f1c880" }, + { "pirate_NA", "02207f27a13625a0b8caef6a7bb9de613ff16e4a5f232da8d7c235c7c5bad72ffe" }, + { "metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, + { "indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + { "chainmakers_NA", "029415a1609c33dfe4a1016877ba35f9265d25d737649f307048efe96e76512877" }, + { "mihailo_EU", "037f9563f30c609b19fd435a19b8bde7d6db703012ba1aba72e9f42a87366d1941" }, + { "tonyl_AR", "0299684d7291abf90975fa493bf53212cf1456c374aa36f83cc94daece89350ae9" }, + { "alien_NA", "03bea1ac333b95c8669ec091907ea8713cae26f74b9e886e13593400e21c4d30a8" }, + { "pungocloud_SH", "025b97d8c23effaca6fa7efacce20bf54df73081b63004a0fe22f3f98fece5669f" }, + { "node9_EU", "029ffa793b5c3248f8ea3da47fa3cf1810dada5af032ecd0e37bab5b92dd63b34e" }, + { "smdmitry_AR", "022a2a45979a6631a25e4c96469423de720a2f4c849548957c35a35c91041ee7ac" }, + { "nodeone_NA", "03f9dd0484e81174fd50775cb9099691c7d140ff00c0f088847e38dc87da67eb9b" }, + { "gcharang_SH", "02ec4172eab854a0d8cd32bc691c83e93975a3df5a4a453a866736c56e025dc359" }, + { "cipi_EU", "02f2b6defff1c544202f66e47cfd6909c54d67c7c39b9c2a99f137dbaf6d0bd8fa" }, + { "etszombi_AR", "0329944b0ac65b6760787ede042a2fde0be9fca1d80dd756bc0ee0b98d389b7682" }, + { "pbca26_NA", "0387e0fb6f2ca951154c87e16c6cbf93a69862bb165c1a96bcd8722b3af24fe533" }, + { "mylo_SH", "03b58f57822e90fe105e6efb63fd8666033ea503d6cc165b1e479bbd8c2ba033e8" }, + { "swisscertifiers_EU", "03ebcc71b42d88994b8b2134bcde6cb269bd7e71a9dd7616371d9294ec1c1902c5" }, + { "marmarachain_AR", "035bbd81a098172592fe97f50a0ce13cbbf80e55cc7862eccdbd7310fab8a90c4c" }, + { "karasugoi_NA", "0262cf2559703464151153c12e00c4b67a969e39b330301fdcaa6667d7eb02c57d" }, + { "phm87_SH", "021773a38db1bc3ede7f28142f901a161c7b7737875edbb40082a201c55dcf0add" }, + { "oszy_EU", "03d1ffd680491b98a3ec5541715681d1a45293c8efb1722c32392a1d792622596a" }, + { "chmex_AR", "036c856ea778ea105b93c0be187004d4e51161eda32888aa307b8f72d490884005" }, + { "dragonhound_NA", "0227e5cad3731e381df157de189527aac8eb50d82a13ce2bd81153984ebc749515" }, + { "strob_SH", "025ceac4256cef83ca4b110f837a71d70a5a977ecfdf807335e00bc78b560d451a" }, + { "madmax_EU", "02ea0cf4d6d151d0528b07efa79cc7403d77cb9195e2e6c8374f5074b9a787e287" }, + { "dudezmobi_AR", "027ecd974ff2a27a37ee69956cd2e6bb31a608116206f3e31ef186823420182450" }, + { "daemonfox_NA", "022d6f4885f53cbd668ad7d03d4f8e830c233f74e3a918da1ed247edfc71820b3d" }, + { "nutellalicka_SH", "02f4b1e71bc865a79c05fe333952b97cb040d8925d13e83925e170188b3011269b" }, + { "starfleet_EU", "025c7275bd750936862b47793f1f0bb3cbed60fb75a48e7da016e557925fe375eb" }, + { "mrlynch_AR", "031987dc82b087cd53e23df5480e265a5928e9243e0e11849fa12359739d8b18a4" }, + { "greer_NA", "03e0995615d7d3cf1107effa6bdb1133e0876cf1768e923aa533a4e2ee675ec383" }, + { "mcrypt_SH", "025faab3cc2e83bf7dad6a9463cbff86c08800e937942126f258cf219bc2320043" }, + { "decker_EU", "03777777caebce56e17ca3aae4e16374335b156f1dd62ee3c7f8799c6b885f5560" }, + { "dappvader_SH", "02962e2e5af746632016bc7b24d444f7c90141a5f42ce54e361b302cf455d90e6a" }, + { "alright_DEV", "02b73a589d61691efa2ada15c006d27bc18493fea867ce6c14db3d3d28751f8ce3" }, + { "artemii235_DEV", "03bb616b12430bdd0483653de18733597a4fd416623c7065c0e21fe9d96460add1" }, + { "tonyl_DEV", "02d5f7fd6e25d34ab2f3318d60cdb89ff3a812ec5d0212c4c113bb12d12616cfdc" }, + { "decker_DEV", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" } + }, + { + // Season 5 + {"alrighttt_DEV", "03483166d8663beeb48a493eec161bf506df1906153b6259f7ca617e4cb8110260"}, // 0 + {"alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f"}, + {"artempikulin_AR", "026a8ed1e4eeeb023cfb8e003e1c1de6a2b771f37e112745ffb8b6e375a9cbfdec"}, + {"chmex_AR", "036c856ea778ea105b93c0be187004d4e51161eda32888aa307b8f72d490884005"}, + {"cipi_AR", "033ae024cdb748e083406a2e20037017a1292079ad6a8161ae5b43f398724fea74"}, + {"shadowbit_AR", "02909c79a198179c193fb85bbd4ba09b875a5a9bd481fec284658188b96ed43519"}, + {"goldenman_AR", "0345b888e5de9c11871c080212ccaebf8a3d77b05fe3d535336efc5c7df334bbc7"}, + {"kolo_AR", "0281d3c7bf067088b9572b4d906afca2083a71a38b1011878ecd347651d00af433"}, + {"madmax_AR", "02f729b8df4dacdc8d811416eb32e98a5cc37023b42c81b77d1c00881de879a99a"}, + {"mcrypt_AR", "029bdb33b08f96524082490f4373bc6026b92bcaef9bc521a840a799c73b75ed80"}, + {"mrlynch_AR", "031987dc82b087cd53e23df5480e265a5928e9243e0e11849fa12359739d8b18a4"}, // 10 + {"ocean_AR", "03c2bc8c57a001a788851fedc33ce72797ee8fe26eaa3abb1b807727e4867a3105"}, + {"smdmitry_AR", "022a2a45979a6631a25e4c96469423de720a2f4c849548957c35a35c91041ee7ac"}, + {"tokel_AR", "03f3bf697173e47de7bae2ae02b3d3bcf28133a47db72f2a0266061597aaa7779d"}, + {"tonyl_AR", "029ad03929ec295e9164e2bfb9f0e0102c280d5e5212503d079d2d99ab492a9106"}, + {"tonyl_DEV", "02342ec82b31a016b71cd1eb2f482a74f63172e1029ba2fb18f0def3bd4fc0668a"}, + {"artem_DEV", "036b9848396ddcdb9bb58ddab2c24b710b8e4e9b0ee084a00518505ecd9e9fe174"}, + {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd"}, + {"alienx_EU", "026afe5b112d1b39e0edafd5e051e261a676104460581f3673f26ceff7f1e6c56c"}, + {"ca333_EU", "03ffb8072f78304c42ae9b60435f6c3296cbc72de129ae49bba175a65c31c9a7e2"}, + {"chmex_EU", "025b7209ba37df8d9695a23ea706ea2594863ab09055ca6bf485855937f3321d1d"}, // 20 + {"cipi_EU", "03d6e1f3a693b5d69049791005d7cb64c259a1ad85833f5a9c545d4fee29905009"}, + {"cipi2_EU", "0202e430157486503f4bde3d3ca770c8f1e2447cf480a6b273b5265b9620f585e3"}, + {"shadowbit_EU", "02668f5f723584f97f5e6f9196fc31018f36a6cf824c60328ad0c097a785df4745"}, + {"komodopioneers_EU", "0351f7f2a6ecce863e4e774bfafe2e59e151c08bf8f350286763a6b8ed97274b82"}, + {"madmax_EU", "028d04f7ccae0d9d57bfa801c4f1e32c707c17589b3c08a0ce08d44eab637eb66b"}, + {"marmarachain_EU", "023a858bbc3f0c6df5b74243315028e968c2f299d84ea8ecc0b28b5f0e2ad24c3c"}, + {"node-9_EU", "03c375924aac39d0c49de6690199e4d08d10fed6725988dcf5d2486661b5e3a656"}, + {"slyris_EU", "021cb6365c13cb35aad4b70aa18b63a75d1d4b9797a0754d3d0142d6fedc83b24e"}, + {"smdmitry_EU", "02eb3aad81778f8d6f7e5295c44ca224e5c812f5e43fc1e9ce4ebafc23324183c9"}, + {"van_EU", "03af7f8c82f20671ca1978116353839d3e501523e379bfb52b1e05d7816bb5812f"}, // 30 + {"shadowbit_DEV", "02ca882f153e715091a2dbc5409096f8c109d9fe6506ca7a918056dd37162b6f6e"}, + {"gcharang_DEV", "02cb445948bf0d89f8d61102e12a5ee6e98be61ac7c2cb9ba435219ea9db967117"}, + {"alien_NA", "03bea1ac333b95c8669ec091907ea8713cae26f74b9e886e13593400e21c4d30a8"}, + {"alienx_NA", "02f0b3ef87629509441b1ae95f28108f258a81910e483b90e0496205e24e7069b8"}, + {"cipi_NA", "036cc1d7476e4260601927be0fc8b748ae68d8fec8f5c498f71569a01bd92046c5"}, + {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4"}, + {"dragonhound_NA", "02e650819f4d1cabeaad6bc5ec8c0722a89e63059a10f8b5e97c983c321608329b"}, + {"hyper_NA", "030994a303b26df6e7c6ed456f069c5de9e200e1380bebc5ed8ebe0f834f477f3d"}, + {"madmax_NA", "03898aec46014e8619e2369cc85073048dad05d3c5bf696d8b524db78a39ae5beb"}, + {"node-9_NA", "02f697eed99fd21f2f0eaad81d13543a75c576f669bfddbcbeef0f7625fea2e9d5"}, // 40 + {"nodeone_NA", "03f9dd0484e81174fd50775cb9099691c7d140ff00c0f088847e38dc87da67eb9b"}, + {"pbca26_NA", "0332543ff1287604afd67f63af0aa0b263aef14fe1850b85db16b81462eed834fd"}, + {"ptyx_NA", "02cbda9c43a794f2134a11815fe86dca017990269accb139e962d764c011c9a4d7"}, + {"strob_NA", "02a1c0bd40b294f06d3e44a52d1b2746c260c475c725e9351f1312e49e01c9a405"}, + {"karasugoi_NA", "0262cf2559703464151153c12e00c4b67a969e39b330301fdcaa6667d7eb02c57d"}, + {"webworker01_NA", "0376558d13c31cf9c664a1b5e58f4fff7153777069bef7a66ed8c8526b99787a9e"}, + {"yurii_DEV", "03e57c7341d2c8a3be62e1caaa28978d76a8277dea7bb484fdd8c55dc05e4e4e93"}, + {"ca333_DEV", "03d885e292842912bd990299ebce33451a5a01cb14e4874d90770efb22e82ef40f"}, + {"chmex_SH", "02698305eb3c27a2c724efd2152f9250739355116f201656c34b83aac2d3aebd19"}, + {"collider_SH", "03bd0022a55a2ead52fd65b317186743374ad320f3704d459f41797e264d1ec854"}, // 50 + {"dappvader_SH", "02bffea7911e09ad9a7df54af0c225516478d3ba138e65061aa8d4b9756bb4c8f4"}, + {"drkush_SH", "030b31cc9528566422e25f3e9b96541ab3626c0dea0e7aa3c0b0bd96039eae2f5a"}, + {"majora31_SH", "033bf21f039a1c832effad208d564e02e968f11e3a3aa41c42e3b748a232fb33f3"}, + {"mcrypt_SH", "025faab3cc2e83bf7dad6a9463cbff86c08800e937942126f258cf219bc2320043"}, + {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309"}, + {"mylo_SH", "03458dca36e800d5bc121d8c0d35f9fc6282880a79fee2d7e050f887b797bc7d6e"}, + {"nutellaLicka_SH", "03a495962a9e9eca06ee3b8ab4cd94e6ea0d87dd39d334ad85a524c4fece1a3db7"}, + {"pbca26_SH", "02c62877e96fc414f2444edf0601abff9d5d2f9078e49fa867ba5305f3c5b3beb0"}, + {"phit_SH", "02a9cef2141fb2af24349c1eea20f5fa8f5dba2835723778d19b23353ddcd877b1"}, + {"sheeba_SH", "03e6578015b7f0ab78a486070435031fff7bae11256ca6a9f3d358ab03029737cb"}, // 60 + {"strob_SH", "025ceac4256cef83ca4b110f837a71d70a5a977ecfdf807335e00bc78b560d451a"}, + {"strobnidan_SH", "02b967fde3686d45056343e488997d4c53f25cd7ad38548cd12b136010a09295ae"}, + {"dragonhound_DEV", "038e010c33c56b61389409eea5597fe17967398731e23185c84c472a16fc5d34ab"} + }, + { + // Season 6 + {"blackice_DEV", "02ca882f153e715091a2dbc5409096f8c109d9fe6506ca7a918056dd37162b6f6e"}, // 0 + {"blackice_AR", "02909c79a198179c193fb85bbd4ba09b875a5a9bd481fec284658188b96ed43519"}, + {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd"}, + {"alien_NA", "03bea1ac333b95c8669ec091907ea8713cae26f74b9e886e13593400e21c4d30a8"}, + {"alien_SH", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f"}, + {"alienx_EU", "026afe5b112d1b39e0edafd5e051e261a676104460581f3673f26ceff7f1e6c56c"}, + {"alienx_NA", "02f0b3ef87629509441b1ae95f28108f258a81910e483b90e0496205e24e7069b8"}, + {"artem.pikulin_AR", "026a8ed1e4eeeb023cfb8e003e1c1de6a2b771f37e112745ffb8b6e375a9cbfdec"}, + {"artem.pikulin_DEV", "036b9848396ddcdb9bb58ddab2c24b710b8e4e9b0ee084a00518505ecd9e9fe174"}, + {"blackice_EU", "02668f5f723584f97f5e6f9196fc31018f36a6cf824c60328ad0c097a785df4745"}, + {"chmex_AR", "036c856ea778ea105b93c0be187004d4e51161eda32888aa307b8f72d490884005"}, // 10 + {"chmex_EU", "025b7209ba37df8d9695a23ea706ea2594863ab09055ca6bf485855937f3321d1d"}, + {"chmex_NA", "030c2528c29d5328243c910277e3d74aa77c9b4e145308007d2b11550731591dbe"}, + {"chmex_SH", "02698305eb3c27a2c724efd2152f9250739355116f201656c34b83aac2d3aebd19"}, + {"chmex1_SH", "02d27ed1cddfbaff9e47865e7df0165457e8f075f70bbea8c0498598ccf494555d"}, + {"cipi_1_EU", "03d6e1f3a693b5d69049791005d7cb64c259a1ad85833f5a9c545d4fee29905009"}, + {"cipi_2_EU", "0202e430157486503f4bde3d3ca770c8f1e2447cf480a6b273b5265b9620f585e3"}, + {"cipi_AR", "033ae024cdb748e083406a2e20037017a1292079ad6a8161ae5b43f398724fea74"}, + {"cipi_NA", "036cc1d7476e4260601927be0fc8b748ae68d8fec8f5c498f71569a01bd92046c5"}, + {"computergenie_EU", "03a8c071036228e0900e0171f616ce1a58f0a761193551d68c4c20e70534f2e183"}, + {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4"}, // 20 + {"dimxy_AR", "02689d0b77b1e8e8c93a102d8b689fd08179164d70e2dd585543c3896a0916e6a1"}, + {"dimxy_DEV", "039a01cd626d5efbe7fd05a59d8e5fced53bacac589192278f9b00ad31654b6956"}, + {"dragonhound_NA", "02e650819f4d1cabeaad6bc5ec8c0722a89e63059a10f8b5e97c983c321608329b"}, + {"fediakash_AR", "027dfe5403f8870fb0e1b94a2b4204373b31ea73179ba500a88dd56d22855cd03b"}, + {"gcharang_DEV", "033b82b5791c65477dd11095cf33332013df6d2bcb7aa06a6dae5f7b22b6959b0b"}, + {"gcharang_SH", "02cb445948bf0d89f8d61102e12a5ee6e98be61ac7c2cb9ba435219ea9db967117"}, + {"goldenman_AR", "02c11f651df6a03f1a17b9ea0b1a73c0acca7aeacd4081e09bd7dd939690af8ae1"}, + {"kolo_AR", "028431645f923a9e383a4e37cbb7168fa34988da23d43097124fe882bdac6d175f"}, + {"kolo_EU", "03e1287d4c14ad73ce9ddd31361a7de8df4eeeefe9460a1ff9a6b2a1242ad3b7c2"}, + {"kolox_AR", "0289f5f64f4bb18d014c4e9f4c888f4da2b6518e88fd5b7768728c38177b66d305"}, // 30 + {"komodopioneers_EU", "0351f7f2a6ecce863e4e774bfafe2e59e151c08bf8f350286763a6b8ed97274b82"}, + {"madmax_DEV", "027100e6b3db2028034db651946ecde90e45be3799ebc310d39af4496772a850ad"}, + {"marmarachain_EU", "0234e40800500370d43979586ee2cec2e777a0368d10c682e78bca30fd1630c18d"}, + {"mcrypt_AR", "029bdb33b08f96524082490f4373bc6026b92bcaef9bc521a840a799c73b75ed80"}, + {"mcrypt_SH", "025faab3cc2e83bf7dad6a9463cbff86c08800e937942126f258cf219bc2320043"}, + {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309"}, + {"mylo_NA", "0365a778014c216401b6ba9c28eec88f116a9a9912e145ba2dbbd065d98b493af5"}, + {"mylo_SH", "03458dca36e800d5bc121d8c0d35f9fc6282880a79fee2d7e050f887b797bc7d6e"}, + {"nodeone_NA", "03f9dd0484e81174fd50775cb9099691c7d140ff00c0f088847e38dc87da67eb9b"}, + {"nutellalicka_AR", "0285be2518bf8d65fceaa5f4d8485002f90d3b7ff274b23bb925fd167128e19589"}, // 40 + {"nutellalicka_SH", "03a8b10c1f74af429fc43ab4eb722f6c2a88087f2d71703e7f0e8001207a966fb5"}, + {"ocean_AR", "03c2bc8c57a001a788851fedc33ce72797ee8fe26eaa3abb1b807727e4867a3105"}, + {"pbca26_NA", "03d8b25536da157d931b159a72c0eeaedb1bf7bb3eb2d02647fa41b2422a2b064e"}, + {"pbca26_SH", "039a55787b742c3725323f0bd81c90a484fbdbf276a16317883bb03eedd9d6aa7c"}, + {"phit_SH", "02a9cef2141fb2af24349c1eea20f5fa8f5dba2835723778d19b23353ddcd877b1"}, + {"ptyx_NA", "0395640e81359526ecbc140716ddd5c9a1ce2a697fb547ca896e17cad3c65e78db"}, + {"ptyx2_NA", "0225ff37e49e443065018736fbcad175ab5993b51b99b846e8de0b8b9abbed2ef2"}, + {"sheeba_SH", "03e6578015b7f0ab78a486070435031fff7bae11256ca6a9f3d358ab03029737cb"}, + {"smdmitry_AR", "022a2a45979a6631a25e4c96469423de720a2f4c849548957c35a35c91041ee7ac"}, + {"smdmitry_EU", "02eb3aad81778f8d6f7e5295c44ca224e5c812f5e43fc1e9ce4ebafc23324183c9"}, // 50 + {"smdmitry_SH", "02d01cd6b87cbf5a9795c06968f0d169168c1be0d82cfeb79958b11ae2c30316c1"}, + {"strob_SH", "025ceac4256cef83ca4b110f837a71d70a5a977ecfdf807335e00bc78b560d451a"}, + {"strobnidan_SH", "02b967fde3686d45056343e488997d4c53f25cd7ad38548cd12b136010a09295ae"}, + {"tokel_NA", "02b472713e87fb2560569857051ea0811c65d668a6fe73df165afe152417f774a0"}, + {"tonyl_AR", "029ad03929ec295e9164e2bfb9f0e0102c280d5e5212503d079d2d99ab492a9106"}, + {"tonyl_DEV", "02342ec82b31a016b71cd1eb2f482a74f63172e1029ba2fb18f0def3bd4fc0668a"}, + {"van_EU", "03af7f8c82f20671ca1978116353839d3e501523e379bfb52b1e05d7816bb5812f"}, + {"webworker01_EU", "0321d523645caffd8e762764ba56f7874a61b9bf534837a2cb6e7da219fab15eef"}, + {"webworker01_NA", "0287883ddd8da366401893ebcc1ff7e52d2ad3736984120a0ab01603e02c21dc98"}, + {"who-biz_NA", "02f91a6772fe1a376e2bbe4b190008e3f878d40a8eaf92c65f1a7680b6b42ea47b"}, // 60 + {"yurii-khi_DEV", "03e57c7341d2c8a3be62e1caaa28978d76a8277dea7bb484fdd8c55dc05e4e4e93"}, + {"ca333_EU", "021d6fbe67d12f492a01306c70ab096f8b8581eb5f958d3f5fe3588ae8c7797f42"}, + {"dragonhound_DEV", "038e010c33c56b61389409eea5597fe17967398731e23185c84c472a16fc5d34ab"} + } +}; diff --git a/src/komodo_hardfork.h b/src/komodo_hardfork.h index 5cf20ad35e0..199bf43a0ee 100644 --- a/src/komodo_hardfork.h +++ b/src/komodo_hardfork.h @@ -19,476 +19,7 @@ extern const int32_t nS6HardforkHeight; // dPoW Season 6, Fri Jun 24 2022 static const uint32_t KMD_SEASON_TIMESTAMPS[NUM_KMD_SEASONS] = {1525132800, 1563148800, nStakedDecemberHardforkTimestamp, nS4Timestamp, nS5Timestamp, nS6Timestamp, 1751328000}; static const int32_t KMD_SEASON_HEIGHTS[NUM_KMD_SEASONS] = {814000, 1444000, nDecemberHardforkHeight, nS4HardforkHeight, nS5HardforkHeight, nS6HardforkHeight, 7113400}; -// Era array of pubkeys. Add extra seasons to bottom as requried, after adding appropriate info above. -static const char *notaries_elected[NUM_KMD_SEASONS][NUM_KMD_NOTARIES][2] = -{ - { - { "0_jl777_testA", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, - { "0_jl777_testB", "02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344" }, - { "0_kolo_testA", "0287aa4b73988ba26cf6565d815786caf0d2c4af704d7883d163ee89cd9977edec" }, - { "artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, - { "artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, - { "artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, - { "artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, - { "badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, - { "badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, - { "badass_SH", "026b49dd3923b78a592c1b475f208e23698d3f085c4c3b4906a59faf659fd9530b" }, - { "crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, // 10 - { "crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, - { "crackers_SH", "02be28310e6312d1dd44651fd96f6a44ccc269a321f907502aae81d246fabdb03e" }, - { "durerus_EU", "02bcbd287670bdca2c31e5d50130adb5dea1b53198f18abeec7211825f47485d57" }, - { "etszombi_AR", "031c79168d15edabf17d9ec99531ea9baa20039d0cdc14d9525863b83341b210e9" }, - { "etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, // 15 - { "etszombi_SH", "025d7a193c0757f7437fad3431f027e7b5ed6c925b77daba52a8755d24bf682dde" }, - { "farl4web_EU", "0300ecf9121cccf14cf9423e2adb5d98ce0c4e251721fa345dec2e03abeffbab3f" }, - { "farl4web_SH", "0396bb5ed3c57aa1221d7775ae0ff751e4c7dc9be220d0917fa8bbdf670586c030" }, - { "fullmoon_AR", "0254b1d64840ce9ff6bec9dd10e33beb92af5f7cee628f999cb6bc0fea833347cc" }, - { "fullmoon_NA", "031fb362323b06e165231c887836a8faadb96eda88a79ca434e28b3520b47d235b" }, // 20 - { "fullmoon_SH", "030e12b42ec33a80e12e570b6c8274ce664565b5c3da106859e96a7208b93afd0d" }, - { "grewal_NA", "03adc0834c203d172bce814df7c7a5e13dc603105e6b0adabc942d0421aefd2132" }, - { "grewal_SH", "03212a73f5d38a675ee3cdc6e82542a96c38c3d1c79d25a1ed2e42fcf6a8be4e68" }, - { "indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, - { "indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, - { "indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, - { "indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, - { "jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, - { "jsgalt_NA", "027b3fb6fede798cd17c30dbfb7baf9332b3f8b1c7c513f443070874c410232446" }, - { "karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, // 30 - { "kashifali_EU", "033777c52a0190f261c6f66bd0e2bb299d30f012dcb8bfff384103211edb8bb207" }, - { "kolo_AR", "03016d19344c45341e023b72f9fb6e6152fdcfe105f3b4f50b82a4790ff54e9dc6" }, - { "kolo_SH", "02aa24064500756d9b0959b44d5325f2391d8e95c6127e109184937152c384e185" }, - { "metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, - { "movecrypto_AR", "022783d94518e4dc77cbdf1a97915b29f427d7bc15ea867900a76665d3112be6f3" }, - { "movecrypto_EU", "021ab53bc6cf2c46b8a5456759f9d608966eff87384c2b52c0ac4cc8dd51e9cc42" }, - { "movecrypto_NA", "02efb12f4d78f44b0542d1c60146738e4d5506d27ec98a469142c5c84b29de0a80" }, - { "movecrypto_SH", "031f9739a3ebd6037a967ce1582cde66e79ea9a0551c54731c59c6b80f635bc859" }, - { "muros_AR", "022d77402fd7179335da39479c829be73428b0ef33fb360a4de6890f37c2aa005e" }, - { "noashh_AR", "029d93ef78197dc93892d2a30e5a54865f41e0ca3ab7eb8e3dcbc59c8756b6e355" }, // 40 - { "noashh_EU", "02061c6278b91fd4ac5cab4401100ffa3b2d5a277e8f71db23401cc071b3665546" }, - { "noashh_NA", "033c073366152b6b01535e15dd966a3a8039169584d06e27d92a69889b720d44e1" }, - { "nxtswe_EU", "032fb104e5eaa704a38a52c126af8f67e870d70f82977e5b2f093d5c1c21ae5899" }, - { "polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, - { "pondsea_AR", "032e1c213787312099158f2d74a89e8240a991d162d4ce8017d8504d1d7004f735" }, - { "pondsea_EU", "0225aa6f6f19e543180b31153d9e6d55d41bc7ec2ba191fd29f19a2f973544e29d" }, - { "pondsea_NA", "031bcfdbb62268e2ff8dfffeb9ddff7fe95fca46778c77eebff9c3829dfa1bb411" }, - { "pondsea_SH", "02209073bc0943451498de57f802650311b1f12aa6deffcd893da198a544c04f36" }, - { "popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, - { "popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, // 50 - { "ptytrader_NA", "0328c61467148b207400b23875234f8a825cce65b9c4c9b664f47410b8b8e3c222" }, - { "ptytrader_SH", "0250c93c492d8d5a6b565b90c22bee07c2d8701d6118c6267e99a4efd3c7748fa4" }, - { "rnr_AR", "029bdb08f931c0e98c2c4ba4ef45c8e33a34168cb2e6bf953cef335c359d77bfcd" }, - { "rnr_EU", "03f5c08dadffa0ffcafb8dd7ffc38c22887bd02702a6c9ac3440deddcf2837692b" }, - { "rnr_NA", "02e17c5f8c3c80f584ed343b8dcfa6d710dfef0889ec1e7728ce45ce559347c58c" }, - { "rnr_SH", "037536fb9bdfed10251f71543fb42679e7c52308bcd12146b2568b9a818d8b8377" }, - { "titomane_AR", "03cda6ca5c2d02db201488a54a548dbfc10533bdc275d5ea11928e8d6ab33c2185" }, - { "titomane_EU", "02e41feded94f0cc59f55f82f3c2c005d41da024e9a805b41105207ef89aa4bfbd" }, - { "titomane_SH", "035f49d7a308dd9a209e894321f010d21b7793461b0c89d6d9231a3fe5f68d9960" }, - { "vanbreuk_EU", "024f3cad7601d2399c131fd070e797d9cd8533868685ddbe515daa53c2e26004c3" }, // 60 - { "xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, - { "xxspot1_XX", "02ef445a392fcaf3ad4176a5da7f43580e8056594e003eba6559a713711a27f955" }, - { "xxspot2_XX", "03d85b221ea72ebcd25373e7961f4983d12add66a92f899deaf07bab1d8b6f5573" } - }, - { - {"0dev1_jl777", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, - {"0dev2_kolo", "030f34af4b908fb8eb2099accb56b8d157d49f6cfb691baa80fdd34f385efed961" }, - {"0dev3_kolo", "025af9d2b2a05338478159e9ac84543968fd18c45fd9307866b56f33898653b014" }, - {"0dev4_decker", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, - {"a-team_SH", "03b59ad322b17cb94080dc8e6dc10a0a865de6d47c16fb5b1a0b5f77f9507f3cce" }, - {"artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, - {"artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, - {"artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, - {"artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, - {"badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, - {"badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, // 10 - {"batman_AR", "033ecb640ec5852f42be24c3bf33ca123fb32ced134bed6aa2ba249cf31b0f2563" }, - {"batman_SH", "02ca5898931181d0b8aafc75ef56fce9c43656c0b6c9f64306e7c8542f6207018c" }, - {"ca333_EU", "03fc87b8c804f12a6bd18efd43b0ba2828e4e38834f6b44c0bfee19f966a12ba99" }, - {"chainmakers_EU", "02f3b08938a7f8d2609d567aebc4989eeded6e2e880c058fdf092c5da82c3bc5ee" }, - {"chainmakers_NA", "0276c6d1c65abc64c8559710b8aff4b9e33787072d3dda4ec9a47b30da0725f57a" }, - {"chainstrike_SH", "0370bcf10575d8fb0291afad7bf3a76929734f888228bc49e35c5c49b336002153" }, - {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, - {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, - {"crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, - {"crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, // 20 - {"dwy_EU", "0259c646288580221fdf0e92dbeecaee214504fdc8bbdf4a3019d6ec18b7540424" }, - {"emmanux_SH", "033f316114d950497fc1d9348f03770cd420f14f662ab2db6172df44c389a2667a" }, - {"etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, - {"fullmoon_AR", "03380314c4f42fa854df8c471618751879f9e8f0ff5dbabda2bd77d0f96cb35676" }, - {"fullmoon_NA", "030216211d8e2a48bae9e5d7eb3a42ca2b7aae8770979a791f883869aea2fa6eef" }, - {"fullmoon_SH", "03f34282fa57ecc7aba8afaf66c30099b5601e98dcbfd0d8a58c86c20d8b692c64" }, - {"goldenman_EU", "02d6f13a8f745921cdb811e32237bb98950af1a5952be7b3d429abd9152f8e388d" }, - {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, - {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, - {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, // 30 - {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, - {"jackson_AR", "038ff7cfe34cb13b524e0941d5cf710beca2ffb7e05ddf15ced7d4f14fbb0a6f69" }, - {"jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, - {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, - {"komodoninja_EU", "038e567b99806b200b267b27bbca2abf6a3e8576406df5f872e3b38d30843cd5ba" }, - {"komodoninja_SH", "033178586896915e8456ebf407b1915351a617f46984001790f0cce3d6f3ada5c2" }, - {"komodopioneers_SH", "033ace50aedf8df70035b962a805431363a61cc4e69d99d90726a2d48fb195f68c" }, - {"libscott_SH", "03301a8248d41bc5dc926088a8cf31b65e2daf49eed7eb26af4fb03aae19682b95" }, - {"lukechilds_AR", "031aa66313ee024bbee8c17915cf7d105656d0ace5b4a43a3ab5eae1e14ec02696" }, - {"madmax_AR", "03891555b4a4393d655bf76f0ad0fb74e5159a615b6925907678edc2aac5e06a75" }, // 40 - {"meshbits_AR", "02957fd48ae6cb361b8a28cdb1b8ccf5067ff68eb1f90cba7df5f7934ed8eb4b2c" }, - {"meshbits_SH", "025c6e94877515dfd7b05682b9cc2fe4a49e076efe291e54fcec3add78183c1edb" }, - {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, - {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, - {"patchkez_SH", "0296270f394140640f8fa15684fc11255371abb6b9f253416ea2734e34607799c4" }, - {"pbca26_NA", "0276aca53a058556c485bbb60bdc54b600efe402a8b97f0341a7c04803ce204cb5" }, - {"peer2cloud_AR", "034e5563cb885999ae1530bd66fab728e580016629e8377579493b386bf6cebb15" }, - {"peer2cloud_SH", "03396ac453b3f23e20f30d4793c5b8ab6ded6993242df4f09fd91eb9a4f8aede84" }, - {"polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, - {"hyper_AR", "020f2f984d522051bd5247b61b080b4374a7ab389d959408313e8062acad3266b4" }, // 50 - {"hyper_EU", "03d00cf9ceace209c59fb013e112a786ad583d7de5ca45b1e0df3b4023bb14bf51" }, - {"hyper_SH", "0383d0b37f59f4ee5e3e98a47e461c861d49d0d90c80e9e16f7e63686a2dc071f3" }, - {"hyper_NA", "03d91c43230336c0d4b769c9c940145a8c53168bf62e34d1bccd7f6cfc7e5592de" }, - {"popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, - {"popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, - {"alien_AR", "0348d9b1fc6acf81290405580f525ee49b4749ed4637b51a28b18caa26543b20f0" }, - {"alien_EU", "020aab8308d4df375a846a9e3b1c7e99597b90497efa021d50bcf1bbba23246527" }, - {"thegaltmines_NA", "031bea28bec98b6380958a493a703ddc3353d7b05eb452109a773eefd15a32e421" }, - {"titomane_AR", "029d19215440d8cb9cc6c6b7a4744ae7fb9fb18d986e371b06aeb34b64845f9325" }, - {"titomane_EU", "0360b4805d885ff596f94312eed3e4e17cb56aa8077c6dd78d905f8de89da9499f" }, // 60 - {"titomane_SH", "03573713c5b20c1e682a2e8c0f8437625b3530f278e705af9b6614de29277a435b" }, - {"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" }, - {"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, - }, - { - {"madmax_NA", "0237e0d3268cebfa235958808db1efc20cc43b31100813b1f3e15cc5aa647ad2c3" }, // 0 - {"alright_AR", "020566fe2fb3874258b2d3cf1809a5d650e0edc7ba746fa5eec72750c5188c9cc9" }, - {"strob_NA", "0206f7a2e972d9dfef1c424c731503a0a27de1ba7a15a91a362dc7ec0d0fb47685" }, - {"dwy_EU", "021c7cf1f10c4dc39d13451123707ab780a741feedab6ac449766affe37515a29e" }, - {"phm87_SH", "021773a38db1bc3ede7f28142f901a161c7b7737875edbb40082a201c55dcf0add" }, - {"chainmakers_NA", "02285d813c30c0bf7eefdab1ff0a8ad08a07a0d26d8b95b3943ce814ac8e24d885" }, - {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, - {"blackjok3r_SH", "021eac26dbad256cbb6f74d41b10763183ee07fb609dbd03480dd50634170547cc" }, - {"chainmakers_EU", "03fdf5a3fce8db7dee89724e706059c32e5aa3f233a6b6cc256fea337f05e3dbf7" }, - {"titomane_AR", "023e3aa9834c46971ff3e7cb86a200ec9c8074a9566a3ea85d400d5739662ee989" }, - {"fullmoon_SH", "023b7252968ea8a955cd63b9e57dee45a74f2d7ba23b4e0595572138ad1fb42d21" }, // 10 - {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, - {"chmex_EU", "0281304ebbcc39e4f09fda85f4232dd8dacd668e20e5fc11fba6b985186c90086e" }, - {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, - {"ca333_DEV", "02856843af2d9457b5b1c907068bef6077ea0904cc8bd4df1ced013f64bf267958" }, - {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, - {"pungocloud_SH", "024dfc76fa1f19b892be9d06e985d0c411e60dbbeb36bd100af9892a39555018f6" }, - {"voskcoin_EU", "034190b1c062a04124ad15b0fa56dfdf34aa06c164c7163b6aec0d654e5f118afb" }, - {"decker_DEV", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, - {"cryptoeconomy_EU", "0290ab4937e85246e048552df3e9a66cba2c1602db76e03763e16c671e750145d1" }, - {"etszombi_EU", "0293ea48d8841af7a419a24d9da11c34b39127ef041f847651bae6ab14dcd1f6b4" }, // 20 - {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, - {"pirate_AR", "03e29c90354815a750db8ea9cb3c1b9550911bb205f83d0355a061ac47c4cf2fde" }, - {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, - {"zatjum_SH", "02d6b0c89cacd58a0af038139a9a90c9e02cd1e33803a1f15fceabea1f7e9c263a" }, - {"madmax_AR", "03c5941fe49d673c094bc8e9bb1a95766b4670c88be76d576e915daf2c30a454d3" }, - {"lukechilds_NA", "03f1051e62c2d280212481c62fe52aab0a5b23c95de5b8e9ad5f80d8af4277a64b" }, - {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, - {"tonyl_AR", "02cc8bc862f2b65ad4f99d5f68d3011c138bf517acdc8d4261166b0be8f64189e1" }, - {"infotech_DEV", "0345ad4ab5254782479f6322c369cec77a7535d2f2162d103d666917d5e4f30c4c" }, - {"fullmoon_NA", "032c716701fe3a6a3f90a97b9d874a9d6eedb066419209eed7060b0cc6b710c60b" }, // 30 - {"etszombi_AR", "02e55e104aa94f70cde68165d7df3e162d4410c76afd4643b161dea044aa6d06ce" }, - {"node-9_EU", "0372e5b51e86e2392bb15039bac0c8f975b852b45028a5e43b324c294e9f12e411" }, - {"phba2061_EU", "03f6bd15dba7e986f0c976ea19d8a9093cb7c989d499f1708a0386c5c5659e6c4e" }, - {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, - {"and1-89_EU", "02736cbf8d7b50835afd50a319f162dd4beffe65f2b1dc6b90e64b32c8e7849ddd" }, - {"komodopioneers_SH", "032a238a5747777da7e819cfa3c859f3677a2daf14e4dce50916fc65d00ad9c52a" }, - {"komodopioneers_EU", "036d02425916444fff8cc7203fcbfc155c956dda5ceb647505836bef59885b6866" }, - {"d0ct0r_NA", "0303725d8525b6f969122faf04152653eb4bf34e10de92182263321769c334bf58" }, - {"kolo_DEV", "02849e12199dcc27ba09c3902686d2ad0adcbfcee9d67520e9abbdda045ba83227" }, - {"peer2cloud_AR", "02acc001fe1fe8fd68685ba26c0bc245924cb592e10cec71e9917df98b0e9d7c37" }, // 40 - {"webworker01_SH", "031e50ba6de3c16f99d414bb89866e578d963a54bde7916c810608966fb5700776" }, - {"webworker01_NA", "032735e9cad1bb00eaababfa6d27864fa4c1db0300c85e01e52176be2ca6a243ce" }, - {"pbca26_NA", "03a97606153d52338bcffd1bf19bb69ef8ce5a7cbdc2dbc3ff4f89d91ea6bbb4dc" }, - {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, - {"pirate_NA", "0255e32d8a56671dee8aa7f717debb00efa7f0086ee802de0692f2d67ee3ee06ee" }, - {"lukechilds_AR", "025c6a73ff6d750b9ddf6755b390948cffdd00f344a639472d398dd5c6b4735d23" }, - {"dragonhound_NA", "0224a9d951d3a06d8e941cc7362b788bb1237bb0d56cc313e797eb027f37c2d375" }, - {"fullmoon_AR", "03da64dd7cd0db4c123c2f79d548a96095a5a103e5b9d956e9832865818ffa7872" }, - {"chainzilla_SH", "0360804b8817fd25ded6e9c0b50e3b0782ac666545b5416644198e18bc3903d9f9" }, - {"titomane_EU", "03772ac0aad6b0e9feec5e591bff5de6775d6132e888633e73d3ba896bdd8e0afb" }, // 50 - {"jeezy_EU", "037f182facbad35684a6e960699f5da4ba89e99f0d0d62a87e8400dd086c8e5dd7" }, - {"titomane_SH", "03850fdddf2413b51790daf51dd30823addb37313c8854b508ea6228205047ef9b" }, - {"alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f" }, - {"pirate_EU", "03fff24efd5648870a23badf46e26510e96d9e79ce281b27cfe963993039dd1351" }, - {"thegaltmines_NA", "02db1a16c7043f45d6033ccfbd0a51c2d789b32db428902f98b9e155cf0d7910ed" }, - {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4" }, - {"nutellalicka_SH", "02f7d90d0510c598ce45915e6372a9cd0ba72664cb65ce231f25d526fc3c5479fc" }, - {"chainstrike_SH", "03b806be3bf7a1f2f6290ec5c1ea7d3ea57774dcfcf2129a82b2569e585100e1cb" }, - {"dwy_SH", "036536d2d52d85f630b68b050f29ea1d7f90f3b42c10f8c5cdf3dbe1359af80aff" }, - {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd" }, // 60 - {"gt_AR", "0348430538a4944d3162bb4749d8c5ed51299c2434f3ee69c11a1f7815b3f46135" }, - {"patchkez_SH", "03f45e9beb5c4cd46525db8195eb05c1db84ae7ef3603566b3d775770eba3b96ee" }, - {"decker_AR", "03ffdf1a116300a78729608d9930742cd349f11a9d64fcc336b8f18592dd9c91bc" }, // 63 - }, - { - // Season 3.5 - {"madmax_NA", "0237e0d3268cebfa235958808db1efc20cc43b31100813b1f3e15cc5aa647ad2c3" }, // 0 - {"alright_AR", "020566fe2fb3874258b2d3cf1809a5d650e0edc7ba746fa5eec72750c5188c9cc9" }, - {"strob_NA", "0206f7a2e972d9dfef1c424c731503a0a27de1ba7a15a91a362dc7ec0d0fb47685" }, - {"hunter_EU", "0378224b4e9d8a0083ce36f2963ec0a4e231ec06b0c780de108e37f41181a89f6a" }, // FIXME verify this, kolo. Change name if you want - {"phm87_SH", "021773a38db1bc3ede7f28142f901a161c7b7737875edbb40082a201c55dcf0add" }, - {"chainmakers_NA", "02285d813c30c0bf7eefdab1ff0a8ad08a07a0d26d8b95b3943ce814ac8e24d885" }, - {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, - {"blackjok3r_SH", "021eac26dbad256cbb6f74d41b10763183ee07fb609dbd03480dd50634170547cc" }, - {"chainmakers_EU", "03fdf5a3fce8db7dee89724e706059c32e5aa3f233a6b6cc256fea337f05e3dbf7" }, - {"titomane_AR", "023e3aa9834c46971ff3e7cb86a200ec9c8074a9566a3ea85d400d5739662ee989" }, - {"fullmoon_SH", "023b7252968ea8a955cd63b9e57dee45a74f2d7ba23b4e0595572138ad1fb42d21" }, // 10 - {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, - {"chmex_EU", "0281304ebbcc39e4f09fda85f4232dd8dacd668e20e5fc11fba6b985186c90086e" }, - {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, - {"ca333_DEV", "02856843af2d9457b5b1c907068bef6077ea0904cc8bd4df1ced013f64bf267958" }, - {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, - {"pungocloud_SH", "024dfc76fa1f19b892be9d06e985d0c411e60dbbeb36bd100af9892a39555018f6" }, - {"voskcoin_EU", "034190b1c062a04124ad15b0fa56dfdf34aa06c164c7163b6aec0d654e5f118afb" }, - {"decker_DEV", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, - {"cryptoeconomy_EU", "0290ab4937e85246e048552df3e9a66cba2c1602db76e03763e16c671e750145d1" }, - {"etszombi_EU", "0293ea48d8841af7a419a24d9da11c34b39127ef041f847651bae6ab14dcd1f6b4" }, // 20 - {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, - {"pirate_AR", "03e29c90354815a750db8ea9cb3c1b9550911bb205f83d0355a061ac47c4cf2fde" }, - {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, - {"zatjum_SH", "02d6b0c89cacd58a0af038139a9a90c9e02cd1e33803a1f15fceabea1f7e9c263a" }, - {"madmax_AR", "03c5941fe49d673c094bc8e9bb1a95766b4670c88be76d576e915daf2c30a454d3" }, - {"lukechilds_NA", "03f1051e62c2d280212481c62fe52aab0a5b23c95de5b8e9ad5f80d8af4277a64b" }, - {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, - {"tonyl_AR", "02cc8bc862f2b65ad4f99d5f68d3011c138bf517acdc8d4261166b0be8f64189e1" }, - {"infotech_DEV", "0345ad4ab5254782479f6322c369cec77a7535d2f2162d103d666917d5e4f30c4c" }, - {"fullmoon_NA", "032c716701fe3a6a3f90a97b9d874a9d6eedb066419209eed7060b0cc6b710c60b" }, // 30 - {"etszombi_AR", "02e55e104aa94f70cde68165d7df3e162d4410c76afd4643b161dea044aa6d06ce" }, - {"node-9_EU", "0372e5b51e86e2392bb15039bac0c8f975b852b45028a5e43b324c294e9f12e411" }, - {"phba2061_EU", "03f6bd15dba7e986f0c976ea19d8a9093cb7c989d499f1708a0386c5c5659e6c4e" }, - {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, - {"and1-89_EU", "02736cbf8d7b50835afd50a319f162dd4beffe65f2b1dc6b90e64b32c8e7849ddd" }, - {"komodopioneers_SH", "032a238a5747777da7e819cfa3c859f3677a2daf14e4dce50916fc65d00ad9c52a" }, - {"komodopioneers_EU", "036d02425916444fff8cc7203fcbfc155c956dda5ceb647505836bef59885b6866" }, - {"d0ct0r_NA", "0303725d8525b6f969122faf04152653eb4bf34e10de92182263321769c334bf58" }, - {"kolo_DEV", "02849e12199dcc27ba09c3902686d2ad0adcbfcee9d67520e9abbdda045ba83227" }, - {"peer2cloud_AR", "02acc001fe1fe8fd68685ba26c0bc245924cb592e10cec71e9917df98b0e9d7c37" }, // 40 - {"webworker01_SH", "031e50ba6de3c16f99d414bb89866e578d963a54bde7916c810608966fb5700776" }, - {"webworker01_NA", "032735e9cad1bb00eaababfa6d27864fa4c1db0300c85e01e52176be2ca6a243ce" }, - {"pbca26_NA", "03a97606153d52338bcffd1bf19bb69ef8ce5a7cbdc2dbc3ff4f89d91ea6bbb4dc" }, - {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, - {"pirate_NA", "0255e32d8a56671dee8aa7f717debb00efa7f0086ee802de0692f2d67ee3ee06ee" }, - {"lukechilds_AR", "025c6a73ff6d750b9ddf6755b390948cffdd00f344a639472d398dd5c6b4735d23" }, - {"dragonhound_NA", "0224a9d951d3a06d8e941cc7362b788bb1237bb0d56cc313e797eb027f37c2d375" }, - {"fullmoon_AR", "03da64dd7cd0db4c123c2f79d548a96095a5a103e5b9d956e9832865818ffa7872" }, - {"chainzilla_SH", "0360804b8817fd25ded6e9c0b50e3b0782ac666545b5416644198e18bc3903d9f9" }, - {"titomane_EU", "03772ac0aad6b0e9feec5e591bff5de6775d6132e888633e73d3ba896bdd8e0afb" }, // 50 - {"jeezy_EU", "037f182facbad35684a6e960699f5da4ba89e99f0d0d62a87e8400dd086c8e5dd7" }, - {"titomane_SH", "03850fdddf2413b51790daf51dd30823addb37313c8854b508ea6228205047ef9b" }, - {"alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f" }, - {"pirate_EU", "03fff24efd5648870a23badf46e26510e96d9e79ce281b27cfe963993039dd1351" }, - {"thegaltmines_NA", "02db1a16c7043f45d6033ccfbd0a51c2d789b32db428902f98b9e155cf0d7910ed" }, - {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4" }, - {"nutellalicka_SH", "02f7d90d0510c598ce45915e6372a9cd0ba72664cb65ce231f25d526fc3c5479fc" }, - {"chainstrike_SH", "03b806be3bf7a1f2f6290ec5c1ea7d3ea57774dcfcf2129a82b2569e585100e1cb" }, - {"hunter_SH", "02407db70ad30ce4dfaee8b4ae35fae88390cad2b0ba0373fdd6231967537ccfdf" }, - {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd" }, // 60 - {"gt_AR", "0348430538a4944d3162bb4749d8c5ed51299c2434f3ee69c11a1f7815b3f46135" }, - {"patchkez_SH", "03f45e9beb5c4cd46525db8195eb05c1db84ae7ef3603566b3d775770eba3b96ee" }, - {"decker_AR", "03ffdf1a116300a78729608d9930742cd349f11a9d64fcc336b8f18592dd9c91bc" }, // 63 - }, - { - // Season 4 - { "alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f" }, - { "alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd" }, - { "strob_NA", "02a1c0bd40b294f06d3e44a52d1b2746c260c475c725e9351f1312e49e01c9a405" }, - { "titomane_SH", "020014ad4eedf6b1aeb0ad3b101a58d0a2fc570719e46530fd98d4e585f63eb4ae" }, - { "fullmoon_AR", "03b251095e747f759505ec745a4bbff9a768b8dce1f65137300b7c21efec01a07a" }, - { "phba2061_EU", "03a9492d2a1601d0d98cfe94d8adf9689d1bb0e600088127a4f6ca937761fb1c66" }, - { "fullmoon_NA", "03931c1d654a99658998ce0ddae108d825943a821d1cddd85e948ac1d483f68fb6" }, - { "fullmoon_SH", "03c2a1ed9ddb7bb8344328946017b9d8d1357b898957dd6aaa8c190ae26740b9ff" }, - { "madmax_AR", "022be5a2829fa0291f9a51ff7aeceef702eef581f2611887c195e29da49092e6de" }, - { "titomane_EU", "0285cf1fdba761daf6f1f611c32d319cd58214972ef822793008b69dde239443dd" }, - { "cipi_NA", "022c6825a24792cc3b010b1531521eba9b5e2662d640ed700fd96167df37e75239" }, - { "indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, - { "decker_AR", "03ffdf1a116300a78729608d9930742cd349f11a9d64fcc336b8f18592dd9c91bc" }, - { "indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, - { "madmax_NA", "02997b7ab21b86bbea558ae79acc35d62c9cedf441578f78112f986d72e8eece08" }, - { "chainzilla_SH", "02288ba6dc57936b59d60345e397d62f5d7e7d975f34ed5c2f2e23288325661563" }, - { "peer2cloud_AR", "0250e7e43a3535731b051d1bcc7dc88fbb5163c3fe41c5dee72bd973bcc4dca9f2" }, - { "pirate_EU", "0231c0f50a06655c3d2edf8d7e722d290195d49c78d50de7786b9d196e8820c848" }, - { "webworker01_NA", "02dfd5f3cef1142879a7250752feb91ddd722c497fb98c7377c0fcc5ccc201bd55" }, - { "zatjum_SH", "036066fd638b10e555597623e97e032b28b4d1fa5a13c2b0c80c420dbddad236c2" }, - { "titomane_AR", "0268203a4c80047edcd66385c22e764ea5fb8bc42edae389a438156e7dca9a8251" }, - { "chmex_EU", "025b7209ba37df8d9695a23ea706ea2594863ab09055ca6bf485855937f3321d1d" }, - { "indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, - { "patchkez_SH", "02cabd6c5fc0b5476c7a01e9d7b907e9f0a051d7f4f731959955d3f6b18ee9a242" }, - { "metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, - { "etszombi_EU", "0341adbf238f33a33cc895633db996c3ad01275313ac6641e046a3db0b27f1c880" }, - { "pirate_NA", "02207f27a13625a0b8caef6a7bb9de613ff16e4a5f232da8d7c235c7c5bad72ffe" }, - { "metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, - { "indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, - { "chainmakers_NA", "029415a1609c33dfe4a1016877ba35f9265d25d737649f307048efe96e76512877" }, - { "mihailo_EU", "037f9563f30c609b19fd435a19b8bde7d6db703012ba1aba72e9f42a87366d1941" }, - { "tonyl_AR", "0299684d7291abf90975fa493bf53212cf1456c374aa36f83cc94daece89350ae9" }, - { "alien_NA", "03bea1ac333b95c8669ec091907ea8713cae26f74b9e886e13593400e21c4d30a8" }, - { "pungocloud_SH", "025b97d8c23effaca6fa7efacce20bf54df73081b63004a0fe22f3f98fece5669f" }, - { "node9_EU", "029ffa793b5c3248f8ea3da47fa3cf1810dada5af032ecd0e37bab5b92dd63b34e" }, - { "smdmitry_AR", "022a2a45979a6631a25e4c96469423de720a2f4c849548957c35a35c91041ee7ac" }, - { "nodeone_NA", "03f9dd0484e81174fd50775cb9099691c7d140ff00c0f088847e38dc87da67eb9b" }, - { "gcharang_SH", "02ec4172eab854a0d8cd32bc691c83e93975a3df5a4a453a866736c56e025dc359" }, - { "cipi_EU", "02f2b6defff1c544202f66e47cfd6909c54d67c7c39b9c2a99f137dbaf6d0bd8fa" }, - { "etszombi_AR", "0329944b0ac65b6760787ede042a2fde0be9fca1d80dd756bc0ee0b98d389b7682" }, - { "pbca26_NA", "0387e0fb6f2ca951154c87e16c6cbf93a69862bb165c1a96bcd8722b3af24fe533" }, - { "mylo_SH", "03b58f57822e90fe105e6efb63fd8666033ea503d6cc165b1e479bbd8c2ba033e8" }, - { "swisscertifiers_EU", "03ebcc71b42d88994b8b2134bcde6cb269bd7e71a9dd7616371d9294ec1c1902c5" }, - { "marmarachain_AR", "035bbd81a098172592fe97f50a0ce13cbbf80e55cc7862eccdbd7310fab8a90c4c" }, - { "karasugoi_NA", "0262cf2559703464151153c12e00c4b67a969e39b330301fdcaa6667d7eb02c57d" }, - { "phm87_SH", "021773a38db1bc3ede7f28142f901a161c7b7737875edbb40082a201c55dcf0add" }, - { "oszy_EU", "03d1ffd680491b98a3ec5541715681d1a45293c8efb1722c32392a1d792622596a" }, - { "chmex_AR", "036c856ea778ea105b93c0be187004d4e51161eda32888aa307b8f72d490884005" }, - { "dragonhound_NA", "0227e5cad3731e381df157de189527aac8eb50d82a13ce2bd81153984ebc749515" }, - { "strob_SH", "025ceac4256cef83ca4b110f837a71d70a5a977ecfdf807335e00bc78b560d451a" }, - { "madmax_EU", "02ea0cf4d6d151d0528b07efa79cc7403d77cb9195e2e6c8374f5074b9a787e287" }, - { "dudezmobi_AR", "027ecd974ff2a27a37ee69956cd2e6bb31a608116206f3e31ef186823420182450" }, - { "daemonfox_NA", "022d6f4885f53cbd668ad7d03d4f8e830c233f74e3a918da1ed247edfc71820b3d" }, - { "nutellalicka_SH", "02f4b1e71bc865a79c05fe333952b97cb040d8925d13e83925e170188b3011269b" }, - { "starfleet_EU", "025c7275bd750936862b47793f1f0bb3cbed60fb75a48e7da016e557925fe375eb" }, - { "mrlynch_AR", "031987dc82b087cd53e23df5480e265a5928e9243e0e11849fa12359739d8b18a4" }, - { "greer_NA", "03e0995615d7d3cf1107effa6bdb1133e0876cf1768e923aa533a4e2ee675ec383" }, - { "mcrypt_SH", "025faab3cc2e83bf7dad6a9463cbff86c08800e937942126f258cf219bc2320043" }, - { "decker_EU", "03777777caebce56e17ca3aae4e16374335b156f1dd62ee3c7f8799c6b885f5560" }, - { "dappvader_SH", "02962e2e5af746632016bc7b24d444f7c90141a5f42ce54e361b302cf455d90e6a" }, - { "alright_DEV", "02b73a589d61691efa2ada15c006d27bc18493fea867ce6c14db3d3d28751f8ce3" }, - { "artemii235_DEV", "03bb616b12430bdd0483653de18733597a4fd416623c7065c0e21fe9d96460add1" }, - { "tonyl_DEV", "02d5f7fd6e25d34ab2f3318d60cdb89ff3a812ec5d0212c4c113bb12d12616cfdc" }, - { "decker_DEV", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" } - }, - { - // Season 5 - {"alrighttt_DEV", "03483166d8663beeb48a493eec161bf506df1906153b6259f7ca617e4cb8110260"}, // 0 - {"alien_AR", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f"}, - {"artempikulin_AR", "026a8ed1e4eeeb023cfb8e003e1c1de6a2b771f37e112745ffb8b6e375a9cbfdec"}, - {"chmex_AR", "036c856ea778ea105b93c0be187004d4e51161eda32888aa307b8f72d490884005"}, - {"cipi_AR", "033ae024cdb748e083406a2e20037017a1292079ad6a8161ae5b43f398724fea74"}, - {"shadowbit_AR", "02909c79a198179c193fb85bbd4ba09b875a5a9bd481fec284658188b96ed43519"}, - {"goldenman_AR", "0345b888e5de9c11871c080212ccaebf8a3d77b05fe3d535336efc5c7df334bbc7"}, - {"kolo_AR", "0281d3c7bf067088b9572b4d906afca2083a71a38b1011878ecd347651d00af433"}, - {"madmax_AR", "02f729b8df4dacdc8d811416eb32e98a5cc37023b42c81b77d1c00881de879a99a"}, - {"mcrypt_AR", "029bdb33b08f96524082490f4373bc6026b92bcaef9bc521a840a799c73b75ed80"}, - {"mrlynch_AR", "031987dc82b087cd53e23df5480e265a5928e9243e0e11849fa12359739d8b18a4"}, // 10 - {"ocean_AR", "03c2bc8c57a001a788851fedc33ce72797ee8fe26eaa3abb1b807727e4867a3105"}, - {"smdmitry_AR", "022a2a45979a6631a25e4c96469423de720a2f4c849548957c35a35c91041ee7ac"}, - {"tokel_AR", "03f3bf697173e47de7bae2ae02b3d3bcf28133a47db72f2a0266061597aaa7779d"}, - {"tonyl_AR", "029ad03929ec295e9164e2bfb9f0e0102c280d5e5212503d079d2d99ab492a9106"}, - {"tonyl_DEV", "02342ec82b31a016b71cd1eb2f482a74f63172e1029ba2fb18f0def3bd4fc0668a"}, - {"artem_DEV", "036b9848396ddcdb9bb58ddab2c24b710b8e4e9b0ee084a00518505ecd9e9fe174"}, - {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd"}, - {"alienx_EU", "026afe5b112d1b39e0edafd5e051e261a676104460581f3673f26ceff7f1e6c56c"}, - {"ca333_EU", "03ffb8072f78304c42ae9b60435f6c3296cbc72de129ae49bba175a65c31c9a7e2"}, - {"chmex_EU", "025b7209ba37df8d9695a23ea706ea2594863ab09055ca6bf485855937f3321d1d"}, // 20 - {"cipi_EU", "03d6e1f3a693b5d69049791005d7cb64c259a1ad85833f5a9c545d4fee29905009"}, - {"cipi2_EU", "0202e430157486503f4bde3d3ca770c8f1e2447cf480a6b273b5265b9620f585e3"}, - {"shadowbit_EU", "02668f5f723584f97f5e6f9196fc31018f36a6cf824c60328ad0c097a785df4745"}, - {"komodopioneers_EU", "0351f7f2a6ecce863e4e774bfafe2e59e151c08bf8f350286763a6b8ed97274b82"}, - {"madmax_EU", "028d04f7ccae0d9d57bfa801c4f1e32c707c17589b3c08a0ce08d44eab637eb66b"}, - {"marmarachain_EU", "023a858bbc3f0c6df5b74243315028e968c2f299d84ea8ecc0b28b5f0e2ad24c3c"}, - {"node-9_EU", "03c375924aac39d0c49de6690199e4d08d10fed6725988dcf5d2486661b5e3a656"}, - {"slyris_EU", "021cb6365c13cb35aad4b70aa18b63a75d1d4b9797a0754d3d0142d6fedc83b24e"}, - {"smdmitry_EU", "02eb3aad81778f8d6f7e5295c44ca224e5c812f5e43fc1e9ce4ebafc23324183c9"}, - {"van_EU", "03af7f8c82f20671ca1978116353839d3e501523e379bfb52b1e05d7816bb5812f"}, // 30 - {"shadowbit_DEV", "02ca882f153e715091a2dbc5409096f8c109d9fe6506ca7a918056dd37162b6f6e"}, - {"gcharang_DEV", "02cb445948bf0d89f8d61102e12a5ee6e98be61ac7c2cb9ba435219ea9db967117"}, - {"alien_NA", "03bea1ac333b95c8669ec091907ea8713cae26f74b9e886e13593400e21c4d30a8"}, - {"alienx_NA", "02f0b3ef87629509441b1ae95f28108f258a81910e483b90e0496205e24e7069b8"}, - {"cipi_NA", "036cc1d7476e4260601927be0fc8b748ae68d8fec8f5c498f71569a01bd92046c5"}, - {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4"}, - {"dragonhound_NA", "02e650819f4d1cabeaad6bc5ec8c0722a89e63059a10f8b5e97c983c321608329b"}, - {"hyper_NA", "030994a303b26df6e7c6ed456f069c5de9e200e1380bebc5ed8ebe0f834f477f3d"}, - {"madmax_NA", "03898aec46014e8619e2369cc85073048dad05d3c5bf696d8b524db78a39ae5beb"}, - {"node-9_NA", "02f697eed99fd21f2f0eaad81d13543a75c576f669bfddbcbeef0f7625fea2e9d5"}, // 40 - {"nodeone_NA", "03f9dd0484e81174fd50775cb9099691c7d140ff00c0f088847e38dc87da67eb9b"}, - {"pbca26_NA", "0332543ff1287604afd67f63af0aa0b263aef14fe1850b85db16b81462eed834fd"}, - {"ptyx_NA", "02cbda9c43a794f2134a11815fe86dca017990269accb139e962d764c011c9a4d7"}, - {"strob_NA", "02a1c0bd40b294f06d3e44a52d1b2746c260c475c725e9351f1312e49e01c9a405"}, - {"karasugoi_NA", "0262cf2559703464151153c12e00c4b67a969e39b330301fdcaa6667d7eb02c57d"}, - {"webworker01_NA", "0376558d13c31cf9c664a1b5e58f4fff7153777069bef7a66ed8c8526b99787a9e"}, - {"yurii_DEV", "03e57c7341d2c8a3be62e1caaa28978d76a8277dea7bb484fdd8c55dc05e4e4e93"}, - {"ca333_DEV", "03d885e292842912bd990299ebce33451a5a01cb14e4874d90770efb22e82ef40f"}, - {"chmex_SH", "02698305eb3c27a2c724efd2152f9250739355116f201656c34b83aac2d3aebd19"}, - {"collider_SH", "03bd0022a55a2ead52fd65b317186743374ad320f3704d459f41797e264d1ec854"}, // 50 - {"dappvader_SH", "02bffea7911e09ad9a7df54af0c225516478d3ba138e65061aa8d4b9756bb4c8f4"}, - {"drkush_SH", "030b31cc9528566422e25f3e9b96541ab3626c0dea0e7aa3c0b0bd96039eae2f5a"}, - {"majora31_SH", "033bf21f039a1c832effad208d564e02e968f11e3a3aa41c42e3b748a232fb33f3"}, - {"mcrypt_SH", "025faab3cc2e83bf7dad6a9463cbff86c08800e937942126f258cf219bc2320043"}, - {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309"}, - {"mylo_SH", "03458dca36e800d5bc121d8c0d35f9fc6282880a79fee2d7e050f887b797bc7d6e"}, - {"nutellaLicka_SH", "03a495962a9e9eca06ee3b8ab4cd94e6ea0d87dd39d334ad85a524c4fece1a3db7"}, - {"pbca26_SH", "02c62877e96fc414f2444edf0601abff9d5d2f9078e49fa867ba5305f3c5b3beb0"}, - {"phit_SH", "02a9cef2141fb2af24349c1eea20f5fa8f5dba2835723778d19b23353ddcd877b1"}, - {"sheeba_SH", "03e6578015b7f0ab78a486070435031fff7bae11256ca6a9f3d358ab03029737cb"}, // 60 - {"strob_SH", "025ceac4256cef83ca4b110f837a71d70a5a977ecfdf807335e00bc78b560d451a"}, - {"strobnidan_SH", "02b967fde3686d45056343e488997d4c53f25cd7ad38548cd12b136010a09295ae"}, - {"dragonhound_DEV", "038e010c33c56b61389409eea5597fe17967398731e23185c84c472a16fc5d34ab"} - }, - { - // Season 6 - {"blackice_DEV", "02ca882f153e715091a2dbc5409096f8c109d9fe6506ca7a918056dd37162b6f6e"}, // 0 - {"blackice_AR", "02909c79a198179c193fb85bbd4ba09b875a5a9bd481fec284658188b96ed43519"}, - {"alien_EU", "03bb749e337b9074465fa28e757b5aa92cb1f0fea1a39589bca91a602834d443cd"}, - {"alien_NA", "03bea1ac333b95c8669ec091907ea8713cae26f74b9e886e13593400e21c4d30a8"}, - {"alien_SH", "03911a60395801082194b6834244fa78a3c30ff3e888667498e157b4aa80b0a65f"}, - {"alienx_EU", "026afe5b112d1b39e0edafd5e051e261a676104460581f3673f26ceff7f1e6c56c"}, - {"alienx_NA", "02f0b3ef87629509441b1ae95f28108f258a81910e483b90e0496205e24e7069b8"}, - {"artem.pikulin_AR", "026a8ed1e4eeeb023cfb8e003e1c1de6a2b771f37e112745ffb8b6e375a9cbfdec"}, - {"artem.pikulin_DEV", "036b9848396ddcdb9bb58ddab2c24b710b8e4e9b0ee084a00518505ecd9e9fe174"}, - {"blackice_EU", "02668f5f723584f97f5e6f9196fc31018f36a6cf824c60328ad0c097a785df4745"}, - {"chmex_AR", "036c856ea778ea105b93c0be187004d4e51161eda32888aa307b8f72d490884005"}, // 10 - {"chmex_EU", "025b7209ba37df8d9695a23ea706ea2594863ab09055ca6bf485855937f3321d1d"}, - {"chmex_NA", "030c2528c29d5328243c910277e3d74aa77c9b4e145308007d2b11550731591dbe"}, - {"chmex_SH", "02698305eb3c27a2c724efd2152f9250739355116f201656c34b83aac2d3aebd19"}, - {"chmex1_SH", "02d27ed1cddfbaff9e47865e7df0165457e8f075f70bbea8c0498598ccf494555d"}, - {"cipi_1_EU", "03d6e1f3a693b5d69049791005d7cb64c259a1ad85833f5a9c545d4fee29905009"}, - {"cipi_2_EU", "0202e430157486503f4bde3d3ca770c8f1e2447cf480a6b273b5265b9620f585e3"}, - {"cipi_AR", "033ae024cdb748e083406a2e20037017a1292079ad6a8161ae5b43f398724fea74"}, - {"cipi_NA", "036cc1d7476e4260601927be0fc8b748ae68d8fec8f5c498f71569a01bd92046c5"}, - {"computergenie_EU", "03a8c071036228e0900e0171f616ce1a58f0a761193551d68c4c20e70534f2e183"}, - {"computergenie_NA", "03a78ae070a5e9e935112cf7ea8293f18950f1011694ea0260799e8762c8a6f0a4"}, // 20 - {"dimxy_AR", "02689d0b77b1e8e8c93a102d8b689fd08179164d70e2dd585543c3896a0916e6a1"}, - {"dimxy_DEV", "039a01cd626d5efbe7fd05a59d8e5fced53bacac589192278f9b00ad31654b6956"}, - {"dragonhound_NA", "02e650819f4d1cabeaad6bc5ec8c0722a89e63059a10f8b5e97c983c321608329b"}, - {"fediakash_AR", "027dfe5403f8870fb0e1b94a2b4204373b31ea73179ba500a88dd56d22855cd03b"}, - {"gcharang_DEV", "033b82b5791c65477dd11095cf33332013df6d2bcb7aa06a6dae5f7b22b6959b0b"}, - {"gcharang_SH", "02cb445948bf0d89f8d61102e12a5ee6e98be61ac7c2cb9ba435219ea9db967117"}, - {"goldenman_AR", "02c11f651df6a03f1a17b9ea0b1a73c0acca7aeacd4081e09bd7dd939690af8ae1"}, - {"kolo_AR", "028431645f923a9e383a4e37cbb7168fa34988da23d43097124fe882bdac6d175f"}, - {"kolo_EU", "03e1287d4c14ad73ce9ddd31361a7de8df4eeeefe9460a1ff9a6b2a1242ad3b7c2"}, - {"kolox_AR", "0289f5f64f4bb18d014c4e9f4c888f4da2b6518e88fd5b7768728c38177b66d305"}, // 30 - {"komodopioneers_EU", "0351f7f2a6ecce863e4e774bfafe2e59e151c08bf8f350286763a6b8ed97274b82"}, - {"madmax_DEV", "027100e6b3db2028034db651946ecde90e45be3799ebc310d39af4496772a850ad"}, - {"marmarachain_EU", "0234e40800500370d43979586ee2cec2e777a0368d10c682e78bca30fd1630c18d"}, - {"mcrypt_AR", "029bdb33b08f96524082490f4373bc6026b92bcaef9bc521a840a799c73b75ed80"}, - {"mcrypt_SH", "025faab3cc2e83bf7dad6a9463cbff86c08800e937942126f258cf219bc2320043"}, - {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309"}, - {"mylo_NA", "0365a778014c216401b6ba9c28eec88f116a9a9912e145ba2dbbd065d98b493af5"}, - {"mylo_SH", "03458dca36e800d5bc121d8c0d35f9fc6282880a79fee2d7e050f887b797bc7d6e"}, - {"nodeone_NA", "03f9dd0484e81174fd50775cb9099691c7d140ff00c0f088847e38dc87da67eb9b"}, - {"nutellalicka_AR", "0285be2518bf8d65fceaa5f4d8485002f90d3b7ff274b23bb925fd167128e19589"}, // 40 - {"nutellalicka_SH", "03a8b10c1f74af429fc43ab4eb722f6c2a88087f2d71703e7f0e8001207a966fb5"}, - {"ocean_AR", "03c2bc8c57a001a788851fedc33ce72797ee8fe26eaa3abb1b807727e4867a3105"}, - {"pbca26_NA", "03d8b25536da157d931b159a72c0eeaedb1bf7bb3eb2d02647fa41b2422a2b064e"}, - {"pbca26_SH", "039a55787b742c3725323f0bd81c90a484fbdbf276a16317883bb03eedd9d6aa7c"}, - {"phit_SH", "02a9cef2141fb2af24349c1eea20f5fa8f5dba2835723778d19b23353ddcd877b1"}, - {"ptyx_NA", "0395640e81359526ecbc140716ddd5c9a1ce2a697fb547ca896e17cad3c65e78db"}, - {"ptyx2_NA", "0225ff37e49e443065018736fbcad175ab5993b51b99b846e8de0b8b9abbed2ef2"}, - {"sheeba_SH", "03e6578015b7f0ab78a486070435031fff7bae11256ca6a9f3d358ab03029737cb"}, - {"smdmitry_AR", "022a2a45979a6631a25e4c96469423de720a2f4c849548957c35a35c91041ee7ac"}, - {"smdmitry_EU", "02eb3aad81778f8d6f7e5295c44ca224e5c812f5e43fc1e9ce4ebafc23324183c9"}, // 50 - {"smdmitry_SH", "02d01cd6b87cbf5a9795c06968f0d169168c1be0d82cfeb79958b11ae2c30316c1"}, - {"strob_SH", "025ceac4256cef83ca4b110f837a71d70a5a977ecfdf807335e00bc78b560d451a"}, - {"strobnidan_SH", "02b967fde3686d45056343e488997d4c53f25cd7ad38548cd12b136010a09295ae"}, - {"tokel_NA", "02b472713e87fb2560569857051ea0811c65d668a6fe73df165afe152417f774a0"}, - {"tonyl_AR", "029ad03929ec295e9164e2bfb9f0e0102c280d5e5212503d079d2d99ab492a9106"}, - {"tonyl_DEV", "02342ec82b31a016b71cd1eb2f482a74f63172e1029ba2fb18f0def3bd4fc0668a"}, - {"van_EU", "03af7f8c82f20671ca1978116353839d3e501523e379bfb52b1e05d7816bb5812f"}, - {"webworker01_EU", "0321d523645caffd8e762764ba56f7874a61b9bf534837a2cb6e7da219fab15eef"}, - {"webworker01_NA", "0287883ddd8da366401893ebcc1ff7e52d2ad3736984120a0ab01603e02c21dc98"}, - {"who-biz_NA", "02f91a6772fe1a376e2bbe4b190008e3f878d40a8eaf92c65f1a7680b6b42ea47b"}, // 60 - {"yurii-khi_DEV", "03e57c7341d2c8a3be62e1caaa28978d76a8277dea7bb484fdd8c55dc05e4e4e93"}, - {"ca333_EU", "021d6fbe67d12f492a01306c70ab096f8b8581eb5f958d3f5fe3588ae8c7797f42"}, - {"dragonhound_DEV", "038e010c33c56b61389409eea5597fe17967398731e23185c84c472a16fc5d34ab"} - } -}; - extern char NOTARYADDRS[64][64]; -extern char NOTARY_ADDRESSES[NUM_KMD_SEASONS][64][64]; \ No newline at end of file +extern char NOTARY_ADDRESSES[NUM_KMD_SEASONS][64][64]; + +extern const char *notaries_elected[NUM_KMD_SEASONS][NUM_KMD_NOTARIES][2]; diff --git a/src/komodo_notary.cpp b/src/komodo_notary.cpp index dec27f3abe1..19626b24629 100644 --- a/src/komodo_notary.cpp +++ b/src/komodo_notary.cpp @@ -81,17 +81,43 @@ int32_t getacseason(uint32_t timestamp) return(0); } +/*** + * Static variables to tell if something has been initialized + */ +static bool didinit_NOTARIES[NUM_KMD_SEASONS]; // komodo_notaries() +static int32_t hwmheight = 0; // komodo_notariesinit() +static bool didinit = false; // komodo_init() + +/***** + * 2 Helpers for unit tests that reset statics (among other things) + * DO NOT USE for anything other than unit tests + */ +void undo_init_STAKED(); // see notaries_staked.cpp +void undo_init_notaries() +{ + undo_init_STAKED(); + memset(didinit_NOTARIES, 0, NUM_KMD_SEASONS * sizeof(bool) ); + if (Pubkeys != nullptr) + { + free(Pubkeys); + Pubkeys = nullptr; + } + hwmheight = 0; + didinit = false; +} + int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp) { int32_t i,htind,n; uint64_t mask = 0; struct knotary_entry *kp,*tmp; - static uint8_t kmd_pubkeys[NUM_KMD_SEASONS][64][33],didinit[NUM_KMD_SEASONS]; + static uint8_t kmd_pubkeys[NUM_KMD_SEASONS][64][33]; if ( timestamp == 0 && ASSETCHAINS_SYMBOL[0] != 0 ) timestamp = komodo_heightstamp(height); else if ( ASSETCHAINS_SYMBOL[0] == 0 ) timestamp = 0; - // If this chain is not a staked chain, use the normal Komodo logic to determine notaries. This allows KMD to still sync and use its proper pubkeys for dPoW. + // If this chain is not a staked chain, use the normal Komodo logic to determine notaries. + // This allows KMD to still sync and use its proper pubkeys for dPoW. if ( is_STAKED(ASSETCHAINS_SYMBOL) == 0 ) { int32_t kmd_season = 0; @@ -108,7 +134,7 @@ int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestam } if ( kmd_season != 0 ) { - if ( didinit[kmd_season-1] == 0 ) + if ( !didinit_NOTARIES[kmd_season-1] ) { for (i=0; i= 0 ) @@ -462,7 +486,7 @@ void komodo_init(int32_t height) } komodo_notarysinit(0,pubkeys,k); } - didinit = 1; + didinit = true; komodo_stateupdate(0,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,zero,0); } } diff --git a/src/komodo_structs.cpp b/src/komodo_structs.cpp index 0e80667a309..3a68639f8ad 100644 --- a/src/komodo_structs.cpp +++ b/src/komodo_structs.cpp @@ -14,24 +14,6 @@ ******************************************************************************/ #include "komodo_structs.h" #include "mem_read.h" -#include - -extern std::mutex komodo_mutex; - -/*** - * komodo_state - */ - -bool komodo_state::add_event(const std::string& symbol, const uint32_t height, std::shared_ptr in) -{ - if (ASSETCHAINS_SYMBOL[0] != 0) - { - std::lock_guard lock(komodo_mutex); - events.push_back( in ); - return true; - } - return false; -} namespace komodo { @@ -96,8 +78,8 @@ std::ostream& operator<<(std::ostream& os, const event& in) break; case(EVENT_NOTARIZED): { - event_notarized* tmp = dynamic_cast(const_cast(&in)); - if (tmp->MoMdepth == 0) + const event_notarized& tmp = static_cast(in); + if (tmp.MoMdepth == 0) os << "N"; else os << "M"; @@ -108,8 +90,8 @@ std::ostream& operator<<(std::ostream& os, const event& in) break; case(EVENT_KMDHEIGHT): { - event_kmdheight* tmp = dynamic_cast(const_cast(&in)); - if (tmp->timestamp == 0) + const event_kmdheight& tmp = static_cast(in); + if (tmp.timestamp == 0) os << "K"; else os << "T"; @@ -152,11 +134,12 @@ event_pubkeys::event_pubkeys(FILE* fp, int32_t height) : event(EVENT_PUBKEYS, he std::ostream& operator<<(std::ostream& os, const event_pubkeys& in) { - const event& e = dynamic_cast(in); + const event& e = static_cast(in); os << e; os << in.num; - for(uint8_t i = 0; i < in.num-1; ++i) - os << in.pubkeys[i]; + for(uint8_t i = 0; i < in.num; ++i) + for(uint8_t j = 0; j < 33; ++j) + os << in.pubkeys[i][j]; return os; } @@ -166,7 +149,7 @@ event_rewind::event_rewind(uint8_t *data, long &pos, long data_len, int32_t heig } std::ostream& operator<<(std::ostream& os, const event_rewind& in) { - const event& e = dynamic_cast(in); + const event& e = static_cast(in); os << e; return os; } @@ -174,7 +157,8 @@ std::ostream& operator<<(std::ostream& os, const event_rewind& in) event_notarized::event_notarized(uint8_t *data, long &pos, long data_len, int32_t height, const char* _dest, bool includeMoM) : event(EVENT_NOTARIZED, height), MoMdepth(0) { - strncpy(this->dest, _dest, sizeof(this->dest)-1); + if (_dest != nullptr) + strncpy(this->dest, _dest, sizeof(this->dest)-1); this->dest[sizeof(this->dest)-1] = 0; MoM.SetNull(); mem_read(this->notarizedheight, data, pos, data_len); @@ -190,7 +174,8 @@ event_notarized::event_notarized(uint8_t *data, long &pos, long data_len, int32_ event_notarized::event_notarized(FILE* fp, int32_t height, const char* _dest, bool includeMoM) : event(EVENT_NOTARIZED, height), MoMdepth(0) { - strncpy(this->dest, _dest, sizeof(this->dest)-1); + if (_dest != nullptr) + strncpy(this->dest, _dest, sizeof(this->dest)-1); this->dest[sizeof(this->dest)-1] = 0; MoM.SetNull(); if ( fread(¬arizedheight,1,sizeof(notarizedheight),fp) != sizeof(notarizedheight) ) @@ -210,7 +195,7 @@ event_notarized::event_notarized(FILE* fp, int32_t height, const char* _dest, bo std::ostream& operator<<(std::ostream& os, const event_notarized& in) { - const event& e = dynamic_cast(in); + const event& e = static_cast(in); os << e; os << serializable(in.notarizedheight); os << serializable(in.blockhash); @@ -245,7 +230,7 @@ event_u::event_u(FILE *fp, int32_t height) : event(EVENT_U, height) std::ostream& operator<<(std::ostream& os, const event_u& in) { - const event& e = dynamic_cast(in); + const event& e = static_cast(in); os << e; os << in.n << in.nid; os.write((const char*)in.mask, 8); @@ -273,7 +258,7 @@ event_kmdheight::event_kmdheight(FILE *fp, int32_t height, bool includeTimestamp std::ostream& operator<<(std::ostream& os, const event_kmdheight& in) { - const event& e = dynamic_cast(in); + const event& e = static_cast(in); os << e << serializable(in.kheight); if (in.timestamp > 0) os << serializable(in.timestamp); @@ -312,7 +297,7 @@ event_opreturn::event_opreturn(FILE* fp, int32_t height) : event(EVENT_OPRETURN, std::ostream& operator<<(std::ostream& os, const event_opreturn& in) { - const event& e = dynamic_cast(in); + const event& e = static_cast(in); os << e << serializable(in.txid) << serializable(in.vout) @@ -342,7 +327,7 @@ event_pricefeed::event_pricefeed(FILE* fp, int32_t height) : event(EVENT_PRICEFE std::ostream& operator<<(std::ostream& os, const event_pricefeed& in) { - const event& e = dynamic_cast(in); + const event& e = static_cast(in); os << e << (uint8_t)in.num; os.write((const char*)in.prices, in.num * sizeof(uint32_t)); return os; diff --git a/src/komodo_structs.h b/src/komodo_structs.h index 6f4f0135186..40c3bc15006 100644 --- a/src/komodo_structs.h +++ b/src/komodo_structs.h @@ -45,6 +45,9 @@ #define KOMODO_ASSETCHAIN_MAXLEN 65 #include "bits256.h" +#include + +extern std::mutex komodo_mutex; // structs prior to refactor struct komodo_kv { UT_hash_handle hh; bits256 pubkey; uint8_t *key,*value; int32_t height; uint32_t flags; uint16_t keylen,valuesize; }; @@ -291,7 +294,19 @@ class komodo_state uint64_t shorted; std::list> events; uint32_t RTbufs[64][3]; uint64_t RTmask; - bool add_event(const std::string& symbol, const uint32_t height, std::shared_ptr in); + template + bool add_event(const std::string& symbol, const uint32_t height, T& in) + { + if (ASSETCHAINS_SYMBOL[0] != 0) + { + std::shared_ptr ptr = std::make_shared( in ); + std::lock_guard lock(komodo_mutex); + events.push_back( ptr ); + return true; + } + return false; + } + protected: /*** * @brief clear the checkpoints collection diff --git a/src/komodo_utils.cpp b/src/komodo_utils.cpp index 8c70a7f7bf9..a88b52389fc 100644 --- a/src/komodo_utils.cpp +++ b/src/komodo_utils.cpp @@ -867,37 +867,51 @@ void iguana_initQ(queue_t *Q,char *name) free(item); } +/** + * @brief Get the username, password, and port from a file + * @param[out] username the username found in the config file + * @param[out] password the password found in the config file + * @param[in] fp the file to be read + * @return the RPC port + */ uint16_t _komodo_userpass(char *username,char *password,FILE *fp) { - char *rpcuser,*rpcpassword,*str,line[8192]; uint16_t port = 0; - rpcuser = rpcpassword = 0; - username[0] = password[0] = 0; + uint16_t port = 0; + char *rpcuser = nullptr; + char *rpcpassword = nullptr; + char line[8192]; + + username[0] = 0; + password[0] = 0; + while ( fgets(line,sizeof(line),fp) != 0 ) { + char *str = nullptr; if ( line[0] == '#' ) continue; - //printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword")); - if ( (str= strstr(line,(char *)"rpcuser")) != 0 ) + if ( (str= strstr(line,(char *)"rpcuser")) != nullptr ) + { rpcuser = parse_conf_line(str,(char *)"rpcuser"); - else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 ) + } + else if ( (str= strstr(line,(char *)"rpcpassword")) != nullptr ) + { rpcpassword = parse_conf_line(str,(char *)"rpcpassword"); - else if ( (str= strstr(line,(char *)"rpcport")) != 0 ) + } + else if ( (str= strstr(line,(char *)"rpcport")) != nullptr ) { port = atoi(parse_conf_line(str,(char *)"rpcport")); - //fprintf(stderr,"rpcport.%u in file\n",port); } } - if ( rpcuser != 0 && rpcpassword != 0 ) + if ( rpcuser != nullptr && rpcpassword != nullptr ) { strcpy(username,rpcuser); strcpy(password,rpcpassword); } - //printf("rpcuser.(%s) rpcpassword.(%s) KMDUSERPASS.(%s) %u\n",rpcuser,rpcpassword,KMDUSERPASS,port); - if ( rpcuser != 0 ) + if ( rpcuser != nullptr ) free(rpcuser); - if ( rpcpassword != 0 ) + if ( rpcpassword != nullptr ) free(rpcpassword); - return(port); + return port; } void komodo_statefname(char *fname,char *symbol,char *str) @@ -1239,21 +1253,79 @@ int8_t equihash_params_possible(uint64_t n, uint64_t k) return(-1); } +/*** + * @brief get username, password, and port from a config file + * @param[in] path the path to the data directory + * @param[in] filename the filename of the config file (without directory) + * @param[out] userpass the username and password from the config file (colon separated) + * @param[out] port the RPC port found in the config file + */ +void get_userpass_and_port(const boost::filesystem::path& path, const std::string& filename, + std::string& userpass, uint16_t& port) +{ + userpass = ""; + port = 0; + boost::filesystem::path datadir_path = path; + datadir_path /= filename; + FILE* fp = fopen(datadir_path.c_str(), "rb"); + if ( fp != nullptr ) + { + char username[512]; + char password[4096]; + port = _komodo_userpass(username,password,fp); + if ( username[0] != 0 && password[0] != 0 ) + userpass = std::string(username) + ":" + std::string(password); + fclose(fp); + } + else + printf("couldnt open.(%s) will not validate dest notarizations\n", datadir_path.c_str()); +} + +/**** + * @brief set ports and usernames/passwords from command line and/or config files + * @note modifies ASSETCHAINS_P2PPORT, ASSETCHAINS_RPCPORT, KMDUSERPASS, BTCUSERPASS, DESTPORT + * @note IS_KOMODO_NOTARY should already be set + * @param ltc_config_filename configuration file for ltc (via -notary command line parameter) + */ +void set_kmd_user_password_port(const std::string& ltc_config_filename) +{ + ASSETCHAINS_P2PPORT = 7770; // default port for P2P + ASSETCHAINS_RPCPORT = 7771; // default port for RPC +#ifdef __APPLE__ + std::string filename = "Komodo.conf"; +#else + std::string filename = "komodo.conf"; +#endif + + auto datadir_path = GetDataDir(); + uint16_t ignore; + std::string userpass; + get_userpass_and_port(datadir_path, filename, userpass, ignore); + if (!userpass.empty()) + strncpy(KMDUSERPASS, userpass.c_str(), 8705); + if (IS_KOMODO_NOTARY) + { + get_userpass_and_port(datadir_path, ltc_config_filename, userpass, DEST_PORT); + if (!userpass.empty()) + strncpy(BTCUSERPASS, userpass.c_str(), 8192); + } +} + void komodo_args(char *argv0) { - std::string name,addn,hexstr,symbol; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[32756],disablebits[32],*extraptr=0; - FILE *fp; uint64_t val; uint16_t port, dest_rpc_port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256], ccEnablesHeight[512] = {0}; CTransaction earlytx; uint256 hashBlock; + std::string name; // -ac_name + char *dirname; + uint8_t disablebits[32],*extraptr=0; + FILE *fp; + int32_t i,nonz=0,n; - std::string ntz_dest_path; - ntz_dest_path = GetArg("-notary", ""); + const std::string ntz_dest_path = GetArg("-notary", ""); IS_KOMODO_NOTARY = ntz_dest_path == "" ? 0 : 1; STAKED_NOTARY_ID = GetArg("-stakednotary", -1); KOMODO_NSPV = GetArg("-nSPV",0); - memset(ccenables,0,sizeof(ccenables)); memset(disablebits,0,sizeof(disablebits)); - memset(ccEnablesHeight,0,sizeof(ccEnablesHeight)); if ( GetBoolArg("-gen", false) != 0 ) { KOMODO_MININGTHREADS = GetArg("-genproclimit",-1); @@ -1294,7 +1366,7 @@ void komodo_args(char *argv0) name = GetArg("-ac_name",""); if ( argv0 != 0 ) { - len = (int32_t)strlen(argv0); + int32_t len = (int32_t)strlen(argv0); for (i=0; i 0 ) - { - for (i=first; i<=last; i++) - { - CLEARBIT(disablebits,i); - ASSETCHAINS_CCDISABLES[i] = 0; - } - }*/ } if ( ASSETCHAINS_BEAMPORT != 0 ) { @@ -1607,8 +1674,10 @@ void komodo_args(char *argv0) printf("ASSETCHAINS_FOUNDERS needs an ASSETCHAINS_OVERRIDE_PUBKEY or ASSETCHAINS_SCRIPTPUB\n"); } } + int32_t extralen = 0; if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 || ASSETCHAINS_CBOPRET != 0 || Mineropret.size() != 0 || (ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0) || KOMODO_SNAPSHOT_INTERVAL != 0 || ASSETCHAINS_EARLYTXIDCONTRACT != 0 || ASSETCHAINS_CBMATURITY != 0 || ASSETCHAINS_ADAPTIVEPOW != 0 ) { + uint8_t extrabuf[32756]; fprintf(stderr,"perc %.4f%% ac_pub=[%02x%02x%02x...] acsize.%d\n",dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0],ASSETCHAINS_OVERRIDE_PUBKEY33[1],ASSETCHAINS_OVERRIDE_PUBKEY33[2],(int32_t)ASSETCHAINS_SCRIPTPUB.size()); extraptr = extrabuf; memcpy(extraptr,ASSETCHAINS_OVERRIDE_PUBKEY33,33), extralen = 33; @@ -1651,7 +1720,7 @@ void komodo_args(char *argv0) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ALGO),(void *)&ASSETCHAINS_ALGO); } - val = ASSETCHAINS_COMMISSION | (((int64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffff) << 40) | ((ASSETCHAINS_PUBLIC != 0) << 7) | ((ASSETCHAINS_PRIVATE != 0) << 6) | ASSETCHAINS_TXPOW; + uint64_t val = ASSETCHAINS_COMMISSION | (((int64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffff) << 40) | ((ASSETCHAINS_PUBLIC != 0) << 7) | ((ASSETCHAINS_PRIVATE != 0) << 6) | ASSETCHAINS_TXPOW; extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val); if ( ASSETCHAINS_FOUNDERS != 0 ) @@ -1670,7 +1739,6 @@ void komodo_args(char *argv0) { decode_hex(&extraptr[extralen],ASSETCHAINS_SCRIPTPUB.size()/2,(char *)ASSETCHAINS_SCRIPTPUB.c_str()); extralen += ASSETCHAINS_SCRIPTPUB.size()/2; - //extralen += iguana_rwnum(1,&extraptr[extralen],(int32_t)ASSETCHAINS_SCRIPTPUB.size(),(void *)ASSETCHAINS_SCRIPTPUB.c_str()); fprintf(stderr,"append ac_script %s\n",ASSETCHAINS_SCRIPTPUB.c_str()); } if ( ASSETCHAINS_SELFIMPORT.size() > 0 ) @@ -1714,7 +1782,7 @@ void komodo_args(char *argv0) { for (i=0; i 0 ) + const std::string addn = GetArg("-seednode",""); + if ( addn.size() > 0 ) ASSETCHAINS_SEED = 1; strncpy(ASSETCHAINS_SYMBOL,name.c_str(),sizeof(ASSETCHAINS_SYMBOL)-1); @@ -1764,9 +1831,9 @@ void komodo_args(char *argv0) MAX_MONEY = komodo_max_money(); - if ( (baseid = komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 ) + int32_t baseid = komodo_baseid(ASSETCHAINS_SYMBOL); + if ( baseid >= 0 && baseid < 32 ) { - //komodo_maxallowed(baseid); printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN); } @@ -1775,7 +1842,6 @@ void komodo_args(char *argv0) if ( KOMODO_BIT63SET(MAX_MONEY) != 0 ) MAX_MONEY = KOMODO_MAXNVALUE; fprintf(stderr,"MAX_MONEY %llu %.8f\n",(long long)MAX_MONEY,(double)MAX_MONEY/SATOSHIDEN); - //printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN); uint16_t tmpport = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen); if ( GetArg("-port",0) != 0 ) { @@ -1792,40 +1858,40 @@ void komodo_args(char *argv0) boost::this_thread::sleep(boost::posix_time::milliseconds(3000)); #endif } - //fprintf(stderr,"Got datadir.(%s)\n",dirname); if ( ASSETCHAINS_SYMBOL[0] != 0 ) { int32_t komodo_baseid(char *origbase); - extern int COINBASE_MATURITY; if ( strcmp(ASSETCHAINS_SYMBOL,"KMD") == 0 ) { fprintf(stderr,"cant have assetchain named KMD\n"); StartShutdown(); } - if ( (port= komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL)) != 0 ) + uint16_t port = komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL); + if ( port != 0 ) ASSETCHAINS_RPCPORT = port; else komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT + 1); if (ASSETCHAINS_CBMATURITY != 0) - COINBASE_MATURITY = ASSETCHAINS_CBMATURITY; + Params().SetCoinbaseMaturity(ASSETCHAINS_CBMATURITY); else if (ASSETCHAINS_LASTERA == 0 || is_STAKED(ASSETCHAINS_SYMBOL) != 0) - COINBASE_MATURITY = 1; - if (COINBASE_MATURITY < 1) + Params().SetCoinbaseMaturity(1); + if (Params().CoinbaseMaturity() < 1) { fprintf(stderr,"ac_cbmaturity must be >0, shutting down\n"); StartShutdown(); } - //fprintf(stderr,"ASSETCHAINS_RPCPORT (%s) %u\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_RPCPORT); } if ( ASSETCHAINS_RPCPORT == 0 ) ASSETCHAINS_RPCPORT = ASSETCHAINS_P2PPORT + 1; - //ASSETCHAINS_NOTARIES = GetArg("-ac_notaries",""); - //komodo_assetchain_pubkeys((char *)ASSETCHAINS_NOTARIES.c_str()); + + uint8_t magic[4]; iguana_rwnum(1,magic,sizeof(ASSETCHAINS_MAGIC),(void *)&ASSETCHAINS_MAGIC); + char magicstr[9]; for (i=0; i<4; i++) sprintf(&magicstr[i<<1],"%02x",magic[i]); magicstr[8] = 0; #ifndef FROM_CLI + char fname[512]; sprintf(fname,"%s_7776",ASSETCHAINS_SYMBOL); if ( (fp= fopen(fname,"wb")) != 0 ) { @@ -1834,7 +1900,6 @@ void komodo_args(char *argv0) notarypay = 1; fprintf(fp,iguanafmtstr,name.c_str(),name.c_str(),name.c_str(),name.c_str(),magicstr,ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,"78.47.196.146",notarypay); fclose(fp); - //printf("created (%s)\n",fname); } else printf("error creating (%s)\n",fname); #endif if ( ASSETCHAINS_CC < 2 ) @@ -1853,47 +1918,13 @@ void komodo_args(char *argv0) } else { - char fname[512],username[512],password[4096]; int32_t iter; FILE *fp; - ASSETCHAINS_P2PPORT = 7770; - ASSETCHAINS_RPCPORT = 7771; - for (iter=0; iter<2; iter++) - { - strcpy(fname,GetDataDir().string().c_str()); -#ifdef _WIN32 - while ( fname[strlen(fname)-1] != '\\' ) - fname[strlen(fname)-1] = 0; - if ( iter == 0 ) - strcat(fname,"Komodo\\komodo.conf"); - else strcat(fname,ntz_dest_path.c_str()); -#else - while ( fname[strlen(fname)-1] != '/' ) - fname[strlen(fname)-1] = 0; -#ifdef __APPLE__ - if ( iter == 0 ) - strcat(fname,"Komodo/Komodo.conf"); - else strcat(fname,ntz_dest_path.c_str()); -#else - if ( iter == 0 ) - strcat(fname,".komodo/komodo.conf"); - else strcat(fname,ntz_dest_path.c_str()); -#endif -#endif - if ( (fp= fopen(fname,"rb")) != 0 ) - { - dest_rpc_port = _komodo_userpass(username,password,fp); - DEST_PORT = iter == 1 ? dest_rpc_port : 0; - sprintf(iter == 0 ? KMDUSERPASS : BTCUSERPASS,"%s:%s",username,password); - fclose(fp); - } else printf("couldnt open.(%s) will not validate dest notarizations\n",fname); - if ( !IS_KOMODO_NOTARY ) - break; - } + // -ac_name not passed, we are on the KMD chain + set_kmd_user_password_port(ntz_dest_path); } int32_t dpowconfs = KOMODO_DPOWCONFS; if ( ASSETCHAINS_SYMBOL[0] != 0 ) { BITCOIND_RPCPORT = GetArg("-rpcport", ASSETCHAINS_RPCPORT); - //fprintf(stderr,"(%s) port.%u chain params initialized\n",ASSETCHAINS_SYMBOL,BITCOIND_RPCPORT); if ( strcmp("PIRATE",ASSETCHAINS_SYMBOL) == 0 && ASSETCHAINS_HALVING[0] == 77777 ) { ASSETCHAINS_HALVING[0] *= 5; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 6ebae40852e..afc7a962f06 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -356,6 +356,13 @@ int32_t queue_size(queue_t *queue); void iguana_initQ(queue_t *Q,char *name); +/** + * @brief Get the username, password, and port from a file + * @param[out] username the username found in the config file + * @param[out] password the password found in the config file + * @param[in] fp the file to be read + * @return the RPC port + */ uint16_t _komodo_userpass(char *username,char *password,FILE *fp); void komodo_statefname(char *fname,char *symbol,char *str); @@ -378,8 +385,6 @@ uint64_t komodo_ac_block_subsidy(int nHeight); int8_t equihash_params_possible(uint64_t n, uint64_t k); -void komodo_args(char *argv0); - void komodo_nameset(char *symbol,char *dest,char *source); struct komodo_state *komodo_stateptrget(char *base); diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile index 2bd2cadcdde..486802d5424 100644 --- a/src/leveldb/Makefile +++ b/src/leveldb/Makefile @@ -107,8 +107,8 @@ clean: -rm -rf ios-x86/* ios-arm/* $(LIBRARY): $(LIBOBJECTS) - rm -f $@ - $(AR) -rs $@ $(LIBOBJECTS) + @rm -f $@ + @$(AR) -rs $@ $(LIBOBJECTS) db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) $(CXX) $(LDFLAGS) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS) @@ -189,8 +189,8 @@ write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) $(CXX) $(LDFLAGS) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) $(MEMENVLIBRARY) : $(MEMENVOBJECTS) - rm -f $@ - $(AR) -rs $@ $(MEMENVOBJECTS) + @rm -f $@ + @$(AR) -rs $@ $(MEMENVOBJECTS) memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) $(CXX) $(LDFLAGS) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LIBS) @@ -220,8 +220,8 @@ IOSARCH=-arch armv6 -arch armv7 -arch armv7s -arch arm64 else .cc.o: - $(CXX) $(CXXFLAGS) -c $< -o $@ + @$(CXX) $(CXXFLAGS) -c $< -o $@ .c.o: - $(CC) $(CFLAGS) -c $< -o $@ + @$(CC) $(CFLAGS) -c $< -o $@ endif diff --git a/src/main.cpp b/src/main.cpp index 59e5dc9f070..adfbda88c53 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1780,19 +1780,30 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF return nMinFee; } - +/***** + * @brief Try to add transaction to memory pool + * @param pool + * @param state + * @param tx + * @param fLimitFree + * @param pfMissingInputs + * @param fRejectAbsurdFee + * @param dosLevel + * @returns true on success + */ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, int dosLevel) { AssertLockHeld(cs_main); - if (pfMissingInputs) + if (pfMissingInputs != nullptr) *pfMissingInputs = false; uint32_t tiptime; - int flag=0,nextBlockHeight = chainActive.Height() + 1; + int flag=0; + int nextBlockHeight = chainActive.Height() + 1; auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus()); if ( nextBlockHeight <= 1 || chainActive.LastTip() == 0 ) tiptime = (uint32_t)time(NULL); - else tiptime = (uint32_t)chainActive.LastTip()->nTime; -//fprintf(stderr,"addmempool 0\n"); + else + tiptime = (uint32_t)chainActive.LastTip()->nTime; // Node operator can choose to reject tx by number of transparent inputs static_assert(std::numeric_limits::max() >= std::numeric_limits::max(), "size_t too small"); size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0); @@ -1806,9 +1817,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return false; } } -//fprintf(stderr,"addmempool 1\n"); auto verifier = libzcash::ProofVerifier::Strict(); - if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,chainActive.LastTip()->nHeight+1,chainActive.LastTip()->GetMedianTimePast() + 777,0) < 0 ) + if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.LastTip() != nullptr + && komodo_validate_interest(tx,chainActive.LastTip()->nHeight+1, + chainActive.LastTip()->GetMedianTimePast() + 777,0) < 0 ) { return error("%s: komodo_validate_interest failed txid.%s", __func__, tx.GetHash().ToString()); } @@ -1824,8 +1836,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa { return error("AcceptToMemoryPool: ContextualCheckTransaction failed"); } -//fprintf(stderr,"addmempool 2\n"); - // Coinbase is only valid in a block, not as a loose transaction + // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) { fprintf(stderr,"AcceptToMemoryPool coinbase as individual tx\n"); @@ -1836,8 +1847,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa string reason; if (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight)) { - // - //fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\nscriptPubKey: %s\n",reason.c_str(),tx.vout[0].scriptPubKey.ToString().c_str()); return state.DoS(0,error("AcceptToMemoryPool: nonstandard transaction: %s", reason),REJECT_NONSTANDARD, reason); } @@ -1846,15 +1855,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // be mined yet. if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) { - //fprintf(stderr,"AcceptToMemoryPool reject non-final\n"); return state.DoS(0, false, REJECT_NONSTANDARD, "non-final"); } -//fprintf(stderr,"addmempool 3\n"); // is it already in the memory pool? uint256 hash = tx.GetHash(); if (pool.exists(hash)) { - //fprintf(stderr,"already in mempool\n"); return state.Invalid(false, REJECT_DUPLICATE, "already in mempool"); } @@ -1867,7 +1873,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (pool.mapNextTx.count(outpoint)) { // Disable replacement feature for now - return false; + return state.Invalid(false, REJECT_INVALID, "mempool conflict"); } } BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { @@ -1884,7 +1890,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } } } -//fprintf(stderr,"addmempool 4\n"); { CCoinsView dummy; CCoinsViewCache view(&dummy); @@ -1898,7 +1903,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // do we already have it? if (view.HaveCoins(hash)) { - //fprintf(stderr,"view.HaveCoins(hash) error\n"); return state.Invalid(false, REJECT_DUPLICATE, "already have coins"); } @@ -1919,7 +1923,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa { if (pfMissingInputs) *pfMissingInputs = true; - //fprintf(stderr,"missing inputs\n"); return false; /* https://github.com/zcash/zcash/blob/master/src/main.cpp#L1490 @@ -1930,7 +1933,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // are the actual inputs available? if (!view.HaveInputs(tx)) { - //fprintf(stderr,"accept failure.1\n"); return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),REJECT_DUPLICATE, "bad-txns-inputs-spent"); } } @@ -1938,16 +1940,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // are the joinsplit's requirements met? if (!view.HaveJoinSplitRequirements(tx)) { - //fprintf(stderr,"accept failure.2\n"); return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met"); } // Bring the best block into scope view.GetBestBlock(); - nValueIn = view.GetValueIn(chainActive.LastTip()->nHeight,&interest,tx,chainActive.LastTip()->nTime); - if ( 0 && interest != 0 ) - fprintf(stderr,"add interest %.8f\n",(double)interest/COIN); + nValueIn = view.GetValueIn(GetHeight(),interest,tx); // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool view.SetBackend(dummy); } @@ -1986,7 +1985,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } } } -//fprintf(stderr,"addmempool 5\n"); // Grab the branch ID we expect this transaction to commit to. We don't // yet know if it does, but if the entry gets added to the mempool, then // it has passed ContextualCheckInputs and therefore this is correct. @@ -2048,7 +2046,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa LogPrint("mempool", errmsg.c_str()); return state.Error("AcceptToMemoryPool: " + errmsg); } -//fprintf(stderr,"addmempool 6\n"); // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. @@ -2074,7 +2071,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa flag = 1; KOMODO_CONNECTING = (1<<30) + (int32_t)chainActive.LastTip()->nHeight + 1; } -//fprintf(stderr,"addmempool 7\n"); if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) { @@ -2103,17 +2099,21 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } } } - // This should be here still? - //SyncWithWallets(tx, NULL); return true; } +/**** + * @brief Add a transaction to the memory pool without the checks of AcceptToMemoryPool + * @param pool the memory pool to add the transaction to + * @param tx the transaction + * @returns true + */ bool CCTxFixAcceptToMemPoolUnchecked(CTxMemPool& pool, const CTransaction &tx) { // called from CheckBlock which is in cs_main and mempool.cs locks already. auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - CTxMemPoolEntry entry(tx, 0, GetTime(), 0, chainActive.Height(), mempool.HasNoInputsOf(tx), false, consensusBranchId); - //fprintf(stderr, "adding %s to mempool from block %d\n",tx.GetHash().ToString().c_str(),chainActive.nHeight); + CTxMemPoolEntry entry(tx, 0, GetTime(), 0, chainActive.Height(), + mempool.HasNoInputsOf(tx), false, consensusBranchId); pool.addUnchecked(tx.GetHash(), entry, false); return true; } @@ -2181,41 +2181,49 @@ struct CompareBlocksByHeightMain } }; -/*uint64_t myGettxout(uint256 hash,int32_t n) -{ - CCoins coins; - LOCK2(cs_main,mempool.cs); - CCoinsViewMemPool view(pcoinsTip, mempool); - if (!view.GetCoins(hash, coins)) - return(0); - if ( n < 0 || (unsigned int)n >= coins.vout.size() || coins.vout[n].IsNull() ) - return(0); - else return(coins.vout[n].nValue); -}*/ - -bool myAddtomempool(CTransaction &tx, CValidationState *pstate, bool fSkipExpiry) +/**** + * @brief add a transaction to the mempool + * @param[in] tx the transaction + * @param pstate where to store any error (can be nullptr) + * @param fSkipExpiry set to false to add to pool without many checks + * @returns true on success + */ +bool myAddtomempool(const CTransaction &tx, CValidationState *pstate, bool fSkipExpiry) { CValidationState state; - if (!pstate) + if (pstate == nullptr) pstate = &state; - CTransaction Ltx; bool fMissingInputs,fOverrideFees = false; - if ( mempool.lookup(tx.GetHash(),Ltx) == 0 ) + + CTransaction Ltx; + if ( mempool.lookup(tx.GetHash(),Ltx) == false ) // does not already exist { if ( !fSkipExpiry ) + { + bool fMissingInputs; + bool fOverrideFees = false; return(AcceptToMemoryPool(mempool, *pstate, tx, false, &fMissingInputs, !fOverrideFees, -1)); + } else return(CCTxFixAcceptToMemPoolUnchecked(mempool,tx)); } - else return(true); + return true; } +/***** + * @brief get a transaction by its hash (without locks) + * @param[in] hash what to look for + * @param[out] txOut the found transaction + * @param[out] hashBlock the hash of the block (all zeros if still in mempool) + * @returns true if found + */ bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) { memset(&hashBlock,0,sizeof(hashBlock)); if ( KOMODO_NSPV_SUPERLITE ) { - int64_t rewardsum = 0; int32_t i,retval,txheight,currentheight,height=0,vout = 0; - for (i=0; iReadTxIndex(hash, postx)) { - //fprintf(stderr,"OpenBlockFile\n"); + if (pblocktree->ReadTxIndex(hash, postx)) + { + // Found the transaction in the index. Load the block to get the block hash CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); if (file.IsNull()) return error("%s: OpenBlockFile failed", __func__); CBlockHeader header; - //fprintf(stderr,"seek and read\n"); try { file >> header; fseek(file.Get(), postx.nTxOffset, SEEK_CUR); @@ -2255,11 +2261,9 @@ bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlo hashBlock = header.GetHash(); if (txOut.GetHash() != hash) return error("%s: txid mismatch", __func__); - //fprintf(stderr,"found on disk %s\n",hash.GetHex().c_str()); return true; } } - //fprintf(stderr,"not found on disk %s\n",hash.GetHex().c_str()); return false; } @@ -2281,10 +2285,16 @@ bool NSPV_myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &ha return false; } -/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ +/** + * @brief Find a transaction (uses locks) + * @param[in] hash the transaction to look for + * @param[out] txOut the transaction found + * @param[out] hashBlock the block where the transaction was found (all zeros if found in mempool) + * @param[in] fAllowSlow true to continue searching even if there are no transaction indexes + * @returns true if found + */ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) { - CBlockIndex *pindexSlow = NULL; memset(&hashBlock,0,sizeof(hashBlock)); LOCK(cs_main); @@ -2315,26 +2325,33 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock } } + CBlockIndex *pindexSlow = nullptr; if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it int nHeight = -1; { - CCoinsViewCache &view = *pcoinsTip; - const CCoins* coins = view.AccessCoins(hash); - if (coins) + const CCoins* coins = pcoinsTip->AccessCoins(hash); + if (coins != nullptr) + { nHeight = coins->nHeight; - } - if (nHeight > 0) - pindexSlow = chainActive[nHeight]; - } - - if (pindexSlow) { - CBlock block; - if (ReadBlockFromDisk(block, pindexSlow,1)) { - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - if (tx.GetHash() == hash) { - txOut = tx; - hashBlock = pindexSlow->GetBlockHash(); - return true; + if (nHeight > 0) + { + CBlockIndex *pindexSlow = chainActive[nHeight]; + if (pindexSlow != nullptr) + { + CBlock block; + if (ReadBlockFromDisk(block, pindexSlow,1)) + { + for(const CTransaction &tx : block.vtx) + { + if (tx.GetHash() == hash) + { + txOut = tx; + hashBlock = pindexSlow->GetBlockHash(); + return true; + } + } + } + } } } } @@ -2343,21 +2360,6 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock return false; } -/*char *komodo_getspendscript(uint256 hash,int32_t n) - { - CTransaction tx; uint256 hashBlock; - if ( !GetTransaction(hash,tx,hashBlock,true) ) - { - printf("null GetTransaction\n"); - return(0); - } - if ( n >= 0 && n < tx.vout.size() ) - return((char *)tx.vout[n].scriptPubKey.ToString().c_str()); - else printf("getspendscript illegal n.%d\n",n); - return(0); - }*/ - - ////////////////////////////////////////////////////////////////////////////// // // CBlock and CBlockIndex @@ -2509,22 +2511,12 @@ bool IsInitialBlockDownload() return true; } - bool state; - arith_uint256 bigZero = arith_uint256(); - arith_uint256 minWork = UintToArith256(chainParams.GetConsensus().nMinimumChainWork); CBlockIndex *ptr = chainActive.Tip(); - if (ptr == NULL) { - //fprintf(stderr,"nullptr in IsInitialDownload\n"); return true; } - if (0 && ptr->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork)) - { - fprintf(stderr,"nChainWork insufficient in IsInitialDownload\n"); - return true; - } - state = ((chainActive.Height() < ptr->nHeight - 24*60) || + bool state = ((chainActive.Height() < ptr->nHeight - 24*60) || ptr->GetBlockTime() < (GetTime() - nMaxTipAge)); if ( KOMODO_INSYNC != 0 ) state = false; @@ -2804,9 +2796,9 @@ namespace Consensus { } // Ensure that coinbases are matured, no DoS as retry may work later - if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { + if (nSpendHeight - coins->nHeight < ::Params().CoinbaseMaturity()) { return state.Invalid( - error("CheckInputs(): tried to spend coinbase at depth %d/%d", nSpendHeight - coins->nHeight, (int32_t)COINBASE_MATURITY), + error("CheckInputs(): tried to spend coinbase at depth %d/%d", nSpendHeight - coins->nHeight, (int32_t)::Params().CoinbaseMaturity()), REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); } @@ -3156,7 +3148,6 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex *pfClean = false; bool fClean = true; - //komodo_disconnect(pindex,block); does nothing? CBlockUndo blockUndo; CDiskBlockPos pos = pindex->GetUndoPos(); if (pos.IsNull()) @@ -3404,6 +3395,25 @@ static int64_t nTimeTotal = 0; bool FindBlockPos(int32_t tmpflag,CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false); bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos); +/***** + * Only for testing, DO NOT USE + * @returns the cs_main mutex + */ +CCriticalSection& get_cs_main() +{ + return cs_main; +} + +/***** + * @brief Apply the effects of this block (with given index) on the UTXO set represented by coins + * @param block the block to add + * @param state the result status + * @param pindex where to insert the block + * @param view the chain + * @param fJustCheck do not actually modify, only do checks + * @param fcheckPOW + * @returns true on success + */ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck,bool fCheckPOW) { CDiskBlockPos blockPos; @@ -3412,7 +3422,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return(true); if ( KOMODO_STOPAT != 0 && pindex->nHeight > KOMODO_STOPAT ) return(false); - //fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->nHeight); AssertLockHeld(cs_main); bool fExpensiveChecks = true; if (fCheckpointsEnabled) { @@ -3430,7 +3439,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in if ( !CheckBlock(&futureblock,pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, fCheckPOW, !fJustCheck) || futureblock != 0 ) { - //fprintf(stderr,"checkblock failure in connectblock futureblock.%d\n",futureblock); return false; } if ( fCheckPOW != 0 && (pindex->nStatus & BLOCK_VALID_CONTEXT) != BLOCK_VALID_CONTEXT ) // Activate Jan 15th, 2019 @@ -3465,7 +3473,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin REJECT_INVALID, "bad-cb-amount"); // calculate the notaries compensation and validate the amounts and pubkeys are correct. notarypaycheque = komodo_checknotarypay((CBlock *)&block,(int32_t)pindex->nHeight); - //fprintf(stderr, "notarypaycheque.%lu\n", notarypaycheque); if ( notarypaycheque > 0 ) blockReward += notarypaycheque; else @@ -3487,7 +3494,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("AcceptBlock(): ReceivedBlockTransactions failed"); setDirtyFileInfo.insert(blockPos.nFile); - //fprintf(stderr,"added ht.%d copy of tmpfile to %d.%d\n",pindex->nHeight,blockPos.nFile,blockPos.nPos); } // verify that the view's current state corresponds to the previous block uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); @@ -3514,8 +3520,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints())); - //if ( KOMODO_TESTNET_EXPIRATION != 0 && pindex->nHeight > KOMODO_TESTNET_EXPIRATION ) // "testnet" - // return(false); // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. BOOST_FOREACH(const CTransaction& tx, block.vtx) { @@ -3592,7 +3596,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (nSigOps > MAX_BLOCK_SIGOPS) return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); - //fprintf(stderr,"ht.%d vout0 t%u\n",pindex->nHeight,tx.nLockTime); if (!tx.IsMint()) { if (!view.HaveInputs(tx)) @@ -3656,21 +3659,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin fprintf(stderr,"valueout %.8f too big\n",(double)valueout/COIN); return state.DoS(100, error("ConnectBlock(): GetValueOut too big"),REJECT_INVALID,"tx valueout is too big"); } - //prevsum = voutsum; - //voutsum += valueout; - /*if ( KOMODO_VALUETOOBIG(voutsum) != 0 ) - { - fprintf(stderr,"voutsum %.8f too big\n",(double)voutsum/COIN); - return state.DoS(100, error("ConnectBlock(): voutsum too big"),REJECT_INVALID,"tx valueout is too big"); - } - else - if ( voutsum < prevsum ) // PRLPAY overflows this and it isnt a conclusive test anyway - return state.DoS(100, error("ConnectBlock(): voutsum less after adding valueout"),REJECT_INVALID,"tx valueout is too big");*/ if (!tx.IsCoinBase()) { - nFees += (stakeTxValue= view.GetValueIn(chainActive.LastTip()->nHeight,&interest,tx,chainActive.LastTip()->nTime) - valueout); + nFees += (stakeTxValue= view.GetValueIn(chainActive.LastTip()->nHeight,interest,tx) - valueout); sum += interest; - //fprintf(stderr, "tx.%s nFees.%li interest.%li\n", tx.GetHash().ToString().c_str(), stakeTxValue, interest); std::vector vChecks; if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL)) @@ -3703,8 +3695,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } } - //if ( ASSETCHAINS_SYMBOL[0] == 0 ) - // komodo_earned_interest(pindex->nHeight,sum); CTxUndo undoDummy; if (i > 0) { blockundo.vtxundo.push_back(CTxUndo()); @@ -3714,7 +3704,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) { // Insert the note commitments into our temporary tree. - sprout_tree.append(note_commitment); } } @@ -3728,7 +3717,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } // This is moved from CheckBlock for staking chains, so we can enforce the staking tx value was indeed paid to the coinbase. - //fprintf(stderr, "blockReward.%li stakeTxValue.%li sum.%li\n",blockReward,stakeTxValue,sum); if ( ASSETCHAINS_STAKED != 0 && fCheckPOW && komodo_checkPOW(blockReward+stakeTxValue-notarypaycheque,1,(CBlock *)&block,pindex->nHeight) < 0 ) return state.DoS(100, error("ConnectBlock: ac_staked chain failed slow komodo_checkPOW"),REJECT_INVALID, "failed-slow_checkPOW"); @@ -3775,8 +3763,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin { if ( ASSETCHAINS_SYMBOL[0] != 0 || pindex->nHeight >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) { - //fprintf(stderr, "coinbase pays too much\n"); - //sleepflag = true; return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), @@ -3793,7 +3779,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return true; // Write undo information to disk - //fprintf(stderr,"nFile.%d isNull %d vs isvalid %d nStatus %x\n",(int32_t)pindex->nFile,pindex->GetUndoPos().IsNull(),pindex->IsValid(BLOCK_VALID_SCRIPTS),(uint32_t)pindex->nStatus); if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) { if (pindex->GetUndoPos().IsNull()) @@ -3880,13 +3865,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin int64_t nTime4 = GetTimeMicros(); nTimeCallbacks += nTime4 - nTime3; LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001); - //FlushStateToDisk(); komodo_connectblock(false,pindex,*(CBlock *)&block); // dPoW state update. if ( ASSETCHAINS_NOTARY_PAY[0] != 0 ) { // Update the notary pay with the latest payment. pindex->nNotaryPay = pindex->pprev->nNotaryPay + notarypaycheque; - //fprintf(stderr, "total notary pay.%li\n", pindex->nNotaryPay); } return true; } @@ -4238,13 +4221,16 @@ static int64_t nTimeFlush = 0; static int64_t nTimeChainState = 0; static int64_t nTimePostConnect = 0; -/** - * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock - * corresponding to pindexNew, to bypass loading it again from disk. - * You probably want to call mempool.removeWithoutBranchId after this, with cs_main held. +/*** + * @brief Connect a new block to chainActive. + * @note You probably want to call mempool.removeWithoutBranchId after this, with cs_main held. + * @param[out] state holds the state + * @param pindexNew the new index + * @param pblock a pointer to a CBlock (nullptr will load it from disk) + * @returns true on success */ -bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) { - +bool ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) +{ assert(pindexNew->pprev == chainActive.Tip()); // Read block from disk. int64_t nTime1 = GetTimeMicros(); @@ -4547,8 +4533,10 @@ static bool ActivateBestChainStep(bool fSkipdpow, CValidationState &state, CBloc nHeight = nTargetHeight; // Connect new blocks. - BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { + BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) + { + if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) + { if (state.IsInvalid()) { // The block violates a consensus rule. if (!state.CorruptionPossible()) @@ -5108,13 +5096,26 @@ bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex, int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime); int32_t komodo_checkPOW(int64_t stakeTxValue,int32_t slowflag,CBlock *pblock,int32_t height); -bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, - libzcash::ProofVerifier& verifier, - bool fCheckPOW, bool fCheckMerkleRoot) +/**** + * @brief various checks of block validity + * @param[out] futureblockp pointer to the future block + * @param[in] height the new height + * @param[out] pindex the block index + * @param[in] block the block to check + * @param[out] state stores results + * @param[in] verifier verification routine + * @param[in] fCheckPOW pass true to check PoW + * @param[in] fCheckMerkleRoot pass true to check merkle root + * @returns true on success, on error, state will contain info + */ +bool CheckBlock(int32_t *futureblockp, int32_t height, CBlockIndex *pindex, const CBlock& block, + CValidationState& state, libzcash::ProofVerifier& verifier, bool fCheckPOW, + bool fCheckMerkleRoot) { - uint8_t pubkey33[33]; uint256 hash; uint32_t tiptime = (uint32_t)block.nTime; + uint8_t pubkey33[33]; + uint32_t tiptime = (uint32_t)block.nTime; // These are checks that are independent of context. - hash = block.GetHash(); + uint256 hash = block.GetHash(); // Check that the header is valid (particularly PoW). This is mostly redundant with the call in AcceptBlockHeader. if (!CheckBlockHeader(futureblockp,height,pindex,block,state,fCheckPOW)) { @@ -5124,22 +5125,21 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C return false; } } - if ( pindex != 0 && pindex->pprev != 0 ) + if ( pindex != nullptr && pindex->pprev != nullptr ) tiptime = (uint32_t)pindex->pprev->nTime; if ( fCheckPOW ) { - //if ( !CheckEquihashSolution(&block, Params()) ) - // return state.DoS(100, error("CheckBlock: Equihash solution invalid"),REJECT_INVALID, "invalid-solution"); komodo_block2pubkey33(pubkey33,(CBlock *)&block); if ( !CheckProofOfWork(block,pubkey33,height,Params().GetConsensus()) ) { - int32_t z; for (z=31; z>=0; z--) + for (int32_t z = 31; z >= 0; z--) fprintf(stderr,"%02x",((uint8_t *)&hash)[z]); fprintf(stderr," failed hash ht.%d\n",height); return state.DoS(50, error("CheckBlock: proof of work failed"),REJECT_INVALID, "high-hash"); } if ( ASSETCHAINS_STAKED == 0 && komodo_checkPOW(0,1,(CBlock *)&block,height) < 0 ) // checks Equihash - return state.DoS(100, error("CheckBlock: failed slow_checkPOW"),REJECT_INVALID, "failed-slow_checkPOW"); + return state.DoS(100, error("CheckBlock: failed slow_checkPOW"),REJECT_INVALID, + "failed-slow_checkPOW"); } if ( height > nDecemberHardforkHeight && ASSETCHAINS_SYMBOL[0] == 0 ) // December 2019 hardfork { @@ -5150,14 +5150,17 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C CBlock blockcopy = block; // block shouldn't be changed below, so let's make it's copy CBlock *pblockcopy = (CBlock *)&blockcopy; if (!komodo_checkopret(pblockcopy, merkleroot)) { - fprintf(stderr, "failed or missing merkleroot expected.%s != merkleroot.%s\n", komodo_makeopret(pblockcopy, false).ToString().c_str(), merkleroot.ToString().c_str()); - return state.DoS(100, error("CheckBlock: failed or missing merkleroot opret in easy-mined"),REJECT_INVALID, "failed-merkle-opret-in-easy-mined"); + fprintf(stderr, "failed or missing merkleroot expected.%s != merkleroot.%s\n", + komodo_makeopret(pblockcopy, false).ToString().c_str(), merkleroot.ToString().c_str()); + return state.DoS(100, error("CheckBlock: failed or missing merkleroot opret in easy-mined"), + REJECT_INVALID, "failed-merkle-opret-in-easy-mined"); } } } // Check the merkle root. - if (fCheckMerkleRoot) { + if (fCheckMerkleRoot) + { bool mutated; uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated); if (block.hashMerkleRoot != hashMerkleRoot2) @@ -5177,8 +5180,8 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C // because we receive the wrong transactions for it. // Size limits - //fprintf(stderr,"%s checkblock %d -> %d vs blocksize.%d\n",ASSETCHAINS_SYMBOL,height,MAX_BLOCK_SIZE(height),(int32_t)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)); - if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE(height) || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE(height)) + if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE(height) + || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE(height)) return state.DoS(100, error("CheckBlock: size limits failed"), REJECT_INVALID, "bad-blk-length"); @@ -5193,44 +5196,48 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C REJECT_INVALID, "bad-cb-multiple"); // Check transactions - CTransaction sTx; - CTransaction *ptx = NULL; if ( ASSETCHAINS_CC != 0 && !fCheckPOW ) return true; - if ( ASSETCHAINS_CC != 0 ) // CC contracts might refer to transactions in the current block, from a CC spend within the same block and out of order + CTransaction sTx; + CTransaction *ptx = nullptr; + + // CC contracts might refer to transactions in the current block, from a + // CC spend within the same block and out of order + if ( ASSETCHAINS_CC != 0 ) { int32_t i,j,rejects=0,lastrejects=0; - //fprintf(stderr,"put block's tx into mempool\n"); - // Copy all non Z-txs in mempool to temporary mempool because there can be tx in local mempool that make the block invalid. + // Copy all non Z-txs in mempool to temporary mempool because there can + // be tx in local mempool that make the block invalid. LOCK2(cs_main,mempool.cs); - //fprintf(stderr, "starting... mempoolsize.%ld\n",mempool.size()); list transactionsToRemove; - BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx) { + for(const CTxMemPoolEntry& e : mempool.mapTx) + { const CTransaction &tx = e.GetTx(); - const uint256 &hash = tx.GetHash(); - if ( tx.vjoinsplit.empty() && tx.vShieldedSpend.empty()) { + if ( tx.vjoinsplit.empty() && tx.vShieldedSpend.empty()) + { transactionsToRemove.push_back(tx); - tmpmempool.addUnchecked(hash,e,true); + tmpmempool.addUnchecked(tx.GetHash(),e,true); } } - BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { + for(const CTransaction& tx : transactionsToRemove) { list removed; mempool.remove(tx, removed, false); } - // add all the txs in the block to the empty mempool. - // CC validation shouldnt (cant) depend on the state of mempool! - while ( 1 ) + // add all the txs in the block to the (somewhat) empty mempool. + // CC validation shouldn't (can't) depend on the state of mempool! + while ( true ) { list removed; for (i=0; i all tx in mempool\n",lastrejects); break; } - //fprintf(stderr,"addtomempool ht.%d for CC checking: n.%d rejects.%d last.%d\n",height,(int32_t)block.vtx.size(),rejects,lastrejects); lastrejects = rejects; rejects = 0; } - //fprintf(stderr,"done putting block's tx into mempool\n"); } for (uint32_t i = 0; i < block.vtx.size(); i++) @@ -5263,7 +5265,7 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C } unsigned int nSigOps = 0; - BOOST_FOREACH(const CTransaction& tx, block.vtx) + for(const CTransaction& tx : block.vtx) { nSigOps += GetLegacySigOpCount(tx); } @@ -5272,9 +5274,6 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C REJECT_INVALID, "bad-blk-sigops", true); if ( fCheckPOW && komodo_check_deposit(height,block,(pindex==0||pindex->pprev==0)?0:pindex->pprev->nTime) < 0 ) { - //static uint32_t counter; - //if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 ) - // fprintf(stderr,"check deposit rejection\n"); LogPrintf("CheckBlockHeader komodo_check_deposit error"); return(false); } @@ -5288,13 +5287,12 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C { LOCK2(cs_main,mempool.cs); // here we add back all txs from the temp mempool to the main mempool. - BOOST_FOREACH(const CTxMemPoolEntry& e, tmpmempool.mapTx) + for(const CTxMemPoolEntry& e : tmpmempool.mapTx) { const CTransaction &tx = e.GetTx(); const uint256 &hash = tx.GetHash(); mempool.addUnchecked(hash,e,true); } - //fprintf(stderr, "finished adding back. mempoolsize.%ld\n",mempool.size()); // empty the temp mempool for next time. tmpmempool.clear(); } @@ -5553,7 +5551,18 @@ bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidat uint256 Queued_reconsiderblock; -bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) +/***** + * @brief + * @param futureblockp + * @param block + * @param state + * @param ppindex + * @param fRequested + * @param dbp + * @returns true if block accepted + */ +bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, CBlockIndex** ppindex, + bool fRequested, CDiskBlockPos* dbp) { const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); @@ -5573,7 +5582,6 @@ bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, C *futureblockp = true; return false; } - //fprintf(stderr,"acceptblockheader passed\n"); // Try to process all requested blocks that we don't have, but only // process an unrequested block if it's new and has enough work to // advance our tip, and isn't too many blocks ahead. @@ -5767,13 +5775,29 @@ CBlockIndex *oldkomodo_ensure(CBlock *pblock, uint256 hash) return(pindex); } -bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) +/***** + * @brief Process a new block + * @note can come from the network or locally mined + * @note This only returns after the best known valid + * block is made active. Note that it does not, however, guarantee that the + * specific block passed to it has been checked for validity! + * @param from_miner no longer used + * @param height the new height + * @param[out] state the results + * @param pfrom the node that produced the block (nullptr for local) + * @param pblock the block to process + * @param fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers. + * @param[out] dbp set to position on disk for block + * @returns true on success + */ +bool ProcessNewBlock(bool from_miner, int32_t height, CValidationState &state, CNode* pfrom, + CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) { // Preliminary checks - bool checked; uint256 hash; int32_t futureblock=0; + bool checked; + int32_t futureblock=0; auto verifier = libzcash::ProofVerifier::Disabled(); - hash = pblock->GetHash(); - //fprintf(stderr,"ProcessBlock %d\n",(int32_t)chainActive.LastTip()->nHeight); + uint256 hash = pblock->GetHash(); { LOCK(cs_main); if ( chainActive.LastTip() != 0 ) @@ -5781,14 +5805,13 @@ bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNo checked = CheckBlock(&futureblock,height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier,0); bool fRequested = MarkBlockAsReceived(hash); fRequested |= fForceProcessing; - if ( checked != 0 && komodo_checkPOW(0,0,pblock,height) < 0 ) //from_miner && ASSETCHAINS_STAKED == 0 + if ( checked && komodo_checkPOW(0,0,pblock,height) < 0 ) { - checked = 0; - //fprintf(stderr,"passed checkblock but failed checkPOW.%d\n",from_miner && ASSETCHAINS_STAKED == 0); + checked = false; } if (!checked && futureblock == 0) { - if ( pfrom != 0 ) + if ( pfrom != nullptr ) { Misbehaving(pfrom->GetId(), 1); } @@ -5797,27 +5820,20 @@ bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNo // Store to disk CBlockIndex *pindex = NULL; - bool ret = AcceptBlock(&futureblock,*pblock, state, &pindex, fRequested, dbp); + bool accepted = AcceptBlock(&futureblock,*pblock, state, &pindex, fRequested, dbp); if (pindex && pfrom) { mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); } CheckBlockIndex(); - if (!ret && futureblock == 0) + if (!accepted && futureblock == 0) { - /*if ( ASSETCHAINS_SYMBOL[0] == 0 ) - { - //fprintf(stderr,"request headers from failed process block peer\n"); - pfrom->PushMessage("getheaders", chainActive.GetLocator(chainActive.LastTip()), uint256()); - }*/ komodo_longestchain(); return error("%s: AcceptBlock FAILED", __func__); } - //else fprintf(stderr,"added block %s %p\n",pindex->GetBlockHash().ToString().c_str(),pindex->pprev); } if (futureblock == 0 && !ActivateBestChain(false, state, pblock)) return error("%s: ActivateBestChain failed", __func__); - //fprintf(stderr,"finished ProcessBlock %d\n",(int32_t)chainActive.LastTip()->nHeight); return true; } @@ -7383,12 +7399,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (pfrom->nVersion < chainparams.GetConsensus().vUpgrades[ CurrentEpoch(GetHeight(), chainparams.GetConsensus())].nProtocolVersion) { - LogPrintf("peer=%d using obsolete version %i vs %d; disconnecting\n", pfrom->id, pfrom->nVersion,(int32_t)chainparams.GetConsensus().vUpgrades[ - CurrentEpoch(GetHeight(), chainparams.GetConsensus())].nProtocolVersion); + LogPrintf("peer=%d using obsolete version %i vs %d; disconnecting\n", + pfrom->id, pfrom->nVersion,(int32_t)chainparams.GetConsensus().vUpgrades[ + CurrentEpoch(GetHeight(), chainparams.GetConsensus())].nProtocolVersion); pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", - chainparams.GetConsensus().vUpgrades[ - CurrentEpoch(GetHeight(), chainparams.GetConsensus())].nProtocolVersion)); + strprintf("Version must be %d or greater", chainparams.GetConsensus().vUpgrades[ + CurrentEpoch(GetHeight(), chainparams.GetConsensus())].nProtocolVersion)); pfrom->fDisconnect = true; return false; } diff --git a/src/main.h b/src/main.h index 9ba9303a65d..e2635ed86ef 100644 --- a/src/main.h +++ b/src/main.h @@ -66,7 +66,6 @@ class PrecomputedTransactionData; struct CNodeStateStats; #define DEFAULT_MEMPOOL_EXPIRY 1 -#define _COINBASE_MATURITY 100 /** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 2000000;//MAX_BLOCK_SIZE; @@ -78,7 +77,7 @@ static const bool DEFAULT_ALERTS = true; /** Minimum alert priority for enabling safe mode. */ static const int ALERT_PRIORITY_SAFE_MODE = 4000; /** Maximum reorg length we will accept before we shut down and alert the user. */ -static unsigned int MAX_REORG_LENGTH = _COINBASE_MATURITY - 1; +static unsigned int MAX_REORG_LENGTH = 100 - 1; // based on COINBASE_MATURITY /** Maximum number of signature check operations in an IsStandard() P2SH script */ static const unsigned int MAX_P2SH_SIGOPS = 15; /** The maximum number of sigops we're willing to relay/mine in a single tx */ @@ -202,17 +201,20 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals); /** Unregister a network node */ void UnregisterNodeSignals(CNodeSignals& nodeSignals); -/** - * Process an incoming block. This only returns after the best known valid +/***** + * @brief Process a new block + * @note can come from the network or locally mined + * @note This only returns after the best known valid * block is made active. Note that it does not, however, guarantee that the * specific block passed to it has been checked for validity! - * - * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation. - * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid. - * @param[in] pblock The block we want to process. - * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers. - * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. - * @return True if state.IsValid() + * @param from_miner no longer used + * @param height the new height + * @param[out] state the results + * @param pfrom the node that produced the block (nullptr for local) + * @param pblock the block to process + * @param fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers. + * @param[out] dbp set to position on disk for block + * @returns true on success */ bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); /** Check whether enough disk space is available for an incoming block */ @@ -252,7 +254,14 @@ bool IsInitialBlockDownload(); int IsNotInSync(); /** Format a string that describes several potential problems detected by the core */ std::string GetWarnings(const std::string& strFor); -/** Retrieve a transaction (from memory pool, or from disk, if possible) */ +/** + * @brief Find a transaction (uses locks) + * @param[in] hash the transaction to look for + * @param[out] txOut the transaction found + * @param[out] hashBlock the block where the transaction was found (all zeros if found in mempool) + * @param[in] fAllowSlow true to continue searching even if there are no transaction indexes + * @returns true if found + */ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ bool ActivateBestChain(bool fSkipdpow, CValidationState &state, CBlock *pblock = NULL); @@ -291,7 +300,17 @@ void FlushStateToDisk(); /** Prune block files and flush state to disk. */ void PruneAndFlush(); -/** (try to) add transaction to memory pool **/ +/** + * @brief Try to add transaction to memory pool + * @param pool + * @param state + * @param tx + * @param fLimitFree + * @param pfMissingInputs + * @param fRejectAbsurdFee + * @param dosLevel + * @returns true on success + */ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectAbsurdFee=false, int dosLevel=-1); @@ -820,7 +839,16 @@ bool PruneOneBlockFile(bool tempfile, const int fileNumber); * of problems. Note that in any case, coins may be modified. */ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); -/** Apply the effects of this block (with given index) on the UTXO set represented by coins */ +/***** + * @brief Apply the effects of this block (with given index) on the UTXO set represented by coins + * @param block the block to add + * @param state the result status + * @param pindex where to insert the block + * @param view the chain + * @param fJustCheck do not actually modify, only do checks + * @param fcheckPOW + * @returns true on success + */ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false,bool fCheckPOW = false); /** Context-independent validity checks */ diff --git a/src/metrics.cpp b/src/metrics.cpp index 7ec6298b03e..ff1924c91da 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -365,7 +365,7 @@ int printMetrics(size_t cols, bool mining) subsidy -= subsidy/5; } - if ((std::max(0, COINBASE_MATURITY - (tipHeight - height)) > 0) || + if ((std::max( 0U, Params().CoinbaseMaturity() - (tipHeight - height)) > 0) || (tipHeight < komodo_block_unlocktime(height) && subsidy >= ASSETCHAINS_TIMELOCKGTE)) { immature += subsidy; } else { diff --git a/src/miner.cpp b/src/miner.cpp index 8a811b4fa25..cb7c0a393a0 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -184,7 +184,15 @@ int32_t komodo_waituntilelegible(uint32_t blocktime, int32_t stakeHeight, uint32 return(1); } -CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake) +/***** + * @breif Generate a new block based on mempool txs, without valid proof-of-work + * @param _pk the public key + * @param _scriptPubKeyIn the script for the public key + * @param gpucount assists in calculating the block's nTime + * @param isStake + * @returns the block template + */ +CBlockTemplate* CreateNewBlock(const CPubKey _pk, const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake) { CScript scriptPubKeyIn(_scriptPubKeyIn); @@ -573,7 +581,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 //fprintf(stderr,"dont have inputs\n"); continue; } - CAmount nTxFees = view.GetValueIn(chainActive.LastTip()->nHeight,&interest,tx,chainActive.LastTip()->nTime)-tx.GetValueOut(); + CAmount nTxFees = view.GetValueIn(chainActive.LastTip()->nHeight,interest,tx)-tx.GetValueOut(); nTxSigOps += GetP2SHSigOpCount(tx, view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1) @@ -900,49 +908,6 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 return pblocktemplate.release(); } -/* - #ifdef ENABLE_WALLET - boost::optional GetMinerScriptPubKey(CReserveKey& reservekey) - #else - boost::optional GetMinerScriptPubKey() - #endif - { - CKeyID keyID; - CBitcoinAddress addr; - if (addr.SetString(GetArg("-mineraddress", ""))) { - addr.GetKeyID(keyID); - } else { - #ifdef ENABLE_WALLET - CPubKey pubkey; - if (!reservekey.GetReservedKey(pubkey)) { - return boost::optional(); - } - keyID = pubkey.GetID(); - #else - return boost::optional(); - #endif - } - - CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; - return scriptPubKey; - } - - #ifdef ENABLE_WALLET - CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) - { - boost::optional scriptPubKey = GetMinerScriptPubKey(reservekey); - #else - CBlockTemplate* CreateNewBlockWithKey() - { - boost::optional scriptPubKey = GetMinerScriptPubKey(); - #endif - - if (!scriptPubKey) { - return NULL; - } - return CreateNewBlock(*scriptPubKey); - }*/ - ////////////////////////////////////////////////////////////////////////////// // // Internal miner @@ -975,6 +940,14 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& // Internal miner // +/***** + * Create a new block + * @param reserveKey + * @param nHeight + * @param gpucount + * @param isStake + * @returns the block template + */ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, int32_t gpucount, bool isStake) { CPubKey pubkey; CScript scriptPubKey; uint8_t *script,*ptr; int32_t i,len; @@ -996,30 +969,26 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, } else if ( USE_EXTERNAL_PUBKEY != 0 ) { - //fprintf(stderr,"use notary pubkey\n"); pubkey = ParseHex(NOTARY_PUBKEY); scriptPubKey = CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG; } else { - //if ( !isStake || ASSETCHAINS_STAKED != 0 ) - { - if (!GetBoolArg("-disablewallet", false)) { - // wallet enabled - if (!reservekey.GetReservedKey(pubkey)) - return NULL; - scriptPubKey.clear(); - scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; - } else { - // wallet disabled - CTxDestination dest = DecodeDestination(GetArg("-mineraddress", "")); - if (IsValidDestination(dest)) { - // CKeyID keyID = boost::get(dest); - // scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; - scriptPubKey = GetScriptForDestination(dest); - } else - return NULL; - } + if (!GetBoolArg("-disablewallet", false)) { + // wallet enabled + if (!reservekey.GetReservedKey(pubkey)) + return NULL; + scriptPubKey.clear(); + scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; + } else { + // wallet disabled + CTxDestination dest = DecodeDestination(GetArg("-mineraddress", "")); + if (IsValidDestination(dest)) { + // CKeyID keyID = boost::get(dest); + // scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; + scriptPubKey = GetScriptForDestination(dest); + } else + return NULL; } } return CreateNewBlock(pubkey, scriptPubKey, gpucount, isStake); diff --git a/src/miner.h b/src/miner.h index a3bedd29204..3d2cf4d32cc 100644 --- a/src/miner.h +++ b/src/miner.h @@ -42,8 +42,15 @@ struct CBlockTemplate }; #define KOMODO_MAXGPUCOUNT 65 -/** Generate a new block, without valid proof-of-work */ -CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& scriptPubKeyIn, int32_t gpucount, bool isStake = false); +/***** + * @breif Generate a new block based on mempool txs, without valid proof-of-work + * @param _pk the public key + * @param _scriptPubKeyIn the script for the public key + * @param gpucount assists in calculating the block's nTime + * @param isStake + * @returns the block template + */ +CBlockTemplate* CreateNewBlock(const CPubKey _pk,const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake = false); #ifdef ENABLE_WALLET boost::optional GetMinerScriptPubKey(CReserveKey& reservekey); CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, int32_t gpucount, bool isStake = false); diff --git a/src/notaries_staked.cpp b/src/notaries_staked.cpp index 0a804db2083..6b5ad4a1769 100644 --- a/src/notaries_staked.cpp +++ b/src/notaries_staked.cpp @@ -9,12 +9,23 @@ extern pthread_mutex_t staked_mutex; +static bool doneinit_STAKED = false; + +/***** + * Reset the doneinit static (for unit testing) + */ +void undo_init_STAKED() +{ + doneinit_STAKED = false; +} + + int8_t is_STAKED(const char *chain_name) { - static int8_t STAKED,doneinit; + static int8_t STAKED; if ( chain_name[0] == 0 ) return(0); - if (doneinit == 1 && ASSETCHAINS_SYMBOL[0] != 0) + if (doneinit_STAKED && ASSETCHAINS_SYMBOL[0] != 0) return(STAKED); else STAKED = 0; if ( (strcmp(chain_name, "LABS") == 0) ) @@ -27,7 +38,7 @@ int8_t is_STAKED(const char *chain_name) STAKED = 4; // These chains are for testing consensus to create a chain etc. Not meant to be actually used for anything important. else if ( (strcmp(chain_name, "THIS_CHAIN_IS_BANNED") == 0) ) STAKED = 255; // Any chain added to this group is banned, no notarisations are valid, as a consensus rule. Can be used to remove a chain from cluster if needed. - doneinit = 1; + doneinit_STAKED = true; return(STAKED); }; diff --git a/src/pow.cpp b/src/pow.cpp index 0ab464906c4..3643f3fc79e 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -383,7 +383,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead if (pindexFirst == NULL) return nProofOfWorkLimit; - bool fNegative,fOverflow; int32_t zawyflag = 0; arith_uint256 easy,origtarget,bnAvg {bnTot / params.nPowAveragingWindow}; + bool fNegative,fOverflow; int32_t zawyflag = 0; + arith_uint256 easy,origtarget; + arith_uint256 bnAvg{bnTot / params.nPowAveragingWindow}; // average number of bits in the lookback window nbits = CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params); if ( ASSETCHAINS_ADAPTIVEPOW > 0 ) { @@ -497,9 +499,16 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead return(nbits); } +/**** + * @brief calculate the nBits value (work required) for the next block + * @param bnAvg the average nBits value (work required) across the lookback window + * @param nLastBlockTime the time of the most recent block in the lookback window + * @param nFirstBlockTime the time of the first block in the lookback window + * @param params the chain's consensus parameters + * @return the nBits value for the next block + */ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, - int64_t nLastBlockTime, int64_t nFirstBlockTime, - const Consensus::Params& params) + int64_t nLastBlockTime, int64_t nFirstBlockTime, const Consensus::Params& params) { // Limit adjustment step // Use medians to prevent time-warp attacks @@ -522,7 +531,7 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, else bnLimit = UintToArith256(params.powAlternate); - const arith_uint256 bnPowLimit = bnLimit; //UintToArith256(params.powLimit); + const arith_uint256 bnPowLimit = bnLimit; arith_uint256 bnNew {bnAvg}; bnNew /= params.AveragingWindowTimespan(); bnNew *= nActualTimespan; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 32d92bbbe4f..11609dc881b 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -267,9 +267,9 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (wtx.IsCoinBase()) { extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; - if ( ASSETCHAINS_SYMBOL[0] == 0 ) - COINBASE_MATURITY = _COINBASE_MATURITY; - quint32 numBlocksToMaturity = COINBASE_MATURITY + 1; + //if ( ASSETCHAINS_SYMBOL[0] == 0 ) + //COINBASE_MATURITY = _COINBASE_MATURITY; + quint32 numBlockToMaturity = 100 + 1; // COINBASE_MATURITY + 1 strHTML += "
" + tr("Generated coins must mature %1 blocks and have any applicable time locks open before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "
"; // we need to display any possible CLTV lock time } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index d12a17342a5..4a267de8044 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -195,6 +195,95 @@ UniValue getgenerate(const UniValue& params, bool fHelp, const CPubKey& mypk) extern uint8_t NOTARY_PUBKEY33[33]; +/***** + * Calculate the PoW value for a block + * @param pblock the block to work on + * @returns true when the PoW is completed + */ +bool CalcPoW(CBlock *pblock) +{ + unsigned int n = Params().EquihashN(); + unsigned int k = Params().EquihashK(); + // Hash state + crypto_generichash_blake2b_state eh_state; + EhInitialiseState(n, k, eh_state); + + // I = the block header minus nonce and solution. + CEquihashInput I{*pblock}; + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << I; + + // H(I||... + crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); + + while (true) { + // Yes, there is a chance every nonce could fail to satisfy the -regtest + // target -- 1 in 2^(2^256). That ain't gonna happen + pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); + + // H(I||V||... + crypto_generichash_blake2b_state curr_state; + curr_state = eh_state; + crypto_generichash_blake2b_update(&curr_state, + pblock->nNonce.begin(), + pblock->nNonce.size()); + + // (x_1, x_2, ...) = A(I, V, n, k) + std::function)> validBlock = + [&pblock](std::vector soln) + { + LOCK(cs_main); + pblock->nSolution = soln; + solutionTargetChecks.increment(); + return CheckProofOfWork(*pblock,NOTARY_PUBKEY33,chainActive.Height(),Params().GetConsensus()); + }; + bool found = EhBasicSolveUncancellable(n, k, curr_state, validBlock); + ehSolverRuns.increment(); + if (found) { + return true; + } + } + // this should never get hit + return false; +} + +/**** + * @brief Generate 1 block + * @param wallet the wallet that should be used + * @returns the block created or nullptr if there was a problem + */ +std::shared_ptr generateBlock(CWallet* wallet, CValidationState* validationState) +{ + CReserveKey reservekey(wallet); + int nHeight; + + { // Don't keep cs_main locked + LOCK(cs_main); + nHeight = chainActive.Height(); + } + + std::unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey,nHeight,KOMODO_MAXGPUCOUNT)); + if (pblocktemplate == nullptr) + return nullptr; + + CBlock *pblock = &pblocktemplate->block; + { + unsigned int nExtraNonce = 0; + LOCK(cs_main); + IncrementExtraNonce(pblock, chainActive.LastTip(), nExtraNonce); + } + + CalcPoW(pblock); // add PoW + CValidationState state; + if (!ProcessNewBlock(1,chainActive.LastTip()->nHeight+1,state, NULL, pblock, true, NULL)) + { + if (validationState != nullptr) + (*validationState) = state; + return nullptr; + } + return std::shared_ptr( new CBlock(*pblock) ); +} + //Value generate(const Array& params, bool fHelp) UniValue generate(const UniValue& params, bool fHelp, const CPubKey& mypk) { @@ -251,8 +340,6 @@ UniValue generate(const UniValue& params, bool fHelp, const CPubKey& mypk) } unsigned int nExtraNonce = 0; UniValue blockHashes(UniValue::VARR); - unsigned int n = Params().EquihashN(); - unsigned int k = Params().EquihashK(); uint64_t lastTime = 0; while (nHeight < nHeightEnd) { @@ -273,46 +360,7 @@ UniValue generate(const UniValue& params, bool fHelp, const CPubKey& mypk) IncrementExtraNonce(pblock, chainActive.LastTip(), nExtraNonce); } - // Hash state - crypto_generichash_blake2b_state eh_state; - EhInitialiseState(n, k, eh_state); - - // I = the block header minus nonce and solution. - CEquihashInput I{*pblock}; - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << I; - - // H(I||... - crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); - - while (true) { - // Yes, there is a chance every nonce could fail to satisfy the -regtest - // target -- 1 in 2^(2^256). That ain't gonna happen - pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); - - // H(I||V||... - crypto_generichash_blake2b_state curr_state; - curr_state = eh_state; - crypto_generichash_blake2b_update(&curr_state, - pblock->nNonce.begin(), - pblock->nNonce.size()); - - // (x_1, x_2, ...) = A(I, V, n, k) - std::function)> validBlock = - [&pblock](std::vector soln) - { - LOCK(cs_main); - pblock->nSolution = soln; - solutionTargetChecks.increment(); - return CheckProofOfWork(*pblock,NOTARY_PUBKEY33,chainActive.Height(),Params().GetConsensus()); - }; - bool found = EhBasicSolveUncancellable(n, k, curr_state, validBlock); - ehSolverRuns.increment(); - if (found) { - goto endloop; - } - } -endloop: + CalcPoW(pblock); // add PoW CValidationState state; if (!ProcessNewBlock(1,chainActive.LastTip()->nHeight+1,state, NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 64d98d78376..22a5f98d800 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1204,6 +1204,17 @@ SigVersion SignatureHashVersion(const CTransaction& txTo) } } +/***** + * Generate a signature hash + * @param scriptCode the scriptPubKey + * @param txTo the transaction we are trying to create + * @param nIn the index of the vIn that has the data to sign + * @param nHashType the hash type (i.e. SIGHASH_ALL) + * @param amount the amount (for hidden txs) + * @param consensusBranchId the branch id + * @param cache additional data + * @returns the signature + */ uint256 SignatureHash( const CScript& scriptCode, const CTransaction& txTo, diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am index c5fa00fc575..bf4d448bd03 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -153,10 +153,10 @@ CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function gen_context_OBJECTS = gen_context.o gen_context_BIN = gen_context$(BUILD_EXEEXT) gen_%.o: src/gen_%.c - $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ + $(AM_V_at)$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ $(gen_context_BIN): $(gen_context_OBJECTS) - $(CC_FOR_BUILD) $^ -o $@ + $(AM_V_at)$(CC_FOR_BUILD) $^ -o $@ $(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h $(tests_OBJECTS): src/ecmult_static_context.h diff --git a/src/snark/Makefile b/src/snark/Makefile index 3ef82ab878a..26fd3ec356c 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -195,7 +195,7 @@ $(DEPINST_EXISTS): -include $(patsubst %.o,%.d, $(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) ) $(LIB_OBJS) $(if $(NO_GTEST),,$(GTEST_OBJS)) $(EXEC_OBJS): %.o: %.cpp - $(CXX) -o $@ $< -c -MMD $(CXXFLAGS) + @$(CXX) -o $@ $< -c -MMD $(CXXFLAGS) LIBGTEST_A = $(DEPINST)/lib/libgtest.a @@ -205,12 +205,12 @@ $(LIBGTEST_A): $(GTESTDIR)/libsnark/gtest-all.cc $(DEPINST_EXISTS) # libsnark.a will contains all of our relevant object files, and we also mash in the .a files of relevant dependencies built by ./prepare-depends.sh $(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS) - $(AR) q $(LIBSNARK_A) $(LIB_OBJS) - if [ -n "$(AR_LIBS)" ]; then mkdir -p tmp-ar; cd tmp-ar; for AR_LIB in $(AR_LIBS); do $(AR) x $$AR_LIB; done; $(AR) qc $(LIBSNARK_A) tmp-ar/*; cd ..; rm -r tmp-ar; fi; - $(AR) s $(LIBSNARK_A) + @$(AR) q $(LIBSNARK_A) $(LIB_OBJS) + @if [ -n "$(AR_LIBS)" ]; then mkdir -p tmp-ar; cd tmp-ar; for AR_LIB in $(AR_LIBS); do $(AR) x $$AR_LIB; done; $(AR) qc $(LIBSNARK_A) tmp-ar/*; cd ..; rm -r tmp-ar; fi; + @$(AR) s $(LIBSNARK_A) libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS) - $(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS) + @$(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS) libsnark/gadgetlib2/tests/gadgetlib2_test: \ libsnark/gadgetlib2/tests/adapters_UTEST.cpp \ diff --git a/src/test-komodo/main.cpp b/src/test-komodo/main.cpp index 1adb729b4a2..7bcd5db543e 100644 --- a/src/test-komodo/main.cpp +++ b/src/test-komodo/main.cpp @@ -18,5 +18,7 @@ int main(int argc, char **argv) { notaryKey = vchSecret.GetKey(); testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + auto retval = RUN_ALL_TESTS(); + ECC_Stop(); + return retval; } diff --git a/src/test-komodo/test_alerts.cpp b/src/test-komodo/test_alerts.cpp new file mode 100644 index 00000000000..a1f9cbe50fe --- /dev/null +++ b/src/test-komodo/test_alerts.cpp @@ -0,0 +1,427 @@ +// Copyright (c) 2013 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// +// Unit tests for alert system +// + +#include "alert.h" +#include "chain.h" +#include "chainparams.h" +#include "clientversion.h" + +#include "main.h" +#include "rpc/protocol.h" +#include "rpc/server.h" +#include "serialize.h" +#include "streams.h" +#include "util.h" +#include "utilstrencodings.h" + +#include "test/test_bitcoin.h" + +#include + +#include +#include +#include + +#include "key.h" +#include +#include // for ::remove +#include + +namespace TestAlerts +{ + +// macro to assist with log messages +#define GTEST_COUT std::cerr << "[ ] [ INFO ] " + +// Code to output a C-style array of values +template +std::string HexStrArray(const T itbegin, const T itend, int lineLength) +{ + std::string rv; + static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + rv.reserve((itend-itbegin)*3); + int i = 0; + for(T it = itbegin; it < itend; ++it) + { + unsigned char val = (unsigned char)(*it); + if(it != itbegin) + { + if (i % lineLength == 0) + rv.push_back('\n'); + else + rv.push_back(' '); + } + rv.push_back('0'); + rv.push_back('x'); + rv.push_back(hexmap[val>>4]); + rv.push_back(hexmap[val&15]); + rv.push_back(','); + i++; + } + + return rv; +} + +template +inline std::string HexStrArray(const T& vch, int lineLength) +{ + return HexStrArray(vch.begin(), vch.end(), lineLength); +} + +// Stuff used by several tests, and set up by TestAlerts::SetupTestCase() +boost::filesystem::path alertnotify_file; +CKey key; +CPubKey pubKey; +std::vector alerts; +boost::filesystem::path temp_directory = boost::filesystem::temp_directory_path(); +boost::filesystem::path binary_file; + +class TestAlerts : public ::testing::Test +{ +public: + TestAlerts() + { + } + ~TestAlerts() + { + } + static void SetUpTestCase() + { + // generate a key that will sign alerts + key.MakeNewKey(false); + pubKey = key.GetPubKey(); + // a place to store the binary file + binary_file = temp_directory / "testAlerts.raw"; + // generate the alerts + GenerateAlertTests(); + // Now read it into the alerts collection + ReadAlerts(binary_file); + alertnotify_file = GetTempPath() / + boost::filesystem::unique_path("alertnotify-%%%%.txt"); + mapArgs["-alertnotify"] = std::string("echo %s >> ") + alertnotify_file.string(); + } + static void TearDownTestCase() + { + if (!boost::filesystem::remove( alertnotify_file) ) + GTEST_COUT << "Boost says it was unable to remove file " << alertnotify_file.string() + << std::endl; + if (!boost::filesystem::remove(binary_file)) + GTEST_COUT << "Unable to remove file " << binary_file.string() << std::endl; + } + + virtual void SetUp() {} + + virtual void TearDown() {} + + /****** + * @brief reads the alerts that were generated by GenerateAlertTests + */ + static std::vector ReadLines(boost::filesystem::path filepath) + { + std::vector result; + + std::ifstream f(filepath.string().c_str()); + std::string line; + while (std::getline(f,line)) + result.push_back(line); + f.close(); + return result; + } + + static bool ReadAlerts(boost::filesystem::path infile) + { + // read the file into a vector + std::ifstream filestream(binary_file.string().c_str(), std::ios::in | std::ios::binary); + std::vector vch( (std::istreambuf_iterator(filestream)), std::istreambuf_iterator()); + + CDataStream stream(vch, SER_DISK, CLIENT_VERSION); + try { + while (!stream.eof()) + { + CAlert alert; + stream >> alert; + alerts.push_back(alert); + } + } + catch (const std::exception&) { return false; } + return true; + } + + static void GenerateAlertTests() + { + CDataStream sBuffer(SER_DISK, CLIENT_VERSION); + + CAlert alert; + alert.nRelayUntil = 60; + alert.nExpiration = 24 * 60 * 60; + alert.nID = 1; + alert.nCancel = 0; // cancels previous messages up to this ID number + alert.nMinVer = 0; // These versions are protocol versions + alert.nMaxVer = 999001; + alert.nPriority = 1; + alert.strComment = "Alert comment"; + alert.strStatusBar = "Alert 1"; + + // Replace SignAndSave with SignAndSerialize + SignAndSerialize(alert, sBuffer); + + // More tests go here ... + alert.setSubVer.insert(std::string("/MagicBean:0.1.0/")); + alert.strStatusBar = "Alert 1 for MagicBean 0.1.0"; + SignAndSerialize(alert, sBuffer); + + alert.setSubVer.insert(std::string("/MagicBean:0.2.0/")); + alert.strStatusBar = "Alert 1 for MagicBean 0.1.0, 0.2.0"; + SignAndSerialize(alert, sBuffer); + + alert.setSubVer.clear(); + ++alert.nID; + alert.nCancel = 1; + alert.nPriority = 100; + alert.strStatusBar = "Alert 2, cancels 1"; + SignAndSerialize(alert, sBuffer); + + alert.nExpiration += 60; + ++alert.nID; + SignAndSerialize(alert, sBuffer); + + ++alert.nID; + alert.nPriority = 5000; + alert.strStatusBar = "Alert 3, disables RPC"; + alert.strRPCError = "RPC disabled"; + SignAndSerialize(alert, sBuffer); + + ++alert.nID; + alert.nPriority = 5000; + alert.strStatusBar = "Alert 4, re-enables RPC"; + alert.strRPCError = ""; + SignAndSerialize(alert, sBuffer); + + ++alert.nID; + alert.nMinVer = 11; + alert.nMaxVer = 22; + alert.nPriority = 100; + SignAndSerialize(alert, sBuffer); + + ++alert.nID; + alert.strStatusBar = "Alert 2 for MagicBean 0.1.0"; + alert.setSubVer.insert(std::string("/MagicBean:0.1.0/")); + SignAndSerialize(alert, sBuffer); + + ++alert.nID; + alert.nMinVer = 0; + alert.nMaxVer = 999999; + alert.strStatusBar = "Evil Alert'; /bin/ls; echo '"; + alert.setSubVer.clear(); + bool b = SignAndSerialize(alert, sBuffer); + + if (b) { + // write alerts to a file + std::vector vch = std::vector(sBuffer.begin(), sBuffer.end()); + std::ofstream outfile(binary_file.string().c_str(), std::ios::out | std::ios::binary); + outfile.write((const char*)&vch[0], vch.size()); + outfile.close(); + } + } + + // Sign CAlert with alert private key + static bool SignAlert(CAlert &alert) + { + // serialize alert data + CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); + sMsg << *(CUnsignedAlert*)&alert; + alert.vchMsg = std::vector(sMsg.begin(), sMsg.end()); + + // sign alert + if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig)) + { + printf("SignAlert() : key.Sign failed\n"); + return false; + } + return true; + } + + // Sign a CAlert and serialize it + static bool SignAndSerialize(CAlert &alert, CDataStream &buffer) + { + // Sign + if(!SignAlert(alert)) + { + printf("SignAndSerialize() : could not sign alert\n"); + return false; + } + // ...and save! + buffer << alert; + return true; + } +}; + +TEST_F(TestAlerts, AlertApplies) +{ + SetMockTime(11); + std::vector alertKey{pubKey.begin(), pubKey.end()}; + + for(const CAlert& alert : alerts) + { + EXPECT_TRUE(alert.CheckSignature(alertKey)); + } + + EXPECT_GE(alerts.size(), 3); + + // Matches: + EXPECT_TRUE(alerts[0].AppliesTo(1, "")); + EXPECT_TRUE(alerts[0].AppliesTo(999001, "")); + EXPECT_TRUE(alerts[0].AppliesTo(1, "/MagicBean:11.11.11/")); + + EXPECT_TRUE(alerts[1].AppliesTo(1, "/MagicBean:0.1.0/")); + EXPECT_TRUE(alerts[1].AppliesTo(999001, "/MagicBean:0.1.0/")); + + EXPECT_TRUE(alerts[2].AppliesTo(1, "/MagicBean:0.1.0/")); + EXPECT_TRUE(alerts[2].AppliesTo(1, "/MagicBean:0.2.0/")); + + // Don't match: + EXPECT_TRUE(!alerts[0].AppliesTo(-1, "")); + EXPECT_TRUE(!alerts[0].AppliesTo(999002, "")); + + EXPECT_TRUE(!alerts[1].AppliesTo(1, "")); + EXPECT_TRUE(!alerts[1].AppliesTo(1, "MagicBean:0.1.0")); + EXPECT_TRUE(!alerts[1].AppliesTo(1, "/MagicBean:0.1.0")); + EXPECT_TRUE(!alerts[1].AppliesTo(1, "MagicBean:0.1.0/")); + EXPECT_TRUE(!alerts[1].AppliesTo(-1, "/MagicBean:0.1.0/")); + EXPECT_TRUE(!alerts[1].AppliesTo(999002, "/MagicBean:0.1.0/")); + EXPECT_TRUE(!alerts[1].AppliesTo(1, "/MagicBean:0.2.0/")); + + EXPECT_TRUE(!alerts[2].AppliesTo(1, "/MagicBean:0.3.0/")); + + SetMockTime(0); +} + + +TEST_F(TestAlerts, AlertNotify) +{ + SetMockTime(11); + const std::vector& alertKey{pubKey.begin(), pubKey.end()}; + + for(CAlert alert : alerts) + alert.ProcessAlert(alertKey, false); + + std::vector r = ReadLines( alertnotify_file); + EXPECT_EQ(r.size(), 6u); + +// Windows built-in echo semantics are different than posixy shells. Quotes and +// whitespace are printed literally. + +#ifndef WIN32 + EXPECT_EQ(r[0], "Alert 1"); + EXPECT_EQ(r[1], "Alert 2, cancels 1"); + EXPECT_EQ(r[2], "Alert 2, cancels 1"); + EXPECT_EQ(r[3], "Alert 3, disables RPC"); + EXPECT_EQ(r[4], "Alert 4, reenables RPC"); // dashes should be removed + EXPECT_EQ(r[5], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed +#else + EXPECT_EQ(r[0], "'Alert 1' "); + EXPECT_EQ(r[1], "'Alert 2, cancels 1' "); + EXPECT_EQ(r[2], "'Alert 2, cancels 1' "); + EXPECT_EQ(r[3], "'Alert 3, disables RPC' "); + EXPECT_EQ(r[4], "'Alert 4, reenables RPC' "); // dashes should be removed + EXPECT_EQ(r[5], "'Evil Alert; /bin/ls; echo ' "); +#endif + + SetMockTime(0); + mapAlerts.clear(); +} + +TEST_F(TestAlerts, AlertDisablesRPC) +{ + SetMockTime(11); + const std::vector& alertKey{pubKey.begin(), pubKey.end()}; + + // Command should work before alerts + EXPECT_EQ(GetWarnings("rpc"), ""); + + // First alert should disable RPC + alerts[5].ProcessAlert(alertKey, false); + EXPECT_EQ(alerts[5].strRPCError, "RPC disabled"); + EXPECT_EQ(GetWarnings("rpc"), "RPC disabled"); + + // Second alert should re-enable RPC + alerts[6].ProcessAlert(alertKey, false); + EXPECT_EQ(alerts[6].strRPCError, ""); + EXPECT_EQ(GetWarnings("rpc"), ""); + + SetMockTime(0); + mapAlerts.clear(); +} + +static bool falseFunc() { return false; } + +TEST_F(TestAlerts, PartitionAlert) +{ + // Test PartitionCheck + CCriticalSection csDummy; + CChainParams& params = Params(CBaseChainParams::MAIN); + int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing; // for komodo mainnet, currently 60 + int64_t normalBlocksPerDay = 86400 / nPowTargetSpacing; + CBlockIndex indexDummy[86400 / 60]; // hard coded to avoid compiler warnings about variable length buffer + + // Generate fake blockchain timestamps relative to + // an arbitrary time: + int64_t now = 1427379054; + SetMockTime(now); + for (int i = 0; i < normalBlocksPerDay; i++) + { + indexDummy[i].phashBlock = nullptr; + if (i == 0) + indexDummy[i].pprev = nullptr; + else + indexDummy[i].pprev = &indexDummy[i-1]; + indexDummy[i].nHeight = i; + indexDummy[i].nTime = now - (normalBlocksPerDay-i)*nPowTargetSpacing; + // Other members don't matter, the partition check code doesn't + // use them + } + + // Test 1: chain with blocks every nPowTargetSpacing seconds, + // as normal, no worries: + PartitionCheck(falseFunc, csDummy, &indexDummy[normalBlocksPerDay - 1], nPowTargetSpacing); + EXPECT_TRUE(strMiscWarning.empty()); + + // Test 2: go 3.5 hours without a block, expect a warning: + now += 3*60*60+30*60; + SetMockTime(now); + PartitionCheck(falseFunc, csDummy, &indexDummy[normalBlocksPerDay - 1], nPowTargetSpacing); + EXPECT_TRUE(!strMiscWarning.empty()); + GTEST_COUT << "Got alert text: " << strMiscWarning << std::endl; + strMiscWarning = ""; + + // Test 3: test the "partition alerts only go off once per day" + // code: + now += 60*10; + SetMockTime(now); + PartitionCheck(falseFunc, csDummy, &indexDummy[normalBlocksPerDay - 1], nPowTargetSpacing); + EXPECT_TRUE(strMiscWarning.empty()); + + // Test 4: get 2.5 times as many blocks as expected: + now += 60*60*24; // Pretend it is a day later + SetMockTime(now); + int64_t quickSpacing = nPowTargetSpacing*2/5; + for (int i = 0; i < normalBlocksPerDay; i++) // Tweak chain timestamps: + indexDummy[i].nTime = now - (normalBlocksPerDay-i)*quickSpacing; + PartitionCheck(falseFunc, csDummy, &indexDummy[normalBlocksPerDay - 1], nPowTargetSpacing); + EXPECT_TRUE(!strMiscWarning.empty()); + GTEST_COUT << "Got alert text: " << strMiscWarning << std::endl; + strMiscWarning = ""; + + SetMockTime(0); + // PartitionCheck adds records to the alertnotify file asynchronously. + // To remove the file, we need to wait briefly for it to be closed. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); +} + +} // namespace TestAlerts diff --git a/src/test-komodo/test_block.cpp b/src/test-komodo/test_block.cpp new file mode 100644 index 00000000000..9b68705ad06 --- /dev/null +++ b/src/test-komodo/test_block.cpp @@ -0,0 +1,237 @@ +#include "primitives/block.h" +#include "testutils.h" +#include "komodo_extern_globals.h" +#include "consensus/validation.h" +#include "coincontrol.h" +#include "miner.h" + +#include +#include + + +TEST(test_block, header_size_is_expected) { + // Header with an empty Equihash solution. + CBlockHeader header; + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << header; + + auto stream_size = CBlockHeader::HEADER_SIZE + 1; + // ss.size is +1 due to data stream header of 1 byte + EXPECT_EQ(ss.size(), stream_size); +} + +TEST(test_block, TestStopAt) +{ + TestChain chain; + auto notary = std::make_shared(chain.getNotaryKey(), "notary"); + std::shared_ptr lastBlock = chain.generateBlock(notary); // genesis block + ASSERT_GT( chain.GetIndex()->nHeight, 0 ); + lastBlock = chain.generateBlock(notary); // now we should be above 1 + ASSERT_GT( chain.GetIndex()->nHeight, 1); + CBlock block; + CValidationState state; + KOMODO_STOPAT = 1; + EXPECT_FALSE( chain.ConnectBlock(block, state, chain.GetIndex(), false, true) ); + KOMODO_STOPAT = 0; // to not stop other tests +} + +TEST(test_block, TestConnectWithoutChecks) +{ + TestChain chain; + auto notary = std::make_shared(chain.getNotaryKey(), "notary"); + auto alice = std::make_shared("alice"); + std::shared_ptr lastBlock = chain.generateBlock(notary); // genesis block + ASSERT_GT( chain.GetIndex()->nHeight, 0 ); + // Add some transaction to a block + int32_t newHeight = chain.GetIndex()->nHeight + 1; + TransactionInProcess fundAlice = notary->CreateSpendTransaction(alice, 100000); + // construct the block + CBlock block; + // first a coinbase tx + auto consensusParams = Params().GetConsensus(); + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(consensusParams, newHeight); + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vin[0].scriptSig = (CScript() << newHeight << CScriptNum(1)) + COINBASE_FLAGS; + txNew.vout.resize(1); + txNew.vout[0].nValue = GetBlockSubsidy(newHeight,consensusParams); + txNew.nExpiryHeight = 0; + block.vtx.push_back(CTransaction(txNew)); + // then the actual tx + block.vtx.push_back(fundAlice.transaction); + CValidationState state; + // create a new CBlockIndex to forward to ConnectBlock + auto index = chain.GetIndex(); + CBlockIndex newIndex; + newIndex.pprev = index; + EXPECT_TRUE( chain.ConnectBlock(block, state, &newIndex, true, false) ); + if (!state.IsValid() ) + FAIL() << state.GetRejectReason(); +} + +TEST(test_block, TestSpendInSameBlock) +{ + //setConsoleDebugging(true); + TestChain chain; + auto notary = std::make_shared(chain.getNotaryKey(), "notary"); + notary->SetBroadcastTransactions(true); + auto alice = std::make_shared("alice"); + alice->SetBroadcastTransactions(true); + auto bob = std::make_shared("bob"); + auto miner = std::make_shared("miner"); + std::shared_ptr lastBlock = chain.generateBlock(notary); // genesis block + ASSERT_GT( chain.GetIndex()->nHeight, 0 ); + CAmount notaryBalance = notary->GetBalance(); + // delay just a second to help with locktime + std::this_thread::sleep_for(std::chrono::seconds(1)); + // Start to build a block + int32_t newHeight = chain.GetIndex()->nHeight + 1; + TransactionInProcess fundAlice = notary->CreateSpendTransaction(alice, 100000, 5000, true); + notaryBalance -= 105000; // transfer + fee + // now have Alice move some funds to Bob in the same block + CCoinControl useThisTransaction; + COutPoint tx(fundAlice.transaction.GetHash(), 1); + useThisTransaction.Select(tx); + TransactionInProcess aliceToBob = alice->CreateSpendTransaction(bob, 50000, 5000, useThisTransaction); + EXPECT_TRUE( alice->CommitTransaction(aliceToBob.transaction, aliceToBob.reserveKey) ); + std::this_thread::sleep_for(std::chrono::seconds(1)); + // see if everything worked + lastBlock = chain.generateBlock(miner); + EXPECT_TRUE( lastBlock != nullptr); + // balances should be correct + EXPECT_EQ( bob->GetBalance() + bob->GetUnconfirmedBalance() + bob->GetImmatureBalance(), CAmount(50000)); + EXPECT_EQ( notary->GetBalance(), notaryBalance); + EXPECT_EQ( alice->GetBalance() + alice->GetUnconfirmedBalance() + alice->GetImmatureBalance(), CAmount(45000)); +} + +TEST(test_block, TestDoubleSpendInSameBlock) +{ + TestChain chain; + auto notary = std::make_shared(chain.getNotaryKey(), "notary"); + notary->SetBroadcastTransactions(true); + auto alice = std::make_shared("alice"); + alice->SetBroadcastTransactions(true); + auto bob = std::make_shared("bob"); + auto charlie = std::make_shared("charlie"); + std::shared_ptr lastBlock = chain.generateBlock(notary); // genesis block + CAmount notaryBalance = notary->GetBalance(); + ASSERT_GT( chain.GetIndex()->nHeight, 0 ); + // Start to build a block + int32_t newHeight = chain.GetIndex()->nHeight + 1; + TransactionInProcess fundAlice = notary->CreateSpendTransaction(alice, 100000, 5000, true); + EXPECT_EQ(mempool.size(), 1); + // now have Alice move some funds to Bob in the same block + { + CCoinControl useThisTransaction; + COutPoint tx(fundAlice.transaction.GetHash(), 1); + useThisTransaction.Select(tx); + TransactionInProcess aliceToBob = alice->CreateSpendTransaction(bob, 10000, 5000, useThisTransaction); + EXPECT_TRUE(alice->CommitTransaction(aliceToBob.transaction, aliceToBob.reserveKey)); + } + // alice attempts to double spend the vout and send something to charlie + { + CCoinControl useThisTransaction; + COutPoint tx(fundAlice.transaction.GetHash(), 1); + useThisTransaction.Select(tx); + TransactionInProcess aliceToCharlie = alice->CreateSpendTransaction(charlie, 10000, 5000, useThisTransaction); + CValidationState state; + EXPECT_FALSE(alice->CommitTransaction(aliceToCharlie.transaction, aliceToCharlie.reserveKey, state)); + EXPECT_EQ(state.GetRejectReason(), "mempool conflict"); + } + /* + EXPECT_EQ(mempool.size(), 3); + CValidationState validationState; + std::shared_ptr block = chain.generateBlock(notary, &validationState); + EXPECT_EQ( block, nullptr ); + EXPECT_EQ( validationState.GetRejectReason(), "bad-txns-inputs-missingorspent"); + */ +} + +bool CalcPoW(CBlock *pblock); + +TEST(test_block, TestProcessBlock) +{ + TestChain chain; + EXPECT_EQ(chain.GetIndex()->nHeight, 0); + auto notary = std::make_shared(chain.getNotaryKey(), "notary"); + auto alice = std::make_shared("alice"); + auto bob = std::make_shared("bob"); + auto charlie = std::make_shared("charlie"); + std::shared_ptr lastBlock = chain.generateBlock(notary); // gives notary everything + EXPECT_EQ(chain.GetIndex()->nHeight, 1); + chain.IncrementChainTime(); + // add a transaction to the mempool + TransactionInProcess fundAlice = notary->CreateSpendTransaction(alice, 100000); + EXPECT_TRUE( chain.acceptTx(fundAlice.transaction).IsValid() ); + // construct the block + CBlock block; + int32_t newHeight = chain.GetIndex()->nHeight + 1; + CValidationState state; + // no transactions + EXPECT_FALSE( ProcessNewBlock(false, newHeight, state, nullptr, &block, false, nullptr) ); + EXPECT_EQ(state.GetRejectReason(), "bad-blk-length"); + EXPECT_EQ(chain.GetIndex()->nHeight, 1); + // add first a coinbase tx + auto consensusParams = Params().GetConsensus(); + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(consensusParams, newHeight); + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vin[0].scriptSig = (CScript() << newHeight << CScriptNum(1)) + COINBASE_FLAGS; + txNew.vout.resize(1); + txNew.vout[0].nValue = GetBlockSubsidy(newHeight,consensusParams); + txNew.nExpiryHeight = 0; + block.vtx.push_back(CTransaction(txNew)); + // no PoW, no merkle root should fail on merkle error + EXPECT_FALSE( ProcessNewBlock(false, newHeight, state, nullptr, &block, false, nullptr) ); + EXPECT_EQ(state.GetRejectReason(), "bad-txnmrklroot"); + // Verify transaction is still in mempool + EXPECT_EQ(mempool.size(), 1); + // finish constructing the block + block.nBits = GetNextWorkRequired( chain.GetIndex(), &block, Params().GetConsensus()); + block.nTime = GetTime(); + block.hashPrevBlock = lastBlock->GetHash(); + block.hashMerkleRoot = block.BuildMerkleTree(); + // Add the PoW + EXPECT_TRUE(CalcPoW(&block)); + state = CValidationState(); + EXPECT_TRUE( ProcessNewBlock(false, newHeight, state, nullptr, &block, false, nullptr) ); + if (!state.IsValid()) + FAIL() << state.GetRejectReason(); + // Verify transaction is still in mempool + EXPECT_EQ(mempool.size(), 1); +} + +TEST(test_block, TestProcessBadBlock) +{ + TestChain chain; + auto notary = std::make_shared(chain.getNotaryKey(), "notary"); + auto alice = std::make_shared("alice"); + auto bob = std::make_shared("bob"); + auto charlie = std::make_shared("charlie"); + std::shared_ptr lastBlock = chain.generateBlock(notary); // genesis block + // add a transaction to the mempool + TransactionInProcess fundAlice = notary->CreateSpendTransaction(alice, 100000); + EXPECT_TRUE( chain.acceptTx(fundAlice.transaction).IsValid() ); + // construct the block + CBlock block; + int32_t newHeight = chain.GetIndex()->nHeight + 1; + CValidationState state; + // no transactions + EXPECT_FALSE( ProcessNewBlock(false, newHeight, state, nullptr, &block, false, nullptr) ); + EXPECT_EQ(state.GetRejectReason(), "bad-blk-length"); + // add first a coinbase tx + auto consensusParams = Params().GetConsensus(); + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(consensusParams, newHeight); + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vin[0].scriptSig = (CScript() << newHeight << CScriptNum(1)) + COINBASE_FLAGS; + txNew.vout.resize(1); + txNew.vout[0].nValue = GetBlockSubsidy(newHeight,consensusParams); + txNew.nExpiryHeight = 0; + block.vtx.push_back(CTransaction(txNew)); + // Add no PoW, should fail on merkle error + EXPECT_FALSE( ProcessNewBlock(false, newHeight, state, nullptr, &block, false, nullptr) ); + EXPECT_EQ(state.GetRejectReason(), "bad-txnmrklroot"); + // Verify transaction is still in mempool + EXPECT_EQ(mempool.size(), 1); +} \ No newline at end of file diff --git a/src/test-komodo/test_coinimport.cpp b/src/test-komodo/test_coinimport.cpp index 05c709eb309..717c517406c 100644 --- a/src/test-komodo/test_coinimport.cpp +++ b/src/test-komodo/test_coinimport.cpp @@ -19,6 +19,8 @@ extern Eval* EVAL_TEST; +std::shared_ptr testChain; + namespace TestCoinImport { @@ -54,7 +56,9 @@ class TestCoinImport : public ::testing::Test, public Eval { protected: - static void SetUpTestCase() { setupChain(); } + static void SetUpTestCase() { testChain = std::make_shared(); } + static void TearDownTestCase() { testChain = nullptr; }; + virtual void SetUp() { ASSETCHAINS_CC = 1; EVAL_TEST = this; diff --git a/src/test/coins_tests.cpp b/src/test-komodo/test_coins.cpp similarity index 79% rename from src/test/coins_tests.cpp rename to src/test-komodo/test_coins.cpp index dc795ad7a7b..ef14be5833b 100644 --- a/src/test/coins_tests.cpp +++ b/src/test-komodo/test_coins.cpp @@ -17,11 +17,12 @@ #include #include -#include +#include #include "zcash/IncrementalMerkleTree.hpp" -namespace +namespace TestCoins { + class CCoinsViewTest : public CCoinsView { uint256 hashBestBlock_; @@ -208,7 +209,7 @@ class CCoinsViewCacheTest : public CCoinsViewCache for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) { ret += it->second.coins.DynamicMemoryUsage(); } - BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret); + EXPECT_EQ(DynamicMemoryUsage(), ret); } }; @@ -238,7 +239,6 @@ class TxWithNullifiers } }; -} uint256 appendRandomSproutCommitment(SproutMerkleTree &tree) { @@ -256,20 +256,20 @@ template bool GetAnchorAt(const CCoinsViewCacheTest &cache, const template<> bool GetAnchorAt(const CCoinsViewCacheTest &cache, const uint256 &rt, SproutMerkleTree &tree) { return cache.GetSproutAnchorAt(rt, tree); } template<> bool GetAnchorAt(const CCoinsViewCacheTest &cache, const uint256 &rt, SaplingMerkleTree &tree) { return cache.GetSaplingAnchorAt(rt, tree); } -BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) -void checkNullifierCache(const CCoinsViewCacheTest &cache, const TxWithNullifiers &txWithNullifiers, bool shouldBeInCache) { +void checkNullifierCache(const CCoinsViewCacheTest &cache, const TxWithNullifiers &txWithNullifiers, bool shouldBeInCache) +{ // Make sure the nullifiers have not gotten mixed up - BOOST_CHECK(!cache.GetNullifier(txWithNullifiers.sproutNullifier, SAPLING)); - BOOST_CHECK(!cache.GetNullifier(txWithNullifiers.saplingNullifier, SPROUT)); + EXPECT_TRUE(!cache.GetNullifier(txWithNullifiers.sproutNullifier, SAPLING)); + EXPECT_TRUE(!cache.GetNullifier(txWithNullifiers.saplingNullifier, SPROUT)); // Check if the nullifiers either are or are not in the cache bool containsSproutNullifier = cache.GetNullifier(txWithNullifiers.sproutNullifier, SPROUT); bool containsSaplingNullifier = cache.GetNullifier(txWithNullifiers.saplingNullifier, SAPLING); - BOOST_CHECK(containsSproutNullifier == shouldBeInCache); - BOOST_CHECK(containsSaplingNullifier == shouldBeInCache); + EXPECT_TRUE(containsSproutNullifier == shouldBeInCache); + EXPECT_TRUE(containsSaplingNullifier == shouldBeInCache); } -BOOST_AUTO_TEST_CASE(nullifier_regression_test) +TEST(TestCoins, nullifier_regression_test) { // Correct behavior: { @@ -357,7 +357,8 @@ BOOST_AUTO_TEST_CASE(nullifier_regression_test) } } -template void anchorPopRegressionTestImpl(ShieldedType type) +template +void anchorPopRegressionTestImpl(ShieldedType type) { // Correct behavior: { @@ -383,8 +384,8 @@ template void anchorPopRegressionTestImpl(ShieldedType type) // The base contains the anchor, of course! { Tree checkTree; - BOOST_CHECK(GetAnchorAt(cache1, tree.root(), checkTree)); - BOOST_CHECK(checkTree.root() == tree.root()); + EXPECT_TRUE(GetAnchorAt(cache1, tree.root(), checkTree)); + EXPECT_TRUE(checkTree.root() == tree.root()); } } @@ -415,8 +416,8 @@ template void anchorPopRegressionTestImpl(ShieldedType type) // treestate... { Tree checktree; - BOOST_CHECK(GetAnchorAt(cache1, tree.root(), checktree)); - BOOST_CHECK(checktree.root() == tree.root()); // Oh, shucks. + EXPECT_TRUE(GetAnchorAt(cache1, tree.root(), checktree)); + EXPECT_TRUE(checktree.root() == tree.root()); // Oh, shucks. } // Flushing cache won't help either, just makes the inconsistency @@ -424,23 +425,20 @@ template void anchorPopRegressionTestImpl(ShieldedType type) cache1.Flush(); { Tree checktree; - BOOST_CHECK(GetAnchorAt(cache1, tree.root(), checktree)); - BOOST_CHECK(checktree.root() == tree.root()); // Oh, shucks. + EXPECT_TRUE(GetAnchorAt(cache1, tree.root(), checktree)); + EXPECT_TRUE(checktree.root() == tree.root()); // Oh, shucks. } } } -BOOST_AUTO_TEST_CASE(anchor_pop_regression_test) +TEST(TestCoins, anchor_pop_regression_test) { - BOOST_TEST_CONTEXT("Sprout") { - anchorPopRegressionTestImpl(SPROUT); - } - BOOST_TEST_CONTEXT("Sapling") { - anchorPopRegressionTestImpl(SAPLING); - } + anchorPopRegressionTestImpl(SPROUT); + anchorPopRegressionTestImpl(SAPLING); } -template void anchorRegressionTestImpl(ShieldedType type) +template +void anchorRegressionTestImpl(ShieldedType type) { // Correct behavior: { @@ -455,8 +453,8 @@ template void anchorRegressionTestImpl(ShieldedType type) cache1.Flush(); cache1.PopAnchor(Tree::empty_root(), type); - BOOST_CHECK(cache1.GetBestAnchor(type) == Tree::empty_root()); - BOOST_CHECK(!GetAnchorAt(cache1, tree.root(), tree)); + EXPECT_TRUE(cache1.GetBestAnchor(type) == Tree::empty_root()); + EXPECT_TRUE(!GetAnchorAt(cache1, tree.root(), tree)); } // Also correct behavior: @@ -472,8 +470,8 @@ template void anchorRegressionTestImpl(ShieldedType type) cache1.PopAnchor(Tree::empty_root(), type); cache1.Flush(); - BOOST_CHECK(cache1.GetBestAnchor(type) == Tree::empty_root()); - BOOST_CHECK(!GetAnchorAt(cache1, tree.root(), tree)); + EXPECT_TRUE(cache1.GetBestAnchor(type) == Tree::empty_root()); + EXPECT_TRUE(!GetAnchorAt(cache1, tree.root(), tree)); } // Works because we bring the anchor in from parent cache. @@ -490,13 +488,13 @@ template void anchorRegressionTestImpl(ShieldedType type) { // Pop anchor. CCoinsViewCacheTest cache2(&cache1); - BOOST_CHECK(GetAnchorAt(cache2, tree.root(), tree)); + EXPECT_TRUE(GetAnchorAt(cache2, tree.root(), tree)); cache2.PopAnchor(Tree::empty_root(), type); cache2.Flush(); } - BOOST_CHECK(cache1.GetBestAnchor(type) == Tree::empty_root()); - BOOST_CHECK(!GetAnchorAt(cache1, tree.root(), tree)); + EXPECT_TRUE(cache1.GetBestAnchor(type) == Tree::empty_root()); + EXPECT_TRUE(!GetAnchorAt(cache1, tree.root(), tree)); } // Was broken: @@ -517,22 +515,18 @@ template void anchorRegressionTestImpl(ShieldedType type) cache2.Flush(); } - BOOST_CHECK(cache1.GetBestAnchor(type) == Tree::empty_root()); - BOOST_CHECK(!GetAnchorAt(cache1, tree.root(), tree)); + EXPECT_TRUE(cache1.GetBestAnchor(type) == Tree::empty_root()); + EXPECT_TRUE(!GetAnchorAt(cache1, tree.root(), tree)); } } -BOOST_AUTO_TEST_CASE(anchor_regression_test) +TEST(TestCoins, anchor_regression_test) { - BOOST_TEST_CONTEXT("Sprout") { - anchorRegressionTestImpl(SPROUT); - } - BOOST_TEST_CONTEXT("Sapling") { - anchorRegressionTestImpl(SAPLING); - } + anchorRegressionTestImpl(SPROUT); + anchorRegressionTestImpl(SAPLING); } -BOOST_AUTO_TEST_CASE(nullifiers_test) +TEST(TestCoins, nullifiers_test) { CCoinsViewTest base; CCoinsViewCacheTest cache(&base); @@ -555,14 +549,15 @@ BOOST_AUTO_TEST_CASE(nullifiers_test) checkNullifierCache(cache3, txWithNullifiers, false); } -template void anchorsFlushImpl(ShieldedType type) +template +void anchorsFlushImpl(ShieldedType type) { CCoinsViewTest base; uint256 newrt; { CCoinsViewCacheTest cache(&base); Tree tree; - BOOST_CHECK(GetAnchorAt(cache, cache.GetBestAnchor(type), tree)); + EXPECT_TRUE(GetAnchorAt(cache, cache.GetBestAnchor(type), tree)); tree.append(GetRandHash()); newrt = tree.root(); @@ -574,28 +569,24 @@ template void anchorsFlushImpl(ShieldedType type) { CCoinsViewCacheTest cache(&base); Tree tree; - BOOST_CHECK(GetAnchorAt(cache, cache.GetBestAnchor(type), tree)); + EXPECT_TRUE(GetAnchorAt(cache, cache.GetBestAnchor(type), tree)); // Get the cached entry. - BOOST_CHECK(GetAnchorAt(cache, cache.GetBestAnchor(type), tree)); + EXPECT_TRUE(GetAnchorAt(cache, cache.GetBestAnchor(type), tree)); uint256 check_rt = tree.root(); - BOOST_CHECK(check_rt == newrt); + EXPECT_TRUE(check_rt == newrt); } } -BOOST_AUTO_TEST_CASE(anchors_flush_test) +TEST(TestCoins, anchors_flush_test) { - BOOST_TEST_CONTEXT("Sprout") { - anchorsFlushImpl(SPROUT); - } - BOOST_TEST_CONTEXT("Sapling") { - anchorsFlushImpl(SAPLING); - } + anchorsFlushImpl(SPROUT); + anchorsFlushImpl(SAPLING); } -BOOST_AUTO_TEST_CASE(chained_joinsplits) +TEST(TestCoins, chained_joinsplits) { // TODO update this or add a similar test when the SaplingNote class exist CCoinsViewTest base; @@ -632,7 +623,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) CMutableTransaction mtx; mtx.vjoinsplit.push_back(js2); - BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx)); + EXPECT_TRUE(!cache.HaveJoinSplitRequirements(mtx)); } { @@ -642,7 +633,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) mtx.vjoinsplit.push_back(js2); mtx.vjoinsplit.push_back(js1); - BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx)); + EXPECT_TRUE(!cache.HaveJoinSplitRequirements(mtx)); } { @@ -650,7 +641,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) mtx.vjoinsplit.push_back(js1); mtx.vjoinsplit.push_back(js2); - BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx)); + EXPECT_TRUE(cache.HaveJoinSplitRequirements(mtx)); } { @@ -659,7 +650,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) mtx.vjoinsplit.push_back(js2); mtx.vjoinsplit.push_back(js3); - BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx)); + EXPECT_TRUE(cache.HaveJoinSplitRequirements(mtx)); } { @@ -669,11 +660,12 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) mtx.vjoinsplit.push_back(js2); mtx.vjoinsplit.push_back(js3); - BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx)); + EXPECT_TRUE(cache.HaveJoinSplitRequirements(mtx)); } } -template void anchorsTestImpl(ShieldedType type) +template +void anchorsTestImpl(ShieldedType type) { // TODO: These tests should be more methodical. // Or, integrate with Bitcoin's tests later. @@ -681,13 +673,13 @@ template void anchorsTestImpl(ShieldedType type) CCoinsViewTest base; CCoinsViewCacheTest cache(&base); - BOOST_CHECK(cache.GetBestAnchor(type) == Tree::empty_root()); + EXPECT_TRUE(cache.GetBestAnchor(type) == Tree::empty_root()); { Tree tree; - BOOST_CHECK(GetAnchorAt(cache, cache.GetBestAnchor(type), tree)); - BOOST_CHECK(cache.GetBestAnchor(type) == tree.root()); + EXPECT_TRUE(GetAnchorAt(cache, cache.GetBestAnchor(type), tree)); + EXPECT_TRUE(cache.GetBestAnchor(type) == tree.root()); tree.append(GetRandHash()); tree.append(GetRandHash()); tree.append(GetRandHash()); @@ -703,13 +695,13 @@ template void anchorsTestImpl(ShieldedType type) uint256 newrt2; cache.PushAnchor(tree); - BOOST_CHECK(cache.GetBestAnchor(type) == newrt); + EXPECT_TRUE(cache.GetBestAnchor(type) == newrt); { Tree confirm_same; - BOOST_CHECK(GetAnchorAt(cache, cache.GetBestAnchor(type), confirm_same)); + EXPECT_TRUE(GetAnchorAt(cache, cache.GetBestAnchor(type), confirm_same)); - BOOST_CHECK(confirm_same.root() == newrt); + EXPECT_TRUE(confirm_same.root() == newrt); } tree.append(GetRandHash()); @@ -718,18 +710,18 @@ template void anchorsTestImpl(ShieldedType type) newrt2 = tree.root(); cache.PushAnchor(tree); - BOOST_CHECK(cache.GetBestAnchor(type) == newrt2); + EXPECT_TRUE(cache.GetBestAnchor(type) == newrt2); Tree test_tree; - BOOST_CHECK(GetAnchorAt(cache, cache.GetBestAnchor(type), test_tree)); + EXPECT_TRUE(GetAnchorAt(cache, cache.GetBestAnchor(type), test_tree)); - BOOST_CHECK(tree.root() == test_tree.root()); + EXPECT_TRUE(tree.root() == test_tree.root()); { Tree test_tree2; GetAnchorAt(cache, newrt, test_tree2); - BOOST_CHECK(test_tree2.root() == newrt); + EXPECT_TRUE(test_tree2.root() == newrt); } { @@ -743,14 +735,10 @@ template void anchorsTestImpl(ShieldedType type) } } -BOOST_AUTO_TEST_CASE(anchors_test) +TEST(TestCoins, anchors_test) { - BOOST_TEST_CONTEXT("Sprout") { - anchorsTestImpl(SPROUT); - } - BOOST_TEST_CONTEXT("Sapling") { - anchorsTestImpl(SAPLING); - } + anchorsTestImpl(SPROUT); + anchorsTestImpl(SAPLING); } static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; @@ -764,7 +752,7 @@ static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; // // During the process, booleans are kept to make sure that the randomized // operation hits all branches. -BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) +TEST(TestCoins, coins_cache_simulation_test) { // Various coverage trackers. bool removed_all_caches = false; @@ -796,7 +784,7 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) uint256 txid = txids[insecure_rand() % txids.size()]; // txid we're going to modify in this iteration. CCoins& coins = result[txid]; CCoinsModifier entry = stack.back()->ModifyCoins(txid); - BOOST_CHECK(coins == *entry); + EXPECT_TRUE(coins == *entry); if (insecure_rand() % 5 == 0 || coins.IsPruned()) { if (coins.IsPruned()) { added_an_entry = true; @@ -819,10 +807,10 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) for (std::map::iterator it = result.begin(); it != result.end(); it++) { const CCoins* coins = stack.back()->AccessCoins(it->first); if (coins) { - BOOST_CHECK(*coins == it->second); + EXPECT_TRUE(*coins == it->second); found_an_entry = true; } else { - BOOST_CHECK(it->second.IsPruned()); + EXPECT_TRUE(it->second.IsPruned()); missed_an_entry = true; } } @@ -860,16 +848,16 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) } // Verify coverage. - BOOST_CHECK(removed_all_caches); - BOOST_CHECK(reached_4_caches); - BOOST_CHECK(added_an_entry); - BOOST_CHECK(removed_an_entry); - BOOST_CHECK(updated_an_entry); - BOOST_CHECK(found_an_entry); - BOOST_CHECK(missed_an_entry); + EXPECT_TRUE(removed_all_caches); + EXPECT_TRUE(reached_4_caches); + EXPECT_TRUE(added_an_entry); + EXPECT_TRUE(removed_an_entry); + EXPECT_TRUE(updated_an_entry); + EXPECT_TRUE(found_an_entry); + EXPECT_TRUE(missed_an_entry); } -BOOST_AUTO_TEST_CASE(coins_coinbase_spends) +TEST(TestCoins, coins_coinbase_spends) { CCoinsViewTest base; CCoinsViewCacheTest cache(&base); @@ -885,7 +873,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends) CTransaction tx(mtx); - BOOST_CHECK(tx.IsCoinBase()); + EXPECT_TRUE(tx.IsCoinBase()); CValidationState state; UpdateCoins(tx, cache, 100); @@ -899,7 +887,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends) { CTransaction tx2(mtx2); - BOOST_CHECK(Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, Params().GetConsensus())); + EXPECT_TRUE(Consensus::CheckTxInputs(tx2, state, cache, 100+ Params().CoinbaseMaturity(), Params().GetConsensus())); } mtx2.vout.resize(1); @@ -908,63 +896,63 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends) { CTransaction tx2(mtx2); - BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, Params().GetConsensus())); - BOOST_CHECK(state.GetRejectReason() == "bad-txns-coinbase-spend-has-transparent-outputs"); + EXPECT_FALSE(Consensus::CheckTxInputs(tx2, state, cache, 100+Params().CoinbaseMaturity(), Params().GetConsensus())); + EXPECT_TRUE(state.GetRejectReason() == "bad-txns-coinbase-spend-has-transparent-outputs"); } } -BOOST_AUTO_TEST_CASE(ccoins_serialization) +TEST(TestCoins, ccoins_serialization) { // Good example CDataStream ss1(ParseHex("0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e"), SER_DISK, CLIENT_VERSION); CCoins cc1; ss1 >> cc1; - BOOST_CHECK_EQUAL(cc1.nVersion, 1); - BOOST_CHECK_EQUAL(cc1.fCoinBase, false); - BOOST_CHECK_EQUAL(cc1.nHeight, 203998); - BOOST_CHECK_EQUAL(cc1.vout.size(), 2); - BOOST_CHECK_EQUAL(cc1.IsAvailable(0), false); - BOOST_CHECK_EQUAL(cc1.IsAvailable(1), true); - BOOST_CHECK_EQUAL(cc1.vout[1].nValue, 60000000000ULL); - BOOST_CHECK_EQUAL(HexStr(cc1.vout[1].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35")))))); + EXPECT_EQ(cc1.nVersion, 1); + EXPECT_EQ(cc1.fCoinBase, false); + EXPECT_EQ(cc1.nHeight, 203998); + EXPECT_EQ(cc1.vout.size(), 2); + EXPECT_EQ(cc1.IsAvailable(0), false); + EXPECT_EQ(cc1.IsAvailable(1), true); + EXPECT_EQ(cc1.vout[1].nValue, 60000000000ULL); + EXPECT_EQ(HexStr(cc1.vout[1].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35")))))); // Good example CDataStream ss2(ParseHex("0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b"), SER_DISK, CLIENT_VERSION); CCoins cc2; ss2 >> cc2; - BOOST_CHECK_EQUAL(cc2.nVersion, 1); - BOOST_CHECK_EQUAL(cc2.fCoinBase, true); - BOOST_CHECK_EQUAL(cc2.nHeight, 120891); - BOOST_CHECK_EQUAL(cc2.vout.size(), 17); + EXPECT_EQ(cc2.nVersion, 1); + EXPECT_EQ(cc2.fCoinBase, true); + EXPECT_EQ(cc2.nHeight, 120891); + EXPECT_EQ(cc2.vout.size(), 17); for (int i = 0; i < 17; i++) { - BOOST_CHECK_EQUAL(cc2.IsAvailable(i), i == 4 || i == 16); + EXPECT_EQ(cc2.IsAvailable(i), i == 4 || i == 16); } - BOOST_CHECK_EQUAL(cc2.vout[4].nValue, 234925952); - BOOST_CHECK_EQUAL(HexStr(cc2.vout[4].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("61b01caab50f1b8e9c50a5057eb43c2d9563a4ee")))))); - BOOST_CHECK_EQUAL(cc2.vout[16].nValue, 110397); - BOOST_CHECK_EQUAL(HexStr(cc2.vout[16].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); + EXPECT_EQ(cc2.vout[4].nValue, 234925952); + EXPECT_EQ(HexStr(cc2.vout[4].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("61b01caab50f1b8e9c50a5057eb43c2d9563a4ee")))))); + EXPECT_EQ(cc2.vout[16].nValue, 110397); + EXPECT_EQ(HexStr(cc2.vout[16].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); // Smallest possible example CDataStream ssx(SER_DISK, CLIENT_VERSION); - BOOST_CHECK_EQUAL(HexStr(ssx.begin(), ssx.end()), ""); + EXPECT_EQ(HexStr(ssx.begin(), ssx.end()), ""); CDataStream ss3(ParseHex("0002000600"), SER_DISK, CLIENT_VERSION); CCoins cc3; ss3 >> cc3; - BOOST_CHECK_EQUAL(cc3.nVersion, 0); - BOOST_CHECK_EQUAL(cc3.fCoinBase, false); - BOOST_CHECK_EQUAL(cc3.nHeight, 0); - BOOST_CHECK_EQUAL(cc3.vout.size(), 1); - BOOST_CHECK_EQUAL(cc3.IsAvailable(0), true); - BOOST_CHECK_EQUAL(cc3.vout[0].nValue, 0); - BOOST_CHECK_EQUAL(cc3.vout[0].scriptPubKey.size(), 0); + EXPECT_EQ(cc3.nVersion, 0); + EXPECT_EQ(cc3.fCoinBase, false); + EXPECT_EQ(cc3.nHeight, 0); + EXPECT_EQ(cc3.vout.size(), 1); + EXPECT_EQ(cc3.IsAvailable(0), true); + EXPECT_EQ(cc3.vout[0].nValue, 0); + EXPECT_EQ(cc3.vout[0].scriptPubKey.size(), 0); // scriptPubKey that ends beyond the end of the stream CDataStream ss4(ParseHex("0002000800"), SER_DISK, CLIENT_VERSION); try { CCoins cc4; ss4 >> cc4; - BOOST_CHECK_MESSAGE(false, "We should have thrown"); + FAIL() << "We should have thrown"; } catch (const std::ios_base::failure& e) { } @@ -972,14 +960,14 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) CDataStream tmp(SER_DISK, CLIENT_VERSION); uint64_t x = 3000000000ULL; tmp << VARINT(x); - BOOST_CHECK_EQUAL(HexStr(tmp.begin(), tmp.end()), "8a95c0bb00"); + EXPECT_EQ(HexStr(tmp.begin(), tmp.end()), "8a95c0bb00"); CDataStream ss5(ParseHex("0002008a95c0bb0000"), SER_DISK, CLIENT_VERSION); try { CCoins cc5; ss5 >> cc5; - BOOST_CHECK_MESSAGE(false, "We should have thrown"); + FAIL() << "We should have thrown"; } catch (const std::ios_base::failure& e) { } } -BOOST_AUTO_TEST_SUITE_END() +} // namespace TestCoins diff --git a/src/gtest/test_equihash.cpp b/src/test-komodo/test_equihash.cpp similarity index 100% rename from src/gtest/test_equihash.cpp rename to src/test-komodo/test_equihash.cpp diff --git a/src/test-komodo/test_events.cpp b/src/test-komodo/test_events.cpp index f2ae8ad5c16..e281c4ce6c6 100644 --- a/src/test-komodo/test_events.cpp +++ b/src/test-komodo/test_events.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -8,8 +9,10 @@ int32_t komodo_faststateinit(struct komodo_state *sp,const char *fname,char *symbol,char *dest); struct komodo_state *komodo_stateptrget(char *base); extern int32_t KOMODO_EXTERNAL_NOTARIES; +template +size_t write_event(T& evt, FILE *fp); -namespace TestEvents { +namespace test_events { void write_p_record(std::FILE* fp) { @@ -19,6 +22,17 @@ void write_p_record(std::FILE* fp) memset(&data[39], 2, 33); // 2nd key is all 2s std::fwrite(data, sizeof(data), 1, fp); } + +void write_p_record_new(std::FILE* fp) +{ + komodo::event_pubkeys evt; + evt.height = 1; + evt.num = 2; + memset(&evt.pubkeys[0], 1, 33); + memset(&evt.pubkeys[1], 2, 33); + write_event(evt, fp); +} + void write_n_record(std::FILE* fp) { // a notarized record has @@ -114,14 +128,14 @@ void write_b_record(std::FILE* fp) std::fwrite(data, sizeof(data), 1, fp); } template -bool compare_serialization(const std::string& filename, std::shared_ptr in) +bool compare_serialization(const std::string& filename, const T& in) { // read contents of file std::ifstream s(filename, std::ios::binary); std::vector file_contents((std::istreambuf_iterator(s)), std::istreambuf_iterator()); // get contents of in std::stringstream ss; - ss << *(in.get()); + ss << in; std::vector in_contents( (std::istreambuf_iterator(ss)), std::istreambuf_iterator()); bool retval = file_contents == in_contents; if (!retval) @@ -147,18 +161,47 @@ bool compare_serialization(const std::string& filename, std::shared_ptr in) return retval; } +bool compare_files(const std::string& file1, const std::string& file2) +{ + std::ifstream f1(file1, std::ifstream::binary|std::ifstream::ate); + std::ifstream f2(file2, std::ifstream::binary|std::ifstream::ate); + + if (f1.fail() || f2.fail()) { + return false; //file problem + } + + if (f1.tellg() != f2.tellg()) { + return false; //size mismatch + } + + //seek back to beginning and use std::equal to compare contents + f1.seekg(0, std::ifstream::beg); + f2.seekg(0, std::ifstream::beg); + return std::equal(std::istreambuf_iterator(f1.rdbuf()), + std::istreambuf_iterator(), + std::istreambuf_iterator(f2.rdbuf())); +} + +void clear_state(const char* symbol) +{ + komodo_state* state = komodo_stateptrget((char*)symbol); + EXPECT_NE(state, nullptr); + state->events.clear(); +} /**** * The main purpose of this test is to verify that * state files created continue to be readable despite logic * changes. Files need to be readable. The record format should * not change without hardfork protection */ -TEST(TestEvents, komodo_faststateinit_test) +TEST(test_events, komodo_faststateinit_test) { char symbol[] = "TST"; strcpy(ASSETCHAINS_SYMBOL, symbol); KOMODO_EXTERNAL_NOTARIES = 1; + clear_state(symbol); + boost::filesystem::path temp = boost::filesystem::unique_path(); boost::filesystem::create_directories(temp); try @@ -193,9 +236,10 @@ TEST(TestEvents, komodo_faststateinit_test) */ // check that the new way is the same EXPECT_EQ(state->events.size(), 1); - std::shared_ptr ev2 = std::dynamic_pointer_cast(state->events.front()); - EXPECT_EQ(ev2->height, 1); - EXPECT_EQ(ev2->type, komodo::komodo_event_type::EVENT_PUBKEYS); + komodo::event_pubkeys& ev2 = + static_cast( *state->events.front() ); + EXPECT_EQ(ev2.height, 1); + EXPECT_EQ(ev2.type, komodo::komodo_event_type::EVENT_PUBKEYS); // the serialized version should match the input EXPECT_TRUE(compare_serialization(full_filename, ev2)); } @@ -224,9 +268,10 @@ TEST(TestEvents, komodo_faststateinit_test) */ // check that the new way is the same EXPECT_EQ(state->events.size(), 2); - std::shared_ptr ev2 = std::dynamic_pointer_cast( *(++state->events.begin()) ); - EXPECT_EQ(ev2->height, 1); - EXPECT_EQ(ev2->type, komodo::komodo_event_type::EVENT_NOTARIZED); + komodo::event_notarized& ev2 = + static_cast( *(*(++state->events.begin())) ); + EXPECT_EQ(ev2.height, 1); + EXPECT_EQ(ev2.type, komodo::komodo_event_type::EVENT_NOTARIZED); // the serialized version should match the input EXPECT_TRUE(compare_serialization(full_filename, ev2)); } @@ -257,9 +302,9 @@ TEST(TestEvents, komodo_faststateinit_test) EXPECT_EQ(state->events.size(), 3); auto itr = state->events.begin(); std::advance(itr, 2); - std::shared_ptr ev2 = std::dynamic_pointer_cast( *(itr) ); - EXPECT_EQ(ev2->height, 1); - EXPECT_EQ(ev2->type, komodo::komodo_event_type::EVENT_NOTARIZED); + komodo::event_notarized& ev2 = static_cast( *(*(itr)) ); + EXPECT_EQ(ev2.height, 1); + EXPECT_EQ(ev2.type, komodo::komodo_event_type::EVENT_NOTARIZED); // the serialized version should match the input EXPECT_TRUE(compare_serialization(full_filename, ev2)); } @@ -288,12 +333,12 @@ TEST(TestEvents, komodo_faststateinit_test) auto itr = state->events.begin(); // this does not get added to state, so we need to serialize the object just // to verify serialization works as expected - std::shared_ptr ev2 = std::make_shared(); - ev2->height = 1; - ev2->n = 'N'; - ev2->nid = 'I'; - memset(ev2->mask, 1, 8); - memset(ev2->hash, 2, 32); + komodo::event_u ev2; + ev2.height = 1; + ev2.n = 'N'; + ev2.nid = 'I'; + memset(ev2.mask, 1, 8); + memset(ev2.hash, 2, 32); EXPECT_TRUE(compare_serialization(full_filename, ev2)); } // record type K (KMD height) @@ -323,9 +368,9 @@ TEST(TestEvents, komodo_faststateinit_test) EXPECT_EQ(state->events.size(), 4); auto itr = state->events.begin(); std::advance(itr, 3); - std::shared_ptr ev2 = std::dynamic_pointer_cast( *(itr) ); - EXPECT_EQ(ev2->height, 1); - EXPECT_EQ(ev2->type, komodo::komodo_event_type::EVENT_KMDHEIGHT); + komodo::event_kmdheight& ev2 = static_cast( *(*(itr)) ); + EXPECT_EQ(ev2.height, 1); + EXPECT_EQ(ev2.type, komodo::komodo_event_type::EVENT_KMDHEIGHT); // the serialized version should match the input EXPECT_TRUE(compare_serialization(full_filename, ev2)); } @@ -356,9 +401,9 @@ TEST(TestEvents, komodo_faststateinit_test) EXPECT_EQ(state->events.size(), 5); auto itr = state->events.begin(); std::advance(itr, 4); - std::shared_ptr ev2 = std::dynamic_pointer_cast( *(itr) ); - EXPECT_EQ(ev2->height, 1); - EXPECT_EQ(ev2->type, komodo::komodo_event_type::EVENT_KMDHEIGHT); + komodo::event_kmdheight& ev2 = static_cast( *(*(itr)) ); + EXPECT_EQ(ev2.height, 1); + EXPECT_EQ(ev2.type, komodo::komodo_event_type::EVENT_KMDHEIGHT); // the serialized version should match the input EXPECT_TRUE(compare_serialization(full_filename, ev2)); } @@ -389,9 +434,9 @@ TEST(TestEvents, komodo_faststateinit_test) EXPECT_EQ(state->events.size(), 6); auto itr = state->events.begin(); std::advance(itr, 5); - std::shared_ptr ev2 = std::dynamic_pointer_cast( *(itr) ); - EXPECT_EQ(ev2->height, 1); - EXPECT_EQ(ev2->type, komodo::komodo_event_type::EVENT_OPRETURN); + komodo::event_opreturn& ev2 = static_cast( *(*(itr)) ); + EXPECT_EQ(ev2.height, 1); + EXPECT_EQ(ev2.type, komodo::komodo_event_type::EVENT_OPRETURN); // the serialized version should match the input EXPECT_TRUE(compare_serialization(full_filename, ev2)); } @@ -422,9 +467,9 @@ TEST(TestEvents, komodo_faststateinit_test) EXPECT_EQ(state->events.size(), 7); auto itr = state->events.begin(); std::advance(itr, 6); - std::shared_ptr ev2 = std::dynamic_pointer_cast( *(itr) ); - EXPECT_EQ(ev2->height, 1); - EXPECT_EQ(ev2->type, komodo::komodo_event_type::EVENT_PRICEFEED); + komodo::event_pricefeed& ev2 = static_cast( *(*(itr)) ); + EXPECT_EQ(ev2.height, 1); + EXPECT_EQ(ev2.type, komodo::komodo_event_type::EVENT_PRICEFEED); // the serialized version should match the input EXPECT_TRUE(compare_serialization(full_filename, ev2)); } @@ -498,38 +543,38 @@ TEST(TestEvents, komodo_faststateinit_test) auto itr = state->events.begin(); std::advance(itr, 7); { - EXPECT_EQ( (*itr)->height, 1); - EXPECT_EQ( (*itr)->type, komodo::komodo_event_type::EVENT_PUBKEYS); + EXPECT_EQ( (**itr).height, 1); + EXPECT_EQ( (**itr).type, komodo::komodo_event_type::EVENT_PUBKEYS); itr++; } { - EXPECT_EQ( (*itr)->height, 1); - EXPECT_EQ( (*itr)->type, komodo::komodo_event_type::EVENT_NOTARIZED); + EXPECT_EQ( (**itr).height, 1); + EXPECT_EQ( (**itr).type, komodo::komodo_event_type::EVENT_NOTARIZED); itr++; } { - EXPECT_EQ( (*itr)->height, 1); - EXPECT_EQ( (*itr)->type, komodo::komodo_event_type::EVENT_NOTARIZED); + EXPECT_EQ( (**itr).height, 1); + EXPECT_EQ( (**itr).type, komodo::komodo_event_type::EVENT_NOTARIZED); itr++; } { - EXPECT_EQ( (*itr)->height, 1); - EXPECT_EQ( (*itr)->type, komodo::komodo_event_type::EVENT_KMDHEIGHT); + EXPECT_EQ( (**itr).height, 1); + EXPECT_EQ( (**itr).type, komodo::komodo_event_type::EVENT_KMDHEIGHT); itr++; } { - EXPECT_EQ( (*itr)->height, 1); - EXPECT_EQ( (*itr)->type, komodo::komodo_event_type::EVENT_KMDHEIGHT); + EXPECT_EQ( (**itr).height, 1); + EXPECT_EQ( (**itr).type, komodo::komodo_event_type::EVENT_KMDHEIGHT); itr++; } { - EXPECT_EQ( (*itr)->height, 1); - EXPECT_EQ( (*itr)->type, komodo::komodo_event_type::EVENT_OPRETURN); + EXPECT_EQ( (**itr).height, 1); + EXPECT_EQ( (**itr).type, komodo::komodo_event_type::EVENT_OPRETURN); itr++; } { - EXPECT_EQ( (*itr)->height, 1); - EXPECT_EQ( (*itr)->type, komodo::komodo_event_type::EVENT_PRICEFEED); + EXPECT_EQ( (**itr).height, 1); + EXPECT_EQ( (**itr).type, komodo::komodo_event_type::EVENT_PRICEFEED); itr++; } } @@ -541,7 +586,7 @@ TEST(TestEvents, komodo_faststateinit_test) boost::filesystem::remove_all(temp); } -TEST(TestEvents, komodo_faststateinit_test_kmd) +TEST(test_events, komodo_faststateinit_test_kmd) { // Nothing should be added to events if this is the komodo chain @@ -549,6 +594,8 @@ TEST(TestEvents, komodo_faststateinit_test_kmd) ASSETCHAINS_SYMBOL[0] = 0; KOMODO_EXTERNAL_NOTARIES = 0; + clear_state(symbol); + boost::filesystem::path temp = boost::filesystem::unique_path(); boost::filesystem::create_directories(temp); try @@ -761,4 +808,83 @@ TEST(TestEvents, komodo_faststateinit_test_kmd) boost::filesystem::remove_all(temp); } -} // namespace TestEvents \ No newline at end of file +TEST(test_events, write_test) +{ + char symbol[] = "TST"; + strcpy(ASSETCHAINS_SYMBOL, symbol); + KOMODO_EXTERNAL_NOTARIES = 1; + + clear_state(symbol); + + boost::filesystem::path temp = boost::filesystem::unique_path(); + boost::filesystem::create_directories(temp); + + const std::string full_filename = (temp / "kstate.tmp").string(); + const std::string full_filename2 = (temp / "kstate2.tmp").string(); + try + { + { + // old way + std::FILE* fp = std::fopen(full_filename.c_str(), "wb+"); + EXPECT_NE(fp, nullptr); + write_p_record(fp); + std::fclose(fp); + // verify files still exists + EXPECT_TRUE(boost::filesystem::exists(full_filename)); + // attempt to read the file + komodo_state* state = komodo_stateptrget((char*)symbol); + EXPECT_NE(state, nullptr); + char* dest = nullptr; + int32_t result = komodo_faststateinit( state, full_filename.c_str(), symbol, dest); + // compare results + EXPECT_EQ(result, 1); + // check that the new way is the same + EXPECT_EQ(state->events.size(), 1); + komodo::event_pubkeys& ev = static_cast( *state->events.front() ); + EXPECT_EQ(ev.height, 1); + EXPECT_EQ(ev.type, komodo::komodo_event_type::EVENT_PUBKEYS); + } + { + // new way + std::FILE* fp = std::fopen(full_filename2.c_str(), "wb+"); + EXPECT_NE(fp, nullptr); + write_p_record_new(fp); + std::fclose(fp); + EXPECT_TRUE(boost::filesystem::exists(full_filename2)); + // the two files should be binarily equal + EXPECT_TRUE( compare_files(full_filename, full_filename2) ); + } + } + catch(...) + { + FAIL() << "Exception thrown"; + } + boost::filesystem::remove_all(temp); +} + +TEST(test_events, event_copy) +{ + // make an object + komodo::event_pubkeys pk1(1); + pk1.num = 2; + memset(pk1.pubkeys[0], 1, 33); + memset(pk1.pubkeys[1], 2, 33); + // make a copy + std::vector> events; + events.push_back( std::make_shared(pk1) ); + komodo::event_pubkeys& pk2 = static_cast(*events.front()); + // are they equal? + EXPECT_EQ(pk1.height, pk2.height); + EXPECT_EQ(pk1.num, pk2.num); + for(uint8_t i = 0; i < pk1.num; ++i) + { + for(uint8_t j = 0; j < 33; ++j) + { + if (pk1.pubkeys[i][j] != pk2.pubkeys[i][j]) + FAIL() << "Error at " << (int)i << " " << (int)j; + } + } + +} + +} // namespace test_events \ No newline at end of file diff --git a/src/gtest/test_mempool.cpp b/src/test-komodo/test_mempool.cpp similarity index 85% rename from src/gtest/test_mempool.cpp rename to src/test-komodo/test_mempool.cpp index 6ef626e5f90..e92fc092170 100644 --- a/src/gtest/test_mempool.cpp +++ b/src/test-komodo/test_mempool.cpp @@ -10,8 +10,53 @@ #include "policy/fees.h" #include "util.h" -// Implementation is in test_checktransaction.cpp -extern CMutableTransaction GetValidTransaction(); +void CreateJoinSplitSignature(CMutableTransaction& mtx, uint32_t consensusBranchId) { + // Generate an ephemeral keypair. + uint256 joinSplitPubKey; + unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; + crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey); + mtx.joinSplitPubKey = joinSplitPubKey; + + // Compute the correct hSig. + // TODO: #966. + static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); + // Empty output script. + CScript scriptCode; + CTransaction signTx(mtx); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + if (dataToBeSigned == one) { + throw std::runtime_error("SignatureHash failed"); + } + + // Add the signature + assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, + dataToBeSigned.begin(), 32, + joinSplitPrivKey + ) == 0); +} + +CMutableTransaction GetValidTransaction() { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + + CMutableTransaction mtx; + mtx.vin.resize(2); + mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); + mtx.vin[0].prevout.n = 0; + mtx.vin[1].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000002"); + mtx.vin[1].prevout.n = 0; + mtx.vout.resize(2); + // mtx.vout[0].scriptPubKey = + mtx.vout[0].nValue = 0; + mtx.vout[1].nValue = 0; + mtx.vjoinsplit.resize(2); + mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000"); + mtx.vjoinsplit[0].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); + mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000002"); + mtx.vjoinsplit[1].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000003"); + + CreateJoinSplitSignature(mtx, consensusBranchId); + return mtx; +} // Fake the input of transaction 5295156213414ed77f6e538e7e8ebe14492156906b9fe995b242477818789364 // - 532639cc6bebed47c1c69ae36dd498c68a012e74ad12729adbd3dbb56f8f3f4a, 0 @@ -96,12 +141,14 @@ TEST(Mempool, PriorityStatsDoNotCrash) { CTxMemPoolEntry entry(tx, nFees, nTime, dPriority, nHeight, true, false, SPROUT_BRANCH_ID); - // Check it does not crash (ie. the death test fails) - EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(testPool.addUnchecked(tx.GetHash(), entry), ""), ""); + // This should not crash + EXPECT_TRUE(testPool.addUnchecked(tx.GetHash(), entry)); EXPECT_EQ(dPriority, MAX_PRIORITY); } +CCriticalSection& get_cs_main(); // in main.cpp + TEST(Mempool, TxInputLimit) { SelectParams(CBaseChainParams::REGTEST); @@ -119,6 +166,7 @@ TEST(Mempool, TxInputLimit) { // Check it fails as expected CValidationState state1; CTransaction tx1(mtx); + LOCK( get_cs_main() ); EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs)); EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low"); @@ -182,6 +230,7 @@ TEST(Mempool, OverwinterNotActiveYet) { CValidationState state1; CTransaction tx1(mtx); + LOCK( get_cs_main() ); EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs)); EXPECT_EQ(state1.GetRejectReason(), "tx-overwinter-not-active"); @@ -206,6 +255,7 @@ TEST(Mempool, SproutV3TxFailsAsExpected) { CValidationState state1; CTransaction tx1(mtx); + LOCK( get_cs_main() ); EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs)); EXPECT_EQ(state1.GetRejectReason(), "version"); } @@ -227,6 +277,7 @@ TEST(Mempool, SproutV3TxWhenOverwinterActive) { CValidationState state1; CTransaction tx1(mtx); + LOCK( get_cs_main() ); EXPECT_FALSE(AcceptToMemoryPool(pool, state1, tx1, false, &missingInputs)); EXPECT_EQ(state1.GetRejectReason(), "tx-overwinter-flag-not-set"); @@ -248,6 +299,8 @@ TEST(Mempool, SproutNegativeVersionTxWhenOverwinterActive) { mtx.vjoinsplit.resize(0); // no joinsplits mtx.fOverwintered = false; + LOCK( get_cs_main() ); + // A Sprout transaction with version -3 is created using Sprout code (as found in zcashd <= 1.0.14). // First four bytes of transaction, parsed as an uint32_t, has the value: 0xfffffffd // This test simulates an Overwinter node receiving this transaction, but incorrectly deserializing the diff --git a/src/test-komodo/test_notary.cpp b/src/test-komodo/test_notary.cpp new file mode 100644 index 00000000000..3661cf9068f --- /dev/null +++ b/src/test-komodo/test_notary.cpp @@ -0,0 +1,165 @@ +#include "testutils.h" +#include "chainparams.h" +#include "komodo_notary.h" + +#include + +void undo_init_notaries(); // test helper + +namespace TestNotary +{ + +/*** + * A little class to help with the different formats keys come in + */ +class my_key +{ +public: + my_key(uint8_t in[33]) + { + for(int i = 0; i < 33; ++i) + key.push_back(in[i]); + } + my_key(const std::string& in) + { + for(int i = 0; i < 33; ++i) + key.push_back( + (unsigned int)strtol(in.substr(i*2, 2).c_str(), nullptr, 16) ); + } + bool fill(uint8_t in[33]) + { + memcpy(in, key.data(), 33); + return true; + } +private: + std::vector key; + friend bool operator==(const my_key& lhs, const my_key& rhs); +}; + +bool operator==(const my_key& lhs, const my_key& rhs) +{ + if (lhs.key == rhs.key) + return true; + return false; +} + +TEST(TestNotary, KomodoNotaries) +{ + // Test komodo_notaries(), getkmdseason() + ASSETCHAINS_SYMBOL[0] = 0; + undo_init_notaries(); + uint8_t pubkeys[64][33]; + int32_t height = 0; + uint32_t timestamp = 0; + // Get the pubkeys of the first era + int32_t result = komodo_notaries(pubkeys, height, timestamp); + EXPECT_EQ(result, 35); + // the first notary didn't change between era 1 and 2, so look at the 2nd notary + EXPECT_EQ( my_key(pubkeys[1]), my_key("02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344")); + // make sure the era hasn't changed before it is supposed to + for(;height <= 179999; ++height) + { + result = komodo_notaries(pubkeys, height, timestamp); + EXPECT_EQ(result, 35); + EXPECT_EQ( getkmdseason(height), 1); + EXPECT_EQ( my_key(pubkeys[1]), my_key("02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344")); + } + EXPECT_EQ(height, 180000); + // at 180000 we start using notaries_elected(komodo_defs.h) instead of Notaries_genesis(komodo_notary.cpp) + for(;height <= 814000; ++height) + { + result = komodo_notaries(pubkeys, height, timestamp); + EXPECT_EQ(result, 64); + EXPECT_EQ( getkmdseason(height), 1); + EXPECT_EQ( my_key(pubkeys[1]), my_key("02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344")); + } + // make sure the era changes when it was supposed to, and we have a new key + EXPECT_EQ(height, 814001); + result = komodo_notaries(pubkeys, height, timestamp); + EXPECT_EQ(result, 64); + EXPECT_EQ( getkmdseason(height), 2); + EXPECT_EQ( my_key(pubkeys[1]), my_key("030f34af4b908fb8eb2099accb56b8d157d49f6cfb691baa80fdd34f385efed961") ); + + // now try the same thing with notaries_staked, which uses timestamp instead of height + // NOTE: If height is passed instead of timestamp, the timestamp is computed based on block timestamps + // notaries come from notaries_STAKED(notaries_staked.h) + // also tests STAKED_era() + height = 0; + timestamp = 1; + undo_init_notaries(); + strcpy(ASSETCHAINS_SYMBOL, "LABS"); + // we should be in era 1 now + result = komodo_notaries(pubkeys, height, timestamp); + EXPECT_EQ(result, 22); + EXPECT_EQ( STAKED_era(timestamp), 1); + EXPECT_EQ( my_key(pubkeys[13]), my_key("03669457b2934d98b5761121dd01b243aed336479625b293be9f8c43a6ae7aaeff")); + timestamp = 1572523200; + EXPECT_EQ(result, 22); + EXPECT_EQ( STAKED_era(timestamp), 1); + EXPECT_EQ( my_key(pubkeys[13]), my_key("03669457b2934d98b5761121dd01b243aed336479625b293be9f8c43a6ae7aaeff")); + // Moving to era 2 should change the notaries. But there is a gap of 777 that uses komodo notaries for some reason + // (NOTE: the first 12 are the same, so use the 13th) + timestamp++; + EXPECT_EQ(timestamp, 1572523201); + result = komodo_notaries(pubkeys, height, timestamp); + EXPECT_EQ(result, 64); + EXPECT_EQ( STAKED_era(timestamp), 0); + EXPECT_EQ( pubkeys[13][0], 0); + // advance past the gap + timestamp += 778; + result = komodo_notaries(pubkeys, height, timestamp); + EXPECT_EQ(result, 24); + EXPECT_EQ( STAKED_era(timestamp), 2); + EXPECT_EQ( my_key(pubkeys[13]), my_key("02d1dd4c5d5c00039322295aa965f9787a87d234ed4f8174231bbd6162e384eba8")); + + // now test getacseason() + EXPECT_EQ( getacseason(0), 1); + EXPECT_EQ( getacseason(1), 1); + EXPECT_EQ( getacseason(1525132800), 1); + EXPECT_EQ( getacseason(1525132801), 2); + EXPECT_EQ( getacseason(1751328000), 7); + EXPECT_EQ( getacseason(1751328001), 0); + + // cleanup + undo_init_notaries(); +} + +TEST(TestNotary, ElectedNotary) +{ + // exercise the routine that checks to see if a particular public key is a notary at the current height + + // setup + undo_init_notaries(); + my_key first_era("02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344"); + my_key second_era("030f34af4b908fb8eb2099accb56b8d157d49f6cfb691baa80fdd34f385efed961"); + + int32_t numnotaries; + uint8_t pubkey[33]; + first_era.fill(pubkey); + int32_t height = 0; + uint32_t timestamp = 0; + + // check the KMD chain, first era + ASSETCHAINS_SYMBOL[0] = 0; + int32_t result = komodo_electednotary(&numnotaries, pubkey, height, timestamp); + EXPECT_EQ(result, 1); + EXPECT_EQ( numnotaries, 35); + // now try a wrong key + second_era.fill(pubkey); + result = komodo_electednotary(&numnotaries, pubkey, height, timestamp); + EXPECT_EQ(result, -1); + EXPECT_EQ(numnotaries, 35); + + // KMD chain, second era + height = 814001; + result = komodo_electednotary(&numnotaries, pubkey, height, timestamp); + EXPECT_EQ(result, 1); + EXPECT_EQ( numnotaries, 64); + // now try a wrong key + first_era.fill(pubkey); + result = komodo_electednotary(&numnotaries, pubkey, height, timestamp); + EXPECT_EQ(result, -1); + EXPECT_EQ(numnotaries, 64); +} + +} // namespace TestNotary \ No newline at end of file diff --git a/src/test-komodo/test_parse_notarisation.cpp b/src/test-komodo/test_parse_notarisation.cpp index 9eab052d2f0..3d80c5d3f02 100644 --- a/src/test-komodo/test_parse_notarisation.cpp +++ b/src/test-komodo/test_parse_notarisation.cpp @@ -7,6 +7,7 @@ #include "komodo_structs.h" #include "test_parse_notarisation.h" +#include #include komodo_state *komodo_stateptr(char *symbol,char *dest); @@ -15,6 +16,11 @@ void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t not const notarized_checkpoint *komodo_npptr(int32_t height); int32_t komodo_prevMoMheight(); int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp); +// method in komodo_utils.cpp: +void set_kmd_user_password_port(const std::string& ltc_config_filename); +extern char KMDUSERPASS[8705]; +extern char BTCUSERPASS[8192]; +extern uint16_t DEST_PORT; class komodo_state_accessor : public komodo_state { @@ -406,8 +412,13 @@ TEST(TestParseNotarisation, test_notarizeddata) EXPECT_EQ(txid, expected_txid); } -TEST(TestParseNotarisation, OldVsNew) +TEST(TestParseNotarisation, DISABLED_OldVsNew) { + /*** + * This test requires a binary file of notarization data + * as well as a long time to run. Re-enable this test to check + * the notarization checkpoints. + */ ASSETCHAINS_SYMBOL[0] = 0; char symbol[4] = { 0 }; char dest[4] = { 0 }; @@ -520,4 +531,99 @@ TEST(TestParseNotarisation, OldVsNew) // for l in `g 'parse notarisation' ~/.komodo/debug.log | pyline 'l.split()[8]'`; do hoek decodeTx '{"hex":"'`src/komodo-cli getrawtransaction "$l"`'"}' | jq '.outputs[1].script.op_return' | pyline 'import base64; print base64.b64decode(l).encode("hex")'; done +TEST(TestParseNotarisation, FilePaths) +{ + // helper for home directory + class MockDataDirectory + { + public: + MockDataDirectory() + { + ClearDatadirCache(); + data_path = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + auto komodo_path = data_path / ".komodo" / "regtest"; + boost::filesystem::create_directories(komodo_path); + orig_home = getenv("HOME"); + setenv("HOME", data_path.c_str(), true); + } + ~MockDataDirectory() + { + boost::filesystem::remove_all(data_path); + setenv("HOME", orig_home.c_str(), true); + ClearDatadirCache(); + } + bool create_config(const std::string& filename, const std::string& user, + const std::string& pass, uint16_t port) + { + std::string file = (data_path / ".komodo" / "regtest" / filename).string(); + std::ofstream komodo(file); + komodo << "rpcuser=" << user << "\n" + << "rpcpassword=" << pass << "\n" + << "rpcport=" << std::to_string(port) << "\n"; + return true; + } + boost::filesystem::path data_path; + std::string orig_home; + }; + { + // default + MockDataDirectory home; + mapArgs.erase("-datadir"); + ASSETCHAINS_P2PPORT = 0; + ASSETCHAINS_RPCPORT = 0; + memset(KMDUSERPASS, 0, sizeof(KMDUSERPASS) ); + memset(BTCUSERPASS, 0, sizeof(BTCUSERPASS) ); + DEST_PORT=0; + IS_KOMODO_NOTARY = 0; + home.create_config("komodo.conf", "test1", "my_password", 1234); + home.create_config("ltc.conf", "test2", "ltc_password", 5678); + set_kmd_user_password_port("ltc.conf"); + EXPECT_EQ( std::string(KMDUSERPASS), std::string("test1:my_password") ); + EXPECT_EQ( std::string(BTCUSERPASS), std::string("")); + EXPECT_EQ(DEST_PORT, 0); + EXPECT_EQ(ASSETCHAINS_P2PPORT, 7770); + EXPECT_EQ(ASSETCHAINS_RPCPORT, 7771); + } + { + // with -datadir + MockDataDirectory home; + mapArgs["-datadir"] = home.data_path.string() + "/.komodo"; + ASSETCHAINS_P2PPORT = 0; + ASSETCHAINS_RPCPORT = 0; + memset(KMDUSERPASS, 0, sizeof(KMDUSERPASS) ); + memset(BTCUSERPASS, 0, sizeof(BTCUSERPASS) ); + DEST_PORT=0; + IS_KOMODO_NOTARY = 0; + std::string expected_kmd("test1:my_password"); + home.create_config("komodo.conf", "test1", "my_password", 1234); + home.create_config("ltc.conf", "test2", "ltc_password", 5678); + set_kmd_user_password_port("ltc.conf"); + EXPECT_EQ( std::string(KMDUSERPASS), std::string("test1:my_password") ); + EXPECT_EQ( std::string(BTCUSERPASS), std::string("")); + EXPECT_EQ(DEST_PORT, 0); + EXPECT_EQ(ASSETCHAINS_P2PPORT, 7770); + EXPECT_EQ(ASSETCHAINS_RPCPORT, 7771); + } + { + // with -notary + MockDataDirectory home; + mapArgs["-datadir"] = home.data_path.string() + "/.komodo"; + ASSETCHAINS_P2PPORT = 0; + ASSETCHAINS_RPCPORT = 0; + memset(KMDUSERPASS, 0, sizeof(KMDUSERPASS) ); + memset(BTCUSERPASS, 0, sizeof(BTCUSERPASS) ); + DEST_PORT=0; + IS_KOMODO_NOTARY = 1; + std::string expected_kmd("test1:my_password"); + home.create_config("komodo.conf", "test1", "my_password", 1234); + home.create_config("ltc.conf", "test2", "ltc_password", 5678); + set_kmd_user_password_port("ltc.conf"); + EXPECT_EQ(std::string(KMDUSERPASS), std::string("test1:my_password")); + EXPECT_EQ(std::string(BTCUSERPASS), std::string("test2:ltc_password")); + EXPECT_EQ(DEST_PORT, 5678); + EXPECT_EQ(ASSETCHAINS_P2PPORT, 7770); + EXPECT_EQ(ASSETCHAINS_RPCPORT, 7771); + } } + +} // namespace TestParseNotarisation diff --git a/src/gtest/test_pow.cpp b/src/test-komodo/test_pow.cpp similarity index 67% rename from src/gtest/test_pow.cpp rename to src/test-komodo/test_pow.cpp index 4557f6db11d..e06f6f80286 100644 --- a/src/gtest/test_pow.cpp +++ b/src/test-komodo/test_pow.cpp @@ -1,9 +1,9 @@ -#include #include "chain.h" #include "chainparams.h" #include "pow.h" #include "random.h" +#include TEST(PoW, DifficultyAveraging) { SelectParams(CBaseChainParams::MAIN); @@ -73,16 +73,19 @@ TEST(PoW, MinDifficultyRules) { SelectParams(CBaseChainParams::TESTNET); const Consensus::Params& params = Params().GetConsensus(); size_t lastBlk = 2*params.nPowAveragingWindow; - size_t firstBlk = lastBlk - params.nPowAveragingWindow; + const uint32_t startTime = 1269211443; // Start with blocks evenly-spaced and equal difficulty std::vector blocks(lastBlk+1); + uint32_t nextTime = startTime; for (int i = 0; i <= lastBlk; i++) { + nextTime = nextTime + params.nPowTargetSpacing; blocks[i].pprev = i ? &blocks[i - 1] : nullptr; blocks[i].nHeight = params.nPowAllowMinDifficultyBlocksAfterHeight.get() + i; - blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; + blocks[i].nTime = nextTime; blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */ - blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + + GetBlockProof(blocks[i - 1]) : arith_uint256(0); } // Create a new block at the target spacing @@ -96,16 +99,50 @@ TEST(PoW, MinDifficultyRules) { bnRes *= params.AveragingWindowTimespan(); EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact()); - // Delay last block up to the edge of the min-difficulty limit + // Delay last block a bit, time warp protection should prevent any change next.nTime += params.nPowTargetSpacing * 5; // Result should be unchanged, modulo integer division precision loss EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact()); - // Delay last block over the min-difficulty limit - next.nTime += 1; + // Delay last block to a huge number. Result should be unchanged, time warp protection + next.nTime = std::numeric_limits::max(); + EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact()); + + // space all blocks out so the median is above the limits and difficulty should drop + nextTime = startTime; + for (int i = 0; i <= lastBlk; i++) { + nextTime = nextTime + ( params.MaxActualTimespan() / params.nPowAveragingWindow + 1); + blocks[i].nTime = nextTime; + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + + GetBlockProof(blocks[i - 1]) : arith_uint256(0); + } + + // difficulty should have decreased ( nBits increased ) + EXPECT_GT(GetNextWorkRequired(&blocks[lastBlk], &next, params), + bnRes.GetCompact()); + + // diffuculty should never decrease below minimum + arith_uint256 minWork = UintToArith256(params.powLimit); + for (int i = 0; i <= lastBlk; i++) { + blocks[i].nBits = minWork.GetCompact(); + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + + GetBlockProof(blocks[i - 1]) : arith_uint256(0); + } + EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), minWork.GetCompact()); + + // space all blocks out so the median is under limits and difficulty should increase + nextTime = startTime; + for (int i = 0; i <= lastBlk; i++) { + nextTime = nextTime + (params.MinActualTimespan() / params.nPowAveragingWindow - 1); + blocks[i].nTime = nextTime; + blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */ + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + + GetBlockProof(blocks[i - 1]) : arith_uint256(0); + } + + // difficulty should have increased ( nBits decreased ) + EXPECT_LT(GetNextWorkRequired(&blocks[lastBlk], &next, params), + bnRes.GetCompact()); - // Result should be the minimum difficulty - EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), - UintToArith256(params.powLimit).GetCompact()); } diff --git a/src/gtest/test_random.cpp b/src/test-komodo/test_random.cpp similarity index 91% rename from src/gtest/test_random.cpp rename to src/test-komodo/test_random.cpp index d89702bcdf4..91d390e05a3 100644 --- a/src/gtest/test_random.cpp +++ b/src/test-komodo/test_random.cpp @@ -2,8 +2,16 @@ #include "random.h" -extern int GenZero(int n); -extern int GenMax(int n); +int GenZero(int n) +{ + return 0; +} + +int GenMax(int n) +{ + return n-1; +} + TEST(Random, MappedShuffle) { std::vector a {8, 4, 6, 3, 5}; diff --git a/src/gtest/test_txid.cpp b/src/test-komodo/test_txid.cpp similarity index 94% rename from src/gtest/test_txid.cpp rename to src/test-komodo/test_txid.cpp index 9b4a21068d1..f3500b08c32 100644 --- a/src/gtest/test_txid.cpp +++ b/src/test-komodo/test_txid.cpp @@ -8,7 +8,7 @@ #include "utilstrencodings.h" /* - Test that removing #1144 succeeded by verifying the hash of a transaction is over the entire serialized form. + Verify the hash of a transaction is over the entire serialized form. */ TEST(txid_tests, check_txid_and_hash_are_same) { // Random zcash transaction aacaa62d40fcdd9192ed35ea9df31660ccf7f6c60566530faaa444fb5d0d410e diff --git a/src/test-komodo/testutils.cpp b/src/test-komodo/testutils.cpp index c17de8bb14b..9119adbf19e 100644 --- a/src/test-komodo/testutils.cpp +++ b/src/test-komodo/testutils.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "core_io.h" #include "key.h" @@ -18,24 +19,66 @@ #include "primitives/transaction.h" #include "script/cc.h" #include "script/interpreter.h" - +#include "komodo_extern_globals.h" +#include "utilmoneystr.h" #include "testutils.h" - +#include "coincontrol.h" +#include "cc/CCinclude.h" std::string notaryPubkey = "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47"; std::string notarySecret = "UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU"; CKey notaryKey; - /* * We need to have control of clock, * otherwise block production can fail. */ int64_t nMockTime; -extern uint32_t USE_EXTERNAL_PUBKEY; +extern int32_t USE_EXTERNAL_PUBKEY; extern std::string NOTARY_PUBKEY; +void adjust_hwmheight(int32_t in); // in komodo.cpp +CCriticalSection& get_cs_main(); // in main.cpp +std::shared_ptr generateBlock(CWallet* wallet, CValidationState* state = nullptr); // in mining.cpp + +void displayTransaction(const CTransaction& tx) +{ + std::cout << "Transaction Hash: " << tx.GetHash().ToString(); + for(size_t i = 0; i < tx.vin.size(); ++i) + { + std::cout << "\nvIn " << i + << " prevout hash : " << tx.vin[i].prevout.hash.ToString() + << " n: " << tx.vin[i].prevout.n; + } + for(size_t i = 0; i < tx.vout.size(); ++i) + { + std::cout << "\nvOut " << i + << " nValue: " << tx.vout[i].nValue + << " scriptPubKey: " << tx.vout[i].scriptPubKey.ToString() + << " interest: " << tx.vout[i].interest; + } + std::cout << "\n"; +} + +void displayBlock(const CBlock& blk) +{ + std::cout << "Block Hash: " << blk.GetHash().ToString() + << "\nPrev Hash: " << blk.hashPrevBlock.ToString() + << "\n"; + for(size_t i = 0; i < blk.vtx.size(); ++i) + { + std::cout << i << " "; + displayTransaction(blk.vtx[i]); + } + std::cout << "\n"; +} + +void setConsoleDebugging(bool enable) +{ + fPrintToConsole = enable; +} + void setupChain() { SelectParams(CBaseChainParams::REGTEST); @@ -44,7 +87,6 @@ void setupChain() NOTARY_PUBKEY = notaryPubkey; USE_EXTERNAL_PUBKEY = 1; mapArgs["-mineraddress"] = "bogus"; - COINBASE_MATURITY = 1; // Global mock time nMockTime = GetTime(); @@ -53,11 +95,6 @@ void setupChain() // Init blockchain ClearDatadirCache(); - auto pathTemp = GetTempPath() / strprintf("test_komodo_%li_%i", GetTime(), GetRand(100000)); - if (ASSETCHAINS_SYMBOL[0]) - pathTemp = pathTemp / strprintf("_%s", ASSETCHAINS_SYMBOL); - boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); pblocktree = new CBlockTreeDB(1 << 20, true); CCoinsViewDB *pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); @@ -65,40 +102,55 @@ void setupChain() InitBlockIndex(); } - +/*** + * Generate a block + * @param block a place to store the block (nullptr skips the disk read) + */ void generateBlock(CBlock *block) { + SetMockTime(nMockTime+=100); // CreateNewBlock can fail if not enough time passes + UniValue params; params.setArray(); params.push_back(1); - uint256 blockId; - - SetMockTime(nMockTime+=100); // CreateNewBlock can fail if not enough time passes try { UniValue out = generate(params, false, CPubKey()); + uint256 blockId; blockId.SetHex(out[0].getValStr()); - if (block) ASSERT_TRUE(ReadBlockFromDisk(*block, mapBlockIndex[blockId], false)); + if (block) + ASSERT_TRUE(ReadBlockFromDisk(*block, mapBlockIndex[blockId], false)); } catch (const UniValue& e) { FAIL() << "failed to create block: " << e.write().data(); } } - +/*** + * Accept a transaction, failing the gtest if the tx is not accepted + * @param tx the transaction to be accepted + */ void acceptTxFail(const CTransaction tx) { CValidationState state; - if (!acceptTx(tx, state)) FAIL() << state.GetRejectReason(); + if (!acceptTx(tx, state)) + FAIL() << state.GetRejectReason(); } bool acceptTx(const CTransaction tx, CValidationState &state) { LOCK(cs_main); - return AcceptToMemoryPool(mempool, state, tx, false, NULL); + bool missingInputs = false; + bool accepted = AcceptToMemoryPool(mempool, state, tx, false, &missingInputs, false, -1); + return accepted && !missingInputs; } - +/*** + * Create a transaction based on input + * @param txIn the vin data (which becomes prevout) + * @param nOut the index of txIn to use as prevout + * @returns the transaction + */ CMutableTransaction spendTx(const CTransaction &txIn, int nOut) { CMutableTransaction mtx; @@ -125,7 +177,7 @@ std::vector getSig(const CMutableTransaction mtx, CScript inputPubKey, * In order to do tests there needs to be inputs to spend. * This method creates a block and returns a transaction that spends the coinbase. */ -void getInputTx(CScript scriptPubKey, CTransaction &txIn) +CTransaction getInputTx(CScript scriptPubKey) { // Get coinbase CBlock block; @@ -143,5 +195,708 @@ void getInputTx(CScript scriptPubKey, CTransaction &txIn) // Accept acceptTxFail(mtx); - txIn = CTransaction(mtx); + return CTransaction(mtx); +} + +/**** + * A class to provide a simple chain for tests + */ + +TestChain::TestChain() +{ + CleanGlobals(); + previousNetwork = Params().NetworkIDString(); + dataDir = GetTempPath() / strprintf("test_komodo_%li_%i", GetTime(), GetRand(100000)); + if (ASSETCHAINS_SYMBOL[0]) + dataDir = dataDir / strprintf("_%s", ASSETCHAINS_SYMBOL); + boost::filesystem::create_directories(dataDir); + mapArgs["-datadir"] = dataDir.string(); + + setupChain(); + USE_EXTERNAL_PUBKEY = 0; // we want control of who mines the block + CBitcoinSecret vchSecret; + vchSecret.SetString(notarySecret); // this returns false due to network prefix mismatch but works anyway + notaryKey = vchSecret.GetKey(); +} + +TestChain::~TestChain() +{ + CleanGlobals(); + // cruel and crude, but cleans up any wallet dbs so subsequent tests run. + bitdb = std::shared_ptr(new CDBEnv{}); + boost::filesystem::remove_all(dataDir); + if (previousNetwork == "main") + SelectParams(CBaseChainParams::MAIN); + if (previousNetwork == "regtest") + SelectParams(CBaseChainParams::REGTEST); + if (previousNetwork == "test") + SelectParams(CBaseChainParams::TESTNET); + +} + +boost::filesystem::path TestChain::GetDataDir() { return dataDir; } + +void TestChain::CleanGlobals() +{ + // hwmheight can get skewed if komodo_connectblock not called (which some tests do) + adjust_hwmheight(0); + for(int i = 0; i < 33; ++i) + { + komodo_state s = KOMODO_STATES[i]; + s.events.clear(); + // TODO: clean notarization points + } +} + +/*** + * Get the block index at the specified height + * @param height the height (0 indicates current height) + * @returns the block index + */ +CBlockIndex *TestChain::GetIndex(uint32_t height) +{ + if (height == 0) + return chainActive.LastTip(); + return chainActive[height]; + +} + +void TestChain::IncrementChainTime() +{ + SetMockTime(nMockTime += 100); +} + +CCoinsViewCache *TestChain::GetCoinsViewCache() +{ + return pcoinsTip; +} + +std::shared_ptr TestChain::generateBlock(std::shared_ptr wallet, CValidationState* state) +{ + std::shared_ptr block; + if (wallet == nullptr) + { + CBlock blk; + ::generateBlock(&blk); + block = std::shared_ptr(new CBlock(blk) ); + } + else + block = ::generateBlock(wallet.get(), state); + return block; +} + +bool TestChain::ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, + bool fJustCheck, bool fCheckPOW) +{ + LOCK( get_cs_main() ); + return ::ConnectBlock(block, state, pindex, *(this->GetCoinsViewCache()), fJustCheck, fCheckPOW); +} + +CKey TestChain::getNotaryKey() { return notaryKey; } + +CValidationState TestChain::acceptTx(const CTransaction& tx) +{ + CValidationState retVal; + bool accepted = ::acceptTx(tx, retVal); + if (!accepted && retVal.IsValid()) + retVal.DoS(100, false, 0U, "acceptTx returned false"); + return retVal; +} + +/****** + * @brief A wallet for testing + * @param chain the chain + * @param name a name for the wallet + */ +TestWallet::TestWallet(const std::string& name) + : CWallet( name + ".dat") +{ + key.MakeNewKey(true); + LOCK(cs_wallet); + bool firstRunRet; + DBErrors err = LoadWallet(firstRunRet); + AddKey(key); + RegisterValidationInterface(this); +} + +/****** + * @brief A wallet for testing + * @param chain the chain + * @param in a key that already exists + * @param name a name for the wallet + */ +TestWallet::TestWallet(const CKey& in, const std::string& name) + : CWallet( name + ".dat"), key(in) +{ + LOCK( cs_wallet ); + bool firstRunRet; + DBErrors err = LoadWallet(firstRunRet); + AddKey(key); + RegisterValidationInterface(this); +} + +TestWallet::~TestWallet() +{ + UnregisterValidationInterface(this); + // TODO: remove file +} + +/*** + * @returns the public key + */ +CPubKey TestWallet::GetPubKey() const { return key.GetPubKey(); } + +/*** + * @returns the private key + */ +CKey TestWallet::GetPrivKey() const { return key; } + +/*** + * Sign a typical transaction + * @param hash the hash to sign + * @param hashType SIGHASH_ALL or something similar + * @returns the bytes to add to ScriptSig +*/ +std::vector TestWallet::Sign(uint256 hash, unsigned char hashType) +{ + std::vector retVal; + key.Sign(hash, retVal); + retVal.push_back(hashType); + return retVal; +} + +/*** + * Sign a cryptocondition + * @param cc the cryptocondition + * @param hash the hash to sign + * @returns the bytes to add to ScriptSig +*/ +std::vector TestWallet::Sign(CC* cc, uint256 hash) +{ + int out = cc_signTreeSecp256k1Msg32(cc, key.begin(), hash.begin()); + return CCSigVec(cc); +} + +/*** + * Transfer to another user + * @param to who to transfer to + * @param amount the amount + * @returns the results + */ +CTransaction TestWallet::Transfer(std::shared_ptr to, CAmount amount, CAmount fee) +{ + TransactionInProcess tip = CreateSpendTransaction(to, amount, fee); + if (!CWallet::CommitTransaction( tip.transaction, tip.reserveKey)) + throw std::logic_error("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + return tip.transaction; +} + +/************* + * @brief Create a transaction, do not place in mempool + * @note throws std::logic_error if there was a problem + * @param to who to send to + * @param amount the amount to send + * @param fee the fee + * @returns the transaction +*/ +TransactionInProcess TestWallet::CreateSpendTransaction(std::shared_ptr to, + CAmount amount, CAmount fee, bool commit) +{ + CAmount curBalance = this->GetBalance(); + CAmount curImatureBalance = this->GetImmatureBalance(); + CAmount curUnconfirmedBalance = this->GetUnconfirmedBalance(); + + // Check amount + if (amount <= 0) + throw std::logic_error("Invalid amount"); + + if (amount > curBalance) + throw std::logic_error("Insufficient funds"); + + // Build recipient vector + std::vector vecSend; + bool fSubtractFeeFromAmount = false; + CRecipient recipient = {GetScriptForDestination(to->GetPubKey()), amount, fSubtractFeeFromAmount}; + vecSend.push_back(recipient); + // other items needed for transaction creation call + CAmount nFeeRequired; + std::string strError; + int nChangePosRet = -1; + TransactionInProcess retVal(this); + if (!CWallet::CreateTransaction(vecSend, retVal.transaction, retVal.reserveKey, nFeeRequired, + nChangePosRet, strError)) + { + if (!fSubtractFeeFromAmount && amount + nFeeRequired > GetBalance()) + strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", + FormatMoney(nFeeRequired)); + throw std::logic_error(strError); + } + + if (commit && !CommitTransaction(retVal.transaction, retVal.reserveKey)) + { + std::logic_error("Unable to commit transaction"); + } + + return retVal; +} + +/************* + * @brief Create a transaction, do not place in mempool + * @note throws std::logic_error if there was a problem + * @param to who to send to + * @param amount the amount to send + * @param fee the fee + * @param txToSpend the specific transaction to spend (ok if not transmitted yet) + * @returns the transaction +*/ +TransactionInProcess TestWallet::CreateSpendTransaction(std::shared_ptr to, + CAmount amount, CAmount fee, CCoinControl& coinControl) +{ + // verify the passed-in transaction has enough funds + std::vector availableTxs; + coinControl.ListSelected(availableTxs); + CTransaction tx; + uint256 hashBlock; + if (!myGetTransaction(availableTxs[0].hash, tx, hashBlock)) + throw std::logic_error("Requested tx not found"); + + CAmount curBalance = tx.vout[availableTxs[0].n].nValue; + + // Check amount + if (amount <= 0) + throw std::logic_error("Invalid amount"); + + if (amount > curBalance) + throw std::logic_error("Insufficient funds"); + + // Build recipient vector + std::vector vecSend; + bool fSubtractFeeFromAmount = false; + CRecipient recipient = {GetScriptForDestination(to->GetPubKey()), amount, fSubtractFeeFromAmount}; + vecSend.push_back(recipient); + // other items needed for transaction creation call + CAmount nFeeRequired; + std::string strError; + int nChangePosRet = -1; + TransactionInProcess retVal(this); + if (!CreateTransaction(vecSend, retVal.transaction, retVal.reserveKey, strError, &coinControl)) + { + if (!fSubtractFeeFromAmount && amount + nFeeRequired > curBalance) + strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", + FormatMoney(nFeeRequired)); + throw std::logic_error(strError); + } + + return retVal; +} + +/**** + * @brief create a transaction spending a vout that is not yet in the wallet + * @param vecSend the recipients + * @param wtxNew the resultant tx + * @param reserveKey the key used + * @param strFailReason the reason for any failure + * @param outputControl the tx to spend + * @returns true on success + */ +bool TestWallet::CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, + CReserveKey& reservekey, std::string& strFailReason, CCoinControl* coinControl) +{ + bool sign = true; + int nChangePosRet = 0; + uint64_t interest2 = 0; + CAmount nValue = 0; + unsigned int nSubtractFeeFromAmount = 0; + BOOST_FOREACH (const CRecipient& recipient, vecSend) + { + if (nValue < 0 || recipient.nAmount < 0) + { + strFailReason = _("Transaction amounts must be positive"); + return false; + } + nValue += recipient.nAmount; + + if (recipient.fSubtractFeeFromAmount) + nSubtractFeeFromAmount++; + } + if (vecSend.empty() || nValue < 0) + { + strFailReason = _("Transaction amounts must be positive"); + return false; + } + + wtxNew.fTimeReceivedIsTxTime = true; + wtxNew.BindWallet(this); + int nextBlockHeight = chainActive.Height() + 1; + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight); + + if (IS_MODE_EXCHANGEWALLET && ASSETCHAINS_SYMBOL[0] == 0) + txNew.nLockTime = 0; + else + { + if ( !komodo_hardfork_active((uint32_t)chainActive.LastTip()->nTime) ) + txNew.nLockTime = (uint32_t)chainActive.LastTip()->nTime + 1; // set to a time close to now + else + txNew.nLockTime = (uint32_t)chainActive.Tip()->GetMedianTimePast(); + } + + // Activates after Overwinter network upgrade + if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (txNew.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD){ + strFailReason = _("nExpiryHeight must be less than TX_EXPIRY_HEIGHT_THRESHOLD."); + return false; + } + } + + unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING; + if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING; + } +/* + // Discourage fee sniping. + // + // However because of a off-by-one-error in previous versions we need to + // neuter it by setting nLockTime to at least one less than nBestHeight. + // Secondly currently propagation of transactions created for block heights + // corresponding to blocks that were just mined may be iffy - transactions + // aren't re-accepted into the mempool - we additionally neuter the code by + // going ten blocks back. Doesn't yet do anything for sniping, but does act + // to shake out wallet bugs like not showing nLockTime'd transactions at + // all. + txNew.nLockTime = std::max(0, chainActive.Height() - 10); + + // Secondly occasionally randomly pick a nLockTime even further back, so + // that transactions that are delayed after signing for whatever reason, + // e.g. high-latency mix networks and some CoinJoin implementations, have + // better privacy. + if (GetRandInt(10) == 0) + txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100)); + + assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); + assert(txNew.nLockTime < LOCKTIME_THRESHOLD);*/ + + { + LOCK2(cs_main, cs_wallet); + { + CAmount nFeeRet = 0; + while (true) + { + txNew.vin.clear(); + txNew.vout.clear(); + wtxNew.fFromMe = true; + nChangePosRet = -1; + bool fFirst = true; + + CAmount nTotalValue = nValue; + if (nSubtractFeeFromAmount == 0) + nTotalValue += nFeeRet; + double dPriority = 0; + // vouts to the payees + BOOST_FOREACH (const CRecipient& recipient, vecSend) + { + CTxOut txout(recipient.nAmount, recipient.scriptPubKey); + + if (recipient.fSubtractFeeFromAmount) + { + txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient + + if (fFirst) // first receiver pays the remainder not divisible by output count + { + fFirst = false; + txout.nValue -= nFeeRet % nSubtractFeeFromAmount; + } + } + + if (txout.IsDust(::minRelayTxFee)) + { + if (recipient.fSubtractFeeFromAmount && nFeeRet > 0) + { + if (txout.nValue < 0) + strFailReason = _("The transaction amount is too small to pay the fee"); + else + strFailReason = _("The transaction amount is too small to send after the fee has been deducted"); + } + else + strFailReason = _("Transaction amount too small"); + return false; + } + txNew.vout.push_back(txout); + } + + // Choose coins to use + std::vector > setCoins; + CAmount nValueIn = 0; + interest2 = 0; + std::vector ctrlVec; + coinControl->ListSelected(ctrlVec); + for(const auto& p : ctrlVec) + { + CTransaction tx; + uint256 hashBlock; + if (myGetTransaction(p.hash, tx, hashBlock)) + { + setCoins.push_back(std::pair(tx, p.n)); + } + } + for(const auto& pcoin : setCoins) + { + CAmount nCredit = pcoin.first.vout[pcoin.second].nValue; + nValueIn += nCredit; + //The coin age after the next block (depth+1) is used instead of the current, + //reflecting an assumption the user would accept a bit more delay for + //a chance at a free transaction. + //But mempool inputs might still be in the mempool, so their age stays 0 + if ( !IS_MODE_EXCHANGEWALLET && ASSETCHAINS_SYMBOL[0] == 0 ) + { + interest2 += pcoin.first.vout[pcoin.second].interest; + } + int age = 0; + if (age != 0) + age += 1; + dPriority += (double)nCredit * age; + } + if ( ASSETCHAINS_SYMBOL[0] == 0 && DONATION_PUBKEY.size() == 66 && interest2 > 5000 ) + { + CScript scriptDonation = CScript() << ParseHex(DONATION_PUBKEY) << OP_CHECKSIG; + CTxOut newTxOut(interest2,scriptDonation); + int32_t nDonationPosRet = txNew.vout.size() - 1; // dont change first or last + std::vector::iterator position = txNew.vout.begin()+nDonationPosRet; + txNew.vout.insert(position, newTxOut); + interest2 = 0; + } + CAmount nChange = (nValueIn - nValue); + if (nSubtractFeeFromAmount == 0) + nChange -= nFeeRet; + + if (nChange > 0) + { + // Fill a vout to ourself + // TODO: pass in scriptChange instead of reservekey so + // change transaction isn't always pay-to-bitcoin-address + CScript scriptChange; + + // coin control: send change to custom address + if (coinControl && !boost::get(&coinControl->destChange)) + scriptChange = GetScriptForDestination(coinControl->destChange); + + // no coin control: send change to newly generated address + else + { + // Note: We use a new key here to keep it from being obvious which side is the change. + // The drawback is that by not reusing a previous key, the change may be lost if a + // backup is restored, if the backup doesn't have the new private key for the change. + // If we reused the old key, it would be possible to add code to look for and + // rediscover unknown transactions that were written with keys of ours to recover + // post-backup change. + + // Reserve a new key pair from key pool + CPubKey vchPubKey; + bool ret; + ret = reservekey.GetReservedKey(vchPubKey); + assert(ret); // should never fail, as we just unlocked + scriptChange = GetScriptForDestination(vchPubKey.GetID()); + } + + CTxOut newTxOut(nChange, scriptChange); + + // We do not move dust-change to fees, because the sender would end up paying more than requested. + // This would be against the purpose of the all-inclusive feature. + // So instead we raise the change and deduct from the recipient. + if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(::minRelayTxFee)) + { + CAmount nDust = newTxOut.GetDustThreshold(::minRelayTxFee) - newTxOut.nValue; + newTxOut.nValue += nDust; // raise change until no more dust + for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient + { + if (vecSend[i].fSubtractFeeFromAmount) + { + txNew.vout[i].nValue -= nDust; + if (txNew.vout[i].IsDust(::minRelayTxFee)) + { + strFailReason = _("The transaction amount is too small to send after the fee has been deducted"); + return false; + } + break; + } + } + } + + // Never create dust outputs; if we would, just + // add the dust to the fee. + if (newTxOut.IsDust(::minRelayTxFee)) + { + nFeeRet += nChange; + reservekey.ReturnKey(); + } + else + { + nChangePosRet = txNew.vout.size() - 1; // dont change first or last + std::vector::iterator position = txNew.vout.begin()+nChangePosRet; + txNew.vout.insert(position, newTxOut); + } + } else reservekey.ReturnKey(); + + // Fill vin + // + // Note how the sequence number is set to max()-1 so that the + // nLockTime set above actually works. + for(const auto& coin : setCoins) + txNew.vin.push_back(CTxIn(coin.first.GetHash(),coin.second,CScript(), + std::numeric_limits::max()-1)); + + // Check mempooltxinputlimit to avoid creating a transaction which the local mempool rejects + size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0); + { + LOCK(cs_main); + if (NetworkUpgradeActive(chainActive.Height() + 1, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + limit = 0; + } + } + if (limit > 0) { + size_t n = txNew.vin.size(); + if (n > limit) { + strFailReason = _(strprintf("Too many transparent inputs %zu > limit %zu", n, limit).c_str()); + return false; + } + } + + // Grab the current consensus branch ID + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + + // Sign + int nIn = 0; + CTransaction txNewConst(txNew); + for(const auto& coin : setCoins) + { + bool signSuccess; + const CScript& scriptPubKey = coin.first.vout[coin.second].scriptPubKey; + SignatureData sigdata; + if (sign) + signSuccess = ProduceSignature(TransactionSignatureCreator( + this, &txNewConst, nIn, coin.first.vout[coin.second].nValue, SIGHASH_ALL), + scriptPubKey, sigdata, consensusBranchId); + else + signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId); + + if (!signSuccess) + { + strFailReason = _("Signing transaction failed"); + return false; + } else { + UpdateTransaction(txNew, nIn, sigdata); + } + + nIn++; + } + + unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); + + // Remove scriptSigs if we used dummy signatures for fee calculation + if (!sign) { + BOOST_FOREACH (CTxIn& vin, txNew.vin) + vin.scriptSig = CScript(); + } + + // Embed the constructed transaction data in wtxNew. + *static_cast(&wtxNew) = CTransaction(txNew); + + // Limit size + if (nBytes >= max_tx_size) + { + strFailReason = _("Transaction too large"); + return false; + } + + dPriority = wtxNew.ComputePriority(dPriority, nBytes); + + // Can we complete this as a free transaction? + if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE) + { + // Not enough fee: enough priority? + double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget); + // Not enough mempool history to estimate: use hard-coded AllowFree. + if (dPriorityNeeded <= 0 && AllowFree(dPriority)) + break; + + // Small enough, and priority high enough, to send for free + if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded) + break; + } + + CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool); + if ( nFeeNeeded < 5000 ) + nFeeNeeded = 5000; + + // If we made it here and we aren't even able to meet the relay fee on the next pass, give up + // because we must be at the maximum allowed fee. + if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes)) + { + strFailReason = _("Transaction too large for fee policy"); + return false; + } + + if (nFeeRet >= nFeeNeeded) + break; // Done, enough fee included. + + // Include more fee and try again. + nFeeRet = nFeeNeeded; + continue; + } + } + } + + return true; +} + +/** + * Call after CreateTransaction unless you want to abort + */ +bool TestWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CValidationState& state) +{ + { + LOCK2(cs_main, cs_wallet); + LogPrintf("CommitTransaction:\n%s", wtxNew.ToString()); + { + // This is only to keep the database open to defeat the auto-flush for the + // duration of this scope. This is the only place where this optimization + // maybe makes sense; please don't do it anywhere else. + CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r+") : NULL; + + // Take key pair from key pool so it won't be used again + reservekey.KeepKey(); + + // Add tx to wallet, because if it has change it's also ours, + // otherwise just for transaction history. + AddToWallet(wtxNew, false, pwalletdb); + + // Notify that old coins are spent + std::set setCoins; + BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) + { + CWalletTx &coin = mapWallet[txin.prevout.hash]; + coin.BindWallet(this); + NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED); + } + + if (fFileBacked) + delete pwalletdb; + } + + // Track how many getdata requests our transaction gets + mapRequestCount[wtxNew.GetHash()] = 0; + + if (fBroadcastTransactions) + { + // Broadcast + if (!::AcceptToMemoryPool(mempool, state, wtxNew, false, nullptr)) + { + fprintf(stderr,"commit failed\n"); + // This must not fail. The transaction has already been signed and recorded. + LogPrintf("CommitTransaction(): Error: Transaction not valid\n"); + return false; + } + wtxNew.RelayWalletTransaction(); + } + } + return true; } diff --git a/src/test-komodo/testutils.h b/src/test-komodo/testutils.h index bbf702f263d..149366b2cdc 100644 --- a/src/test-komodo/testutils.h +++ b/src/test-komodo/testutils.h @@ -1,8 +1,8 @@ -#ifndef TESTUTILS_H -#define TESTUTILS_H +#pragma once #include "main.h" - +#include "wallet/wallet.h" +#include "consensus/validation.h" #define VCH(a,b) std::vector(a, a + b) @@ -16,14 +16,181 @@ extern std::string notaryPubkey; extern std::string notarySecret; extern CKey notaryKey; +/*** + * @brief Look inside a transaction + * @param tx the transaction to look at + */ +void displayTransaction(const CTransaction& tx); +/**** + * @brief Look inside a block + * @param blk the block to look at + */ +void displayBlock(const CBlock& blk); + +void setConsoleDebugging(bool enable); void setupChain(); +/*** + * Generate a block + * @param block a place to store the block (read from disk) + */ void generateBlock(CBlock *block=NULL); bool acceptTx(const CTransaction tx, CValidationState &state); void acceptTxFail(const CTransaction tx); -void getInputTx(CScript scriptPubKey, CTransaction &txIn); +/**** + * In order to do tests there needs to be inputs to spend. + * This method creates a block and returns a transaction that spends the coinbase. + * @param scriptPubKey + * @returns the transaction + */ +CTransaction getInputTx(CScript scriptPubKey); CMutableTransaction spendTx(const CTransaction &txIn, int nOut=0); std::vector getSig(const CMutableTransaction mtx, CScript inputPubKey, int nIn=0); +class TransactionInProcess +{ +public: + TransactionInProcess(CWallet* wallet) : reserveKey(wallet) {} + CWalletTx transaction; + CReserveKey reserveKey; +}; + +class TestWallet; + +class TestChain +{ +public: + /*** + * ctor to create a chain + */ + TestChain(); + /*** + * dtor to release resources + */ + ~TestChain(); + /*** + * Get the block index at the specified height + * @param height the height (0 indicates current height + * @returns the block index + */ + CBlockIndex *GetIndex(uint32_t height = 0); + /*** + * Get this chains view of the state of the chain + * @returns the view + */ + CCoinsViewCache *GetCoinsViewCache(); + /** + * Generate a block + * @returns the block generated + */ + std::shared_ptr generateBlock(std::shared_ptr wallet, + CValidationState* validationState = nullptr); + /**** + * @brief set the chain time to something reasonable + * @note must be called after generateBlock if you + * want to produce another block + */ + void IncrementChainTime(); + /*** + * @returns the notary's key + */ + CKey getNotaryKey(); + /*** + * Add a transactoion to the mempool + * @param tx the transaction + * @returns the results + */ + CValidationState acceptTx(const CTransaction &tx); + /**** + * @brief attempt to connect a block to the chain + * @param block the block to connect + * @param state where to hold the results + * @param pindex the new chain index + * @param justCheck whether or not to do all checks + * @param checkPOW true to check PoW + * @returns true on success + */ + bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, + bool fJustCheck = false,bool fCheckPOW = false); + + boost::filesystem::path GetDataDir(); +private: + boost::filesystem::path dataDir; + std::string previousNetwork; + void CleanGlobals(); +}; -#endif /* TESTUTILS_H */ +/*** + * An easy-to-use wallet for testing Komodo + */ +class TestWallet : public CWallet +{ +public: + TestWallet(const std::string& name); + TestWallet(const CKey& in, const std::string& name); + ~TestWallet(); + /*** + * @returns the public key + */ + CPubKey GetPubKey() const; + /*** + * @returns the private key + */ + CKey GetPrivKey() const; + /*** + * Sign a typical transaction + * @param hash the hash to sign + * @param hashType SIGHASH_ALL or something similar + * @returns the bytes to add to ScriptSig + */ + std::vector Sign(uint256 hash, unsigned char hashType); + /*** + * Sign a cryptocondition + * @param cc the cryptocondition + * @param hash the hash to sign + * @returns the bytes to add to ScriptSig + */ + std::vector Sign(CC* cc, uint256 hash); + /***** + * @brief create a transaction with 1 recipient (signed) + * @param to who to send funds to + * @param amount + * @param fee + * @returns the transaction + */ + TransactionInProcess CreateSpendTransaction(std::shared_ptr to, CAmount amount, + CAmount fee = 0, bool commit = true); + /************* + * @brief Create a transaction, do not place in mempool + * @note throws std::logic_error if there was a problem + * @param to who to send to + * @param amount the amount to send + * @param fee the fee + * @param txToSpend the specific transaction to spend (ok if not transmitted yet) + * @returns the transaction + */ + TransactionInProcess CreateSpendTransaction(std::shared_ptr to, + CAmount amount, CAmount fee, CCoinControl& coinControl); + /**** + * @brief create a transaction spending a vout that is not yet in the wallet + * @param vecSend the recipients + * @param wtxNew the resultant tx + * @param reserveKey the key used + * @param strFailReason the reason for any failure + * @param outputControl the tx to spend + * @returns true on success + */ + bool CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, + CReserveKey& reservekey, std::string& strFailReason, CCoinControl* coinControl); + using CWallet::CommitTransaction; + bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CValidationState& state); + /*** + * Transfer to another user (sends to mempool) + * @param to who to transfer to + * @param amount the amount + * @returns the results + */ + CTransaction Transfer(std::shared_ptr to, CAmount amount, CAmount fee = 0); +private: + CKey key; +}; diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 522f0d8f293..27b3917e027 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -91,7 +91,7 @@ TestingSetup::TestingSetup() // instead of unit tests, but for now we need these here. RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET - bitdb.MakeMock(); + bitdb->MakeMock(); RegisterWalletRPCCommands(tableRPC); #endif ClearDatadirCache(); @@ -129,8 +129,8 @@ TestingSetup::~TestingSetup() delete pcoinsdbview; delete pblocktree; #ifdef ENABLE_WALLET - bitdb.Flush(true); - bitdb.Reset(); + bitdb->Flush(true); + bitdb->Reset(); #endif boost::filesystem::remove_all(pathTemp); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 2ff9dd051ff..24fd01101c1 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -31,7 +31,6 @@ #include "utilmoneystr.h" #include "validationinterface.h" #include "version.h" -#define _COINBASE_MATURITY 100 using namespace std; @@ -399,7 +398,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem // Remove transactions spending a coinbase which are now immature extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; if ( ASSETCHAINS_SYMBOL[0] == 0 ) - COINBASE_MATURITY = _COINBASE_MATURITY; + Params().ResetCoinbaseMaturity(); // Remove transactions spending a coinbase which are now immature and no-longer-final transactions LOCK(cs); list transactionsToRemove; @@ -414,7 +413,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); if (nCheckFrequency != 0) assert(coins); - if (!coins || (coins->IsCoinBase() && (((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY) && + if (!coins || (coins->IsCoinBase() && (((signed long)nMemPoolHeight) - coins->nHeight < Params().CoinbaseMaturity()) && ((signed long)nMemPoolHeight < komodo_block_unlocktime(coins->nHeight) && coins->IsAvailable(0) && coins->vout[0].nValue >= ASSETCHAINS_TIMELOCKGTE))) { transactionsToRemove.push_back(tx); diff --git a/src/util.cpp b/src/util.cpp index fa62ba1ff85..97fee9f45f3 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -529,8 +529,14 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread) } extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; -//int64_t MAX_MONEY = 200000000 * 100000000LL; +/**** + * @brief get the OS-specific default data directory + * @note Windows: be "C:\Users\[username]\AppData\Roaming\Komodo" + * @note Mac: ~/Library/Application Support/Komodo + * @note Unix: ~/.komodo + * @returns the default path to the Komodo data directory + */ boost::filesystem::path GetDefaultDataDir() { namespace fs = boost::filesystem; @@ -649,7 +655,13 @@ const boost::filesystem::path GetExportDir() return path; } - +/**** + * @brief determine the data directory + * @note looks at the -datadir command-line parameter or OS-specific defaults + * @note creates the directory if it does not already exist + * @param fNetSpecific if true, adds network-specific subdirectory (i.e. "regtest" or "testnet3") + * @returns the full OS-specific data directory including Komodo (i.e. "~/.komodo") + */ const boost::filesystem::path &GetDataDir(bool fNetSpecific) { namespace fs = boost::filesystem; @@ -677,8 +689,6 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) path /= BaseParams().DataDir(); fs::create_directories(path); - //std::string assetpath = path + "/assets"; - //boost::filesystem::create_directory(assetpath); return path; } diff --git a/src/util.h b/src/util.h index 17bf19952b0..fb61df33e49 100644 --- a/src/util.h +++ b/src/util.h @@ -139,7 +139,21 @@ int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest); bool TryCreateDirectory(const boost::filesystem::path& p); +/**** + * @brief get the OS-specific default data directory + * @note Windows: be "C:\Users\[username]\AppData\Roaming\Komodo" + * @note Mac: ~/Library/Application Support/Komodo + * @note Unix: ~/.komodo + * @returns the default path to the Komodo data directory + */ boost::filesystem::path GetDefaultDataDir(); +/**** + * @brief determine the data directory + * @note looks at the -datadir command-line parameter or OS-specific defaults + * @note creates the directory if it does not already exist + * @param fNetSpecific if true, adds network-specific subdirectory (i.e. "regtest" or "testnet3") + * @returns the full OS-specific data directory including Komodo (i.e. "~/.komodo") + */ const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); void ClearDatadirCache(); boost::filesystem::path GetConfigFile(); diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index dd0880b756a..f1ca0f51197 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -46,7 +46,10 @@ unsigned int nWalletDBUpdated; // CDB // -CDBEnv bitdb; +// A singleton for all wallets in this process +// Making this a static variable causes problems with testing, so +// switching to a shared_ptr +std::shared_ptr bitdb(new CDBEnv()); void CDBEnv::EnvShutdown() { @@ -254,17 +257,17 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose nFlags |= DB_CREATE; { - LOCK(bitdb.cs_db); - if (!bitdb.Open(GetDataDir())) + LOCK(bitdb->cs_db); + if (!bitdb->Open(GetDataDir())) throw runtime_error("CDB: Failed to open database environment."); strFile = strFilename; - ++bitdb.mapFileUseCount[strFile]; - pdb = bitdb.mapDb[strFile]; + ++bitdb->mapFileUseCount[strFile]; + pdb = bitdb->mapDb[strFile]; if (pdb == NULL) { - pdb = new Db(bitdb.dbenv, 0); + pdb = new Db(bitdb->dbenv, 0); - bool fMockDb = bitdb.IsMock(); + bool fMockDb = bitdb->IsMock(); if (fMockDb) { DbMpoolFile* mpf = pdb->get_mpf(); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); @@ -282,7 +285,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose if (ret != 0) { delete pdb; pdb = NULL; - --bitdb.mapFileUseCount[strFile]; + --bitdb->mapFileUseCount[strFile]; strFile = ""; throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFile)); } @@ -294,7 +297,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose fReadOnly = fTmp; } - bitdb.mapDb[strFile] = pdb; + bitdb->mapDb[strFile] = pdb; } } } @@ -309,7 +312,7 @@ void CDB::Flush() if (fReadOnly) nMinutes = 1; - bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); + bitdb->dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); } void CDB::Close() @@ -325,8 +328,8 @@ void CDB::Close() Flush(); { - LOCK(bitdb.cs_db); - --bitdb.mapFileUseCount[strFile]; + LOCK(bitdb->cs_db); + --bitdb->mapFileUseCount[strFile]; } } @@ -357,19 +360,19 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) { while (true) { { - LOCK(bitdb.cs_db); - if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) { + LOCK(bitdb->cs_db); + if (!bitdb->mapFileUseCount.count(strFile) || bitdb->mapFileUseCount[strFile] == 0) { // Flush log data to the dat file - bitdb.CloseDb(strFile); - bitdb.CheckpointLSN(strFile); - bitdb.mapFileUseCount.erase(strFile); + bitdb->CloseDb(strFile); + bitdb->CheckpointLSN(strFile); + bitdb->mapFileUseCount.erase(strFile); bool fSuccess = true; LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile); string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} CDB db(strFile.c_str(), "r"); - Db* pdbCopy = new Db(bitdb.dbenv, 0); + Db* pdbCopy = new Db(bitdb->dbenv, 0); int ret = pdbCopy->open(NULL, // Txn pointer strFileRes.c_str(), // Filename @@ -412,17 +415,17 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) } if (fSuccess) { db.Close(); - bitdb.CloseDb(strFile); + bitdb->CloseDb(strFile); if (pdbCopy->close(0)) fSuccess = false; delete pdbCopy; } } if (fSuccess) { - Db dbA(bitdb.dbenv, 0); + Db dbA(bitdb->dbenv, 0); if (dbA.remove(strFile.c_str(), NULL, 0)) fSuccess = false; - Db dbB(bitdb.dbenv, 0); + Db dbB(bitdb->dbenv, 0); if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) fSuccess = false; } diff --git a/src/wallet/db.h b/src/wallet/db.h index 8ad246de434..dd9d50a56f5 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -60,7 +60,7 @@ class CDBEnv public: mutable CCriticalSection cs_db; - DbEnv *dbenv; + DbEnv *dbenv = nullptr; std::map mapFileUseCount; std::map mapDb; @@ -109,7 +109,7 @@ class CDBEnv } }; -extern CDBEnv bitdb; +extern std::shared_ptr bitdb; /** RAII class that provides access to a Berkeley database */ @@ -292,7 +292,7 @@ class CDB { if (!pdb || activeTxn) return false; - DbTxn* ptxn = bitdb.TxnBegin(); + DbTxn* ptxn = bitdb->TxnBegin(); if (!ptxn) return false; activeTxn = ptxn; diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index 20c39da2b15..98c1e09c04c 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -1477,7 +1477,7 @@ TEST(WalletTests, CachedWitnessesCleanIndex) { wallet.AddSproutSpendingKey(sk); // Generate a chain - size_t numBlocks = WITNESS_CACHE_SIZE + 10; + size_t numBlocks = MAX_REORG_LENGTH + 10; blocks.resize(numBlocks); indices.resize(numBlocks); for (size_t i = 0; i < numBlocks; i++) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index e69e67c231a..949fba49229 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -771,12 +771,12 @@ set CWallet::GetConflicts(const uint256& txid) const void CWallet::Flush(bool shutdown) { - bitdb.Flush(shutdown); + bitdb->Flush(shutdown); } bool CWallet::Verify(const string& walletFile, string& warningString, string& errorString) { - if (!bitdb.Open(GetDataDir())) + if (!bitdb->Open(GetDataDir())) { // try moving the database env out of the way boost::filesystem::path pathDatabase = GetDataDir() / "database"; @@ -789,7 +789,7 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er } // try again - if (!bitdb.Open(GetDataDir())) { + if (!bitdb->Open(GetDataDir())) { // if it still fails, it probably means we can't even create the database env string msg = strprintf(_("Error initializing wallet database environment %s!"), GetDataDir()); errorString += msg; @@ -800,13 +800,13 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er if (GetBoolArg("-salvagewallet", false)) { // Recover readable keypairs: - if (!CWalletDB::Recover(bitdb, walletFile, true)) + if (!CWalletDB::Recover(*bitdb, walletFile, true)) return false; } if (boost::filesystem::exists(GetDataDir() / walletFile)) { - CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover); + CDBEnv::VerifyResult r = bitdb->Verify(walletFile, CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) { warningString += strprintf(_("Warning: wallet.dat corrupt, data salvaged!" @@ -977,7 +977,7 @@ void CWallet::ClearNoteWitnessCache() } template -void CopyPreviousWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize) +void CopyPreviousWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize, int64_t maxWitnessCacheSize) { for (auto& item : noteDataMap) { auto* nd = &(item.second); @@ -996,7 +996,7 @@ void CopyPreviousWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nW if (nd->witnesses.size() > 0) { nd->witnesses.push_front(nd->witnesses.front()); } - if (nd->witnesses.size() > WITNESS_CACHE_SIZE) { + if (nd->witnesses.size() > maxWitnessCacheSize) { nd->witnesses.pop_back(); } } @@ -1069,11 +1069,11 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex, { LOCK(cs_wallet); for (std::pair& wtxItem : mapWallet) { - ::CopyPreviousWitnesses(wtxItem.second.mapSproutNoteData, pindex->nHeight, nWitnessCacheSize); - ::CopyPreviousWitnesses(wtxItem.second.mapSaplingNoteData, pindex->nHeight, nWitnessCacheSize); + ::CopyPreviousWitnesses(wtxItem.second.mapSproutNoteData, pindex->nHeight, nWitnessCacheSize, maxWitnessCacheSize); + ::CopyPreviousWitnesses(wtxItem.second.mapSaplingNoteData, pindex->nHeight, nWitnessCacheSize, maxWitnessCacheSize); } - if (nWitnessCacheSize < WITNESS_CACHE_SIZE) { + if (nWitnessCacheSize < maxWitnessCacheSize) { nWitnessCacheSize += 1; } @@ -1136,7 +1136,7 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex, } template -bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize) +bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize, int64_t maxWitnessCacheSize) { extern int32_t KOMODO_REWIND; @@ -1179,7 +1179,7 @@ bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t n assert((nWitnessCacheSize - 1) >= nd->witnesses.size()); } } - assert(KOMODO_REWIND != 0 || nWitnessCacheSize > 0 || WITNESS_CACHE_SIZE != _COINBASE_MATURITY+10); + assert(KOMODO_REWIND != 0 || nWitnessCacheSize > 0 || maxWitnessCacheSize != Params().CoinbaseMaturity()+10); return true; } @@ -1188,12 +1188,12 @@ void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex) { LOCK(cs_wallet); for (std::pair& wtxItem : mapWallet) { - if (!::DecrementNoteWitnesses(wtxItem.second.mapSproutNoteData, pindex->nHeight, nWitnessCacheSize)) + if (!::DecrementNoteWitnesses(wtxItem.second.mapSproutNoteData, pindex->nHeight, nWitnessCacheSize, maxWitnessCacheSize)) needsRescan = true; - if (!::DecrementNoteWitnesses(wtxItem.second.mapSaplingNoteData, pindex->nHeight, nWitnessCacheSize)) + if (!::DecrementNoteWitnesses(wtxItem.second.mapSaplingNoteData, pindex->nHeight, nWitnessCacheSize, maxWitnessCacheSize)) needsRescan = true; } - if ( WITNESS_CACHE_SIZE == _COINBASE_MATURITY+10 ) + if ( maxWitnessCacheSize == Params().CoinbaseMaturity()+10 ) { nWitnessCacheSize -= 1; // TODO: If nWitnessCache is zero, we need to regenerate the caches (#1302) @@ -3517,7 +3517,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int return true; } -bool CWallet::SelectCoins(const CAmount& nTargetValue, set >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl* coinControl) const +bool CWallet::SelectCoins(const CAmount& nTargetValue, set >& setCoinsRet, + CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, + const CCoinControl* coinControl) const { // Output parameter fOnlyCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos. uint64_t tmp; int32_t retval; @@ -3614,7 +3616,16 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set vecSend; @@ -3658,8 +3669,20 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC return true; } -bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, - int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign) +/***** + * @brief create a transaction + * @param vecSend who to send to + * @param wtxNew wallet transaction + * @param reservekey + * @param nFeeRet + * @param nChangePosRet + * @param strFailReason + * @param coinControl + * @param sign true to sign inputs + */ +bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, + CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, + bool sign) { uint64_t interest2 = 0; CAmount nValue = 0; unsigned int nSubtractFeeFromAmount = 0; BOOST_FOREACH (const CRecipient& recipient, vecSend) @@ -4876,14 +4899,14 @@ int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const int CMerkleTx::GetBlocksToMaturity() const { if ( ASSETCHAINS_SYMBOL[0] == 0 ) - COINBASE_MATURITY = _COINBASE_MATURITY; + Params().ResetCoinbaseMaturity(); if (!IsCoinBase()) return 0; int32_t depth = GetDepthInMainChain(); int32_t ut = UnlockTime(0); int32_t toMaturity = (ut - chainActive.Height()) < 0 ? 0 : ut - chainActive.Height(); //printf("depth.%i, unlockTime.%i, toMaturity.%i\n", depth, ut, toMaturity); - ut = (COINBASE_MATURITY - depth) < 0 ? 0 : COINBASE_MATURITY - depth; + ut = (Params().CoinbaseMaturity() - depth) < 0 ? 0 : Params().CoinbaseMaturity() - depth; return(ut < toMaturity ? toMaturity : ut); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b1e5b66b82a..fa9dfac8c10 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -73,11 +73,6 @@ static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2; static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning; //! Largest (in bytes) free transaction we're willing to create static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; -//! Size of witness cache -// Should be large enough that we can expect not to reorg beyond our cache -// unless there is some exceptional network disruption. -extern unsigned int WITNESS_CACHE_SIZE; - //! Size of HD seed in bytes static const size_t HD_WALLET_SEED_LENGTH = 32; @@ -747,6 +742,12 @@ class CAccountingEntry */ class CWallet : public CCryptoKeyStore, public CValidationInterface { +protected: + bool fBroadcastTransactions; + //! Size of witness cache + // Should be large enough that we can expect not to reorg beyond our cache + // unless there is some exceptional network disruption. + int64_t maxWitnessCacheSize; private: bool SelectCoins(const CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl *coinControl = NULL) const; @@ -760,7 +761,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface int64_t nNextResend; int64_t nLastResend; - bool fBroadcastTransactions; template using TxSpendMap = std::multimap; @@ -887,15 +887,13 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface MasterKeyMap mapMasterKeys; unsigned int nMasterKeyMaxID; - CWallet() + CWallet(int64_t witnessCacheSize = MAX_REORG_LENGTH + 10) : maxWitnessCacheSize(witnessCacheSize) { SetNull(); } - CWallet(const std::string& strWalletFileIn) + CWallet(const std::string& strWalletFileIn, int64_t witnessCacheSize = MAX_REORG_LENGTH + 10) : CWallet(witnessCacheSize) { - SetNull(); - strWalletFile = strWalletFileIn; fFileBacked = true; } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index da1f07871c7..f3962a6a696 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1139,13 +1139,13 @@ void ThreadFlushWalletDB(const string& strFile) if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2) { - TRY_LOCK(bitdb.cs_db,lockDb); + TRY_LOCK(bitdb->cs_db,lockDb); if (lockDb) { // Don't do this if any databases are in use int nRefCount = 0; - map::iterator mi = bitdb.mapFileUseCount.begin(); - while (mi != bitdb.mapFileUseCount.end()) + map::iterator mi = bitdb->mapFileUseCount.begin(); + while (mi != bitdb->mapFileUseCount.end()) { nRefCount += (*mi).second; mi++; @@ -1154,18 +1154,18 @@ void ThreadFlushWalletDB(const string& strFile) if (nRefCount == 0) { boost::this_thread::interruption_point(); - map::iterator mi = bitdb.mapFileUseCount.find(strFile); - if (mi != bitdb.mapFileUseCount.end()) + map::iterator mi = bitdb->mapFileUseCount.find(strFile); + if (mi != bitdb->mapFileUseCount.end()) { LogPrint("db", "Flushing wallet.dat\n"); nLastFlushed = nWalletDBUpdated; int64_t nStart = GetTimeMillis(); // Flush wallet.dat so it's self contained - bitdb.CloseDb(strFile); - bitdb.CheckpointLSN(strFile); + bitdb->CloseDb(strFile); + bitdb->CheckpointLSN(strFile); - bitdb.mapFileUseCount.erase(mi++); + bitdb->mapFileUseCount.erase(mi++); LogPrint("db", "Flushed wallet.dat %dms\n", GetTimeMillis() - nStart); } } @@ -1181,13 +1181,13 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) while (true) { { - LOCK(bitdb.cs_db); - if (!bitdb.mapFileUseCount.count(wallet.strWalletFile) || bitdb.mapFileUseCount[wallet.strWalletFile] == 0) + LOCK(bitdb->cs_db); + if (!bitdb->mapFileUseCount.count(wallet.strWalletFile) || bitdb->mapFileUseCount[wallet.strWalletFile] == 0) { // Flush log data to the dat file - bitdb.CloseDb(wallet.strWalletFile); - bitdb.CheckpointLSN(wallet.strWalletFile); - bitdb.mapFileUseCount.erase(wallet.strWalletFile); + bitdb->CloseDb(wallet.strWalletFile); + bitdb->CheckpointLSN(wallet.strWalletFile); + bitdb->mapFileUseCount.erase(wallet.strWalletFile); // Copy wallet.dat boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 0a272c8a1d8..702686b21e1 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -53,7 +53,7 @@ void pre_wallet_load() UnregisterValidationInterface(pwalletMain); delete pwalletMain; pwalletMain = NULL; - bitdb.Reset(); + bitdb->Reset(); RegisterNodeSignals(GetNodeSignals()); LogPrintf("%s: done\n", __func__); } diff --git a/zcutil/build-mac-dtest.sh b/zcutil/build-mac-dtest.sh index 8104c720009..06171305bdd 100755 --- a/zcutil/build-mac-dtest.sh +++ b/zcutil/build-mac-dtest.sh @@ -18,11 +18,13 @@ Usage: $0 --help Show this help message and exit. -$0 [ --enable-lcov ] [ MAKEARGS... ] - Build Zcash and most of its transitive dependencies from - source. MAKEARGS are applied to both dependencies and Zcash itself. If - --enable-lcov is passed, Zcash is configured to add coverage +$0 [ --enable-lcov ] [ --enable-debug ] [ MAKEARGS... ] + Build Komodo and most of its transitive dependencies from + source. MAKEARGS are applied to both dependencies and Komodo itself. + If --enable-lcov is passed, Komodo is configured to add coverage instrumentation, thus enabling "make cov" to work. + If --enable-debug is passed, Komodo is built with debugging information. It + must be passed after the previous arguments, if present. EOF exit 0 fi @@ -37,22 +39,25 @@ then shift fi +# If --enable-debug is the next argument, enable debugging +DEBUGGING_ARG='' +if [ "x${1:-}" = 'x--enable-debug' ] +then + DEBUG=1 + export DEBUG + DEBUGGING_ARG='--enable-debug' + shift +fi + TRIPLET=`./depends/config.guess` PREFIX="$(pwd)/depends/$TRIPLET" make "$@" -C ./depends/ V=1 NO_QT=1 NO_PROTON=1 -#BUILD CCLIB - -WD=$PWD -cd src/cc -echo $PWD -./makecustom -cd $WD - ./autogen.sh + CPPFLAGS="-I$PREFIX/include -arch x86_64 -DTESTMODE" LDFLAGS="-L$PREFIX/lib -arch x86_64 -Wl,-no_pie" \ -CXXFLAGS='-arch x86_64 -I/usr/local/Cellar/gcc\@8/8.3.0/include/c++/8.3.0/ -I$PREFIX/include -fwrapv -fno-strict-aliasing -Wno-builtin-declaration-mismatch -Werror -Wno-error=attributes -g -Wl,-undefined -Wl,dynamic_lookup' \ -./configure --prefix="${PREFIX}" --with-gui=no "$HARDENING_ARG" "$LCOV_ARG" +CXXFLAGS="-arch x86_64 -I/usr/local/Cellar/gcc\@8/8.3.0/include/c++/8.3.0/ -I$PREFIX/include -fwrapv -fno-strict-aliasing -Wno-builtin-declaration-mismatch -Werror -Wno-error=attributes -g -Wl,-undefined -Wl,dynamic_lookup" \ +./configure --prefix="${PREFIX}" --with-gui=no "$HARDENING_ARG" "$LCOV_ARG" "$DEBUGGING_ARG" -make "$@" V=1 NO_GTEST=1 STATIC=1 +make "$@" NO_GTEST=1 STATIC=1 diff --git a/zcutil/build-mac.sh b/zcutil/build-mac.sh index ea03242cc71..77a5e764ecf 100755 --- a/zcutil/build-mac.sh +++ b/zcutil/build-mac.sh @@ -18,11 +18,13 @@ Usage: $0 --help Show this help message and exit. -$0 [ --enable-lcov ] [ MAKEARGS... ] - Build Zcash and most of its transitive dependencies from - source. MAKEARGS are applied to both dependencies and Zcash itself. If - --enable-lcov is passed, Zcash is configured to add coverage +$0 [ --enable-lcov ] [ --enable-debug ] [ MAKEARGS... ] + Build Komodo and most of its transitive dependencies from + source. MAKEARGS are applied to both dependencies and Komodo itself. + If --enable-lcov is passed, Komodo is configured to add coverage instrumentation, thus enabling "make cov" to work. + If --enable-debug is passed, Komodo is built with debugging information. It + must be passed after the previous arguments, if present. EOF exit 0 fi @@ -37,22 +39,25 @@ then shift fi +# If --enable-debug is the next argument, enable debugging +DEBUGGING_ARG='' +if [ "x${1:-}" = 'x--enable-debug' ] +then + DEBUG=1 + export DEBUG + DEBUGGING_ARG='--enable-debug' + shift +fi + TRIPLET=`./depends/config.guess` PREFIX="$(pwd)/depends/$TRIPLET" make "$@" -C ./depends/ V=1 NO_QT=1 NO_PROTON=1 -#BUILD CCLIB - -WD=$PWD -cd src/cc -echo $PWD -./makecustom -cd $WD - ./autogen.sh + CPPFLAGS="-I$PREFIX/include -arch x86_64" LDFLAGS="-L$PREFIX/lib -arch x86_64 -Wl,-no_pie" \ -CXXFLAGS='-arch x86_64 -I/usr/local/Cellar/gcc\@8/8.3.0/include/c++/8.3.0/ -I$PREFIX/include -fwrapv -fno-strict-aliasing -Wno-builtin-declaration-mismatch -Werror -Wno-error=attributes -g -Wl,-undefined -Wl,dynamic_lookup' \ -./configure --prefix="${PREFIX}" --with-gui=no "$HARDENING_ARG" "$LCOV_ARG" +CXXFLAGS="-arch x86_64 -I/usr/local/Cellar/gcc\@8/8.3.0/include/c++/8.3.0/ -I$PREFIX/include -fwrapv -fno-strict-aliasing -Wno-builtin-declaration-mismatch -Werror -Wno-error=attributes -g -Wl,-undefined -Wl,dynamic_lookup" \ +./configure --prefix="${PREFIX}" --with-gui=no "$HARDENING_ARG" "$LCOV_ARG" "$DEBUGGING_ARG" -make "$@" V=1 NO_GTEST=1 STATIC=1 +make "$@" NO_GTEST=1 STATIC=1 diff --git a/zcutil/build-win-dtest.sh b/zcutil/build-win-dtest.sh index 00a64de5bf7..94bed448bde 100755 --- a/zcutil/build-win-dtest.sh +++ b/zcutil/build-win-dtest.sh @@ -2,23 +2,24 @@ export HOST=x86_64-w64-mingw32 CXX=x86_64-w64-mingw32-g++-posix CC=x86_64-w64-mingw32-gcc-posix -PREFIX="$(pwd)/depends/$HOST" set -eu -o pipefail - set -x -cd "$(dirname "$(readlink -f "$0")")/.." -cd depends/ && make HOST=$HOST V=1 NO_QT=1 -cd ../ -WD=$PWD -cd src/cc -echo $PWD -./makecustom -cd $WD +UTIL_DIR="$(dirname "$(readlink -f "$0")")" +BASE_DIR="$(dirname "$(readlink -f "$UTIL_DIR")")" +PREFIX="$BASE_DIR/depends/$HOST" + +cd $BASE_DIR/depends +make HOST=$HOST NO_QT=1 "$@" +cd $BASE_DIR ./autogen.sh CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site CXXFLAGS="-DPTW32_STATIC_LIB -DCURL_STATICLIB -DCURVE_ALT_BN128 -fopenmp -pthread" CPPFLAGS=-DTESTMODE ./configure --prefix="${PREFIX}" --host=x86_64-w64-mingw32 --enable-static --disable-shared sed -i 's/-lboost_system-mt /-lboost_system-mt-s /' configure -cd src/ -CC="${CC} -g " CXX="${CXX} -g " make V=1 komodod.exe komodo-cli.exe komodo-tx.exe + +cd $BASE_DIR/src/cryptoconditions +CC="${CC} -g " CXX="${CXX} -g " make V=1 +cd $BASE_DIR + +CC="${CC} -g " CXX="${CXX} -g " make V=1 src/komodod.exe src/komodo-cli.exe src/komodo-tx.exe diff --git a/zcutil/build-win.sh b/zcutil/build-win.sh index e8c0465d98b..ffd01134074 100755 --- a/zcutil/build-win.sh +++ b/zcutil/build-win.sh @@ -2,23 +2,19 @@ export HOST=x86_64-w64-mingw32 CXX=x86_64-w64-mingw32-g++-posix CC=x86_64-w64-mingw32-gcc-posix -PREFIX="$(pwd)/depends/$HOST" set -eu -o pipefail -set -x -cd "$(dirname "$(readlink -f "$0")")/.." +UTIL_DIR="$(dirname "$(readlink -f "$0")")" +BASE_DIR="$(dirname "$(readlink -f "$UTIL_DIR")")" +PREFIX="$BASE_DIR/depends/$HOST" -cd depends/ && make HOST=$HOST V=1 NO_QT=1 -cd ../ -WD=$PWD -cd src/cc -echo $PWD -./makecustom -cd $WD +cd $BASE_DIR/depends +make HOST=$HOST NO_QT=1 "$@" +cd $BASE_DIR ./autogen.sh -CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site CXXFLAGS="-DPTW32_STATIC_LIB -DCURL_STATICLIB -DCURVE_ALT_BN128 -fopenmp -pthread" ./configure --prefix="${PREFIX}" --host=x86_64-w64-mingw32 --enable-static --disable-shared +CONFIG_SITE=$BASE_DIR/depends/$HOST/share/config.site CXXFLAGS="-DPTW32_STATIC_LIB -DCURL_STATICLIB -DCURVE_ALT_BN128 -fopenmp -pthread" ./configure --prefix=$PREFIX --host=$HOST --enable-static --disable-shared sed -i 's/-lboost_system-mt /-lboost_system-mt-s /' configure -cd src/ -CC="${CC} -g " CXX="${CXX} -g " make V=1 komodod.exe komodo-cli.exe komodo-tx.exe + +make "$@" diff --git a/zcutil/build.sh b/zcutil/build.sh index 6f625b185aa..7b6da0d701f 100755 --- a/zcutil/build.sh +++ b/zcutil/build.sh @@ -44,23 +44,23 @@ then Usage: $0 --help Show this help message and exit. -$0 [ --enable-lcov || --disable-tests ] [ --disable-mining ] [ --enable-proton ] [ --disable-libs ] [ MAKEARGS... ] - Build Zcash and most of its transitive dependencies from - source. MAKEARGS are applied to both dependencies and Zcash itself. - If --enable-lcov is passed, Zcash is configured to add coverage +$0 [ --enable-lcov || --disable-tests ] [ --disable-mining ] [ --enable-proton ] [ --disable-libs ] [ --enable-debug ] [ MAKEARGS... ] + Build Komodo and most of its transitive dependencies from + source. MAKEARGS are applied to both dependencies and Komodo itself. + If --enable-lcov is passed, Komodo is configured to add coverage instrumentation, thus enabling "make cov" to work. - If --disable-tests is passed instead, the Zcash tests are not built. - If --disable-mining is passed, Zcash is configured to not build any mining + If --disable-tests is passed instead, the Komodo tests are not built. + If --disable-mining is passed, Komodo is configured to not build any mining code. It must be passed after the test arguments, if present. - If --enable-proton is passed, Zcash is configured to build the Apache Qpid Proton + If --enable-proton is passed, Komodo is configured to build the Apache Qpid Proton library required for AMQP support. This library is not built by default. It must be passed after the test/mining arguments, if present. + If --enable-debug is passed, Komodo is built with debugging information. It + must be passed after the previous arguments, if present. EOF exit 0 fi -set -x - # If --enable-lcov is the first argument, enable lcov coverage support: LCOV_ARG='' HARDENING_ARG='--enable-hardening' @@ -92,24 +92,26 @@ then shift fi -eval "$MAKE" --version -as --version -ld -v - -HOST="$HOST" BUILD="$BUILD" NO_PROTON="$PROTON_ARG" "$MAKE" "$@" -C ./depends/ V=1 -./autogen.sh - -CONFIG_SITE="$PWD/depends/$HOST/share/config.site" ./configure "$HARDENING_ARG" "$LCOV_ARG" "$TEST_ARG" "$MINING_ARG" "$PROTON_ARG" "$CONFIGURE_FLAGS" CXXFLAGS='-g' - -#BUILD CCLIB +# If --enable-debug is the next argument, enable debugging +DEBUGGING_ARG='' +if [ "x${1:-}" = 'x--enable-debug' ] +then + DEBUG=1 + export DEBUG + DEBUGGING_ARG='--enable-debug' + shift +fi -WD=$PWD +if [[ -z "${VERBOSE-}" ]]; then + VERBOSITY="--enable-silent-rules" +else + VERBOSITY="--disable-silent-rules" +fi -cd src/cc -echo $PWD -./makecustom +HOST="$HOST" BUILD="$BUILD" NO_PROTON="$PROTON_ARG" "$MAKE" "$@" -C ./depends/ +./autogen.sh -cd $WD +CONFIG_SITE="$PWD/depends/$HOST/share/config.site" ./configure "$HARDENING_ARG" "$LCOV_ARG" "$TEST_ARG" "$MINING_ARG" "$PROTON_ARG" "$DEBUGGING_ARG" "$CONFIGURE_FLAGS" -"$MAKE" "$@" V=1 +"$MAKE" "$@"