]> Git Repo - VerusCoin.git/commitdiff
Merge pull request #5 from jl777/dev
authormiketout <[email protected]>
Fri, 4 May 2018 22:40:27 +0000 (15:40 -0700)
committerGitHub <[email protected]>
Fri, 4 May 2018 22:40:27 +0000 (15:40 -0700)
integrate jl777 changes for komodo interest

38 files changed:
.gitignore
src/Makefile.am
src/Makefile.gtest.include
src/Makefile.qt.include
src/Makefile.qttest.include
src/Makefile.test.include
src/Makefile.zcash.include
src/chainparams.cpp
src/consensus/params.h
src/crypto/haraka.c [new file with mode: 0644]
src/crypto/haraka.h [new file with mode: 0644]
src/crypto/verus_hash.cpp [new file with mode: 0644]
src/crypto/verus_hash.h [new file with mode: 0644]
src/fiat/verus [new file with mode: 0644]
src/hash.h
src/init.cpp
src/keystore.h
src/komodo_bitcoind.h
src/komodo_defs.h
src/komodo_globals.h
src/komodo_utils.h
src/main.cpp
src/main.h
src/metrics.h
src/miner.cpp
src/pow.cpp
src/primitives/block.cpp
src/primitives/block.h
src/qt/transactiondesc.cpp
src/rpcmining.cpp
src/script/script_ext.cpp [new file with mode: 0644]
src/script/script_ext.h [new file with mode: 0644]
src/util.cpp
src/util.h
src/wallet-utility [new file with mode: 0644]
src/wallet-utility.cpp
src/wallet/wallet.cpp
src/wallet/wallet.h

index bebcef93246e80121702e3b1bc9b20a4ccf3c97b..3916d4e87cc19a99fb4a487ae5b62e17193c4975 100644 (file)
@@ -120,3 +120,4 @@ src/komodo-cli
 src/komodod
 src/komodo-tx
 src/komodo-test
+src/wallet-utility
index a1232968da6514a9e59d6c38a620a9d1017696e4..7355d17d2dba7d6162da744dcf46a1b6a6e3c96c 100644 (file)
@@ -42,6 +42,7 @@ LIBBITCOIN_COMMON=libbitcoin_common.a
 LIBBITCOIN_CLI=libbitcoin_cli.a
 LIBBITCOIN_UTIL=libbitcoin_util.a
 LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
+LIBVERUS_CRYPTO=crypto/libverus_crypto.a
 LIBSECP256K1=secp256k1/libsecp256k1.la
 LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions_core.la
 LIBSNARK=snark/libsnark.a
@@ -72,12 +73,13 @@ $(LIBCRYPTOCONDITIONS): $(wildcard cryptoconditions/src/*) $(wildcard cryptocond
 # Make is not made aware of per-object dependencies to avoid limiting building parallelization
 # But to build the less dependent modules first, we manually select their order here:
 EXTRA_LIBRARIES = \
-       crypto/libbitcoin_crypto.a \
-       libbitcoin_util.a \
-       libbitcoin_common.a \
-       libbitcoin_server.a \
-       libbitcoin_cli.a \
-       libzcash.a
+  crypto/libbitcoin_crypto.a \
+  crypto/libverus_crypto.a \
+  libbitcoin_util.a \
+  libbitcoin_common.a \
+  libbitcoin_server.a \
+  libbitcoin_cli.a \
+  libzcash.a
 if ENABLE_WALLET
 BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
 EXTRA_LIBRARIES += libbitcoin_wallet.a
@@ -163,6 +165,7 @@ BITCOIN_CORE_H = \
   core_io.h \
   core_memusage.h \
   deprecation.h \
+  haraka.h \
   hash.h \
   httprpc.h \
   httpserver.h \
@@ -342,22 +345,24 @@ libbitcoin_wallet_a_SOURCES = \
 crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
 crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
 crypto_libbitcoin_crypto_a_SOURCES = \
-       crypto/common.h \
-       crypto/equihash.cpp \
-       crypto/equihash.h \
-       crypto/equihash.tcc \
-       crypto/hmac_sha256.cpp \
-       crypto/hmac_sha256.h \
-       crypto/hmac_sha512.cpp \
-       crypto/hmac_sha512.h \
-       crypto/ripemd160.cpp \
-       crypto/ripemd160.h \
-       crypto/sha1.cpp \
-       crypto/sha1.h \
-       crypto/sha256.cpp \
-       crypto/sha256.h \
-       crypto/sha512.cpp \
-       crypto/sha512.h
+  crypto/common.h \
+  crypto/equihash.cpp \
+  crypto/equihash.h \
+  crypto/equihash.tcc \
+  crypto/hmac_sha256.cpp \
+  crypto/hmac_sha256.h \
+  crypto/hmac_sha512.cpp \
+  crypto/hmac_sha512.h \
+  crypto/ripemd160.cpp \
+  crypto/ripemd160.h \
+  crypto/sha1.cpp \
+  crypto/sha1.h \
+  crypto/sha256.cpp \
+  crypto/sha256.h \
+  crypto/sha512.cpp \
+  crypto/sha512.h \
+  crypto/verus_hash.h \
+  crypto/verus_hash.cpp
 
 if ENABLE_MINING
 EQUIHASH_TROMP_SOURCES = \
@@ -371,9 +376,16 @@ crypto_libbitcoin_crypto_a_SOURCES += \
        ${EQUIHASH_TROMP_SOURCES}
 endif
 
+# Verus hash specific library
+crypto_libverus_crypto_a_CPPFLAGS = -O3 -Wint-conversion -march=native -funroll-loops -fomit-frame-pointer -fPIC $(AM_CPPFLAGS)
+crypto_libverus_crypto_a_CXXFLAGS = -O3 -Wint-conversion -march=native -funroll-loops -fomit-frame-pointer -fPIC $(AM_CXXFLAGS)
+crypto_libverus_crypto_a_SOURCES = \
+  crypto/haraka.h \
+  crypto/haraka.c
+
 # common: shared between zcashd and non-server tools
-libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
-libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+libbitcoin_common_a_CPPFLAGS = -fPIC $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+libbitcoin_common_a_CXXFLAGS = -fPIC $(AM_CXXFLAGS) $(PIE_FLAGS)
 libbitcoin_common_a_SOURCES = \
   amount.cpp \
   arith_uint256.cpp \
@@ -396,6 +408,7 @@ libbitcoin_common_a_SOURCES = \
   script/cc.cpp \
   script/interpreter.cpp \
   script/script.cpp \
+  script/script_ext.cpp \
   script/script_error.cpp \
   script/sign.cpp \
   script/standard.cpp \
@@ -457,6 +470,7 @@ komodod_LDADD = \
   $(LIBUNIVALUE) \
   $(LIBBITCOIN_UTIL) \
   $(LIBBITCOIN_CRYPTO) \
+  $(LIBVERUS_CRYPTO) \
   $(LIBZCASH) \
   $(LIBSNARK) \
   $(LIBLEVELDB) \
@@ -480,6 +494,7 @@ komodod_LDADD += \
   $(EVENT_PTHREADS_LIBS) \
   $(EVENT_LIBS) \
   $(LIBBITCOIN_CRYPTO) \
+  $(LIBVERUS_CRYPTO) \
   $(LIBZCASH_LIBS)
 
 if ENABLE_PROTON
@@ -521,6 +536,7 @@ wallet_utility_LDADD = \
        libbitcoin_wallet.a \
        $(LIBBITCOIN_COMMON) \
        $(LIBBITCOIN_CRYPTO) \
+  $(LIBVERUS_CRYPTO) \
        $(LIBSECP256K1) \
        $(LIBBITCOIN_UTIL) \
        $(BOOST_LIBS) \
@@ -551,6 +567,7 @@ komodo_tx_LDADD = \
   $(LIBZCASH) \
   $(LIBSNARK) \
   $(LIBBITCOIN_CRYPTO) \
+  $(LIBVERUS_CRYPTO) \
   $(LIBZCASH_LIBS) \
   $(LIBCRYPTOCONDITIONS)
 
index f70672052fa8e2e9c448bdf31d508cd4d87df666..b424fd41f85839b2494a9e2cc1d9b06acfe4fa91 100644 (file)
@@ -49,7 +49,7 @@ endif
 komodo_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
 komodo_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) \
+komodo_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
   $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
 if ENABLE_ZMQ
 zcash_gtest_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
index c2101673749c3d68ca59867b64907ba52e01d56c..6afc3a7075a5bf735a082db0920143b39e8122a4 100644 (file)
@@ -361,7 +361,7 @@ qt_komodo_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
 if ENABLE_WALLET
 qt_komodo_qt_LDADD += $(LIBBITCOIN_WALLET)
 endif
-qt_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
+qt_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
   $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBZCASH_LIBS)
 qt_komodo_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
 qt_komodo_qt_LIBTOOLFLAGS = --tag CXX
index 3e57a89266a2c7287b43f0b0948908ba6fd75bab..2d56d07e38165fc40a40566a3fcb85dc297add51 100644 (file)
@@ -30,7 +30,7 @@ qt_test_test_komodo_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
 if ENABLE_WALLET
 qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_WALLET)
 endif
-qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
+qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
   $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
   $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBZCASH_LIBS)
 qt_test_test_komodo_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
index ff270bd6af5e5210cc39c7c66047ac160be686aa..e1f9678e13f48b6e70bce5f3877b0d8d03e57a8e 100644 (file)
@@ -103,7 +103,7 @@ endif
 
 test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
 test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
-test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
+test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
   $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
 test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
 if ENABLE_WALLET
index da5b4344da7340d1fa96e722778098b9081d0353..4302b2e0da59114259108ac3a8bd768afb0bc014 100644 (file)
@@ -24,6 +24,7 @@ zcash_CreateJoinSplit_LDADD = \
   $(LIBSNARK) \
   $(LIBBITCOIN_UTIL) \
   $(LIBBITCOIN_CRYPTO) \
+  $(LIBVERUS_CRYPTO) \
   $(BOOST_LIBS) \
   $(LIBZCASH_LIBS) \
   $(LIBCRYPTOCONDITIONS) \
index df258d78286c8f215f161fcb67b5defabbc5e77e..1cf2106b096603d58440aaf8ec0232bf9907d034 100644 (file)
@@ -83,6 +83,8 @@ extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
 extern uint32_t ASSETCHAIN_INIT;
 extern uint32_t ASSETCHAINS_MAGIC;
 extern uint64_t ASSETCHAINS_SUPPLY;
+extern uint64_t ASSETCHAINS_ALGO;
+extern uint64_t ASSETCHAINS_EQUIHASH;
 
 const arith_uint256 maxUint = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
 
@@ -100,6 +102,8 @@ public:
         consensus.nMajorityWindow = 4000;
         consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f");
         consensus.nPowAveragingWindow = 17;
+        consensus.nMaxFutureBlockTime = 7 * 60; // 7 mins
+
         assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
         consensus.nPowMaxAdjustDown = 32; // 32% adjustment down
         consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
@@ -178,7 +182,7 @@ public:
 
         vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
 
-        fMiningRequiresPeers = true;
+        //fMiningRequiresPeers = true;
         fDefaultConsistencyChecks = false;
         fRequireStandard = true;
         fMineBlocksOnDemand = false;
@@ -229,7 +233,15 @@ void *chainparams_commandline(void *ptr)
         mainParams.pchMessageStart[3] = (ASSETCHAINS_MAGIC >> 24) & 0xff;
         fprintf(stderr,">>>>>>>>>> %s: p2p.%u rpc.%u magic.%08x %u %u coins\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_MAGIC,ASSETCHAINS_MAGIC,(uint32_t)ASSETCHAINS_SUPPLY);
 
-       checkpointData = //(Checkpoints::CCheckpointData)
+        if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH)
+        {
+            // this is only good for 60 second blocks with an averaging window of 45. for other parameters, use:
+            // nLwmaAjustedWeight = (N+1)/2 * (0.9989^(500/nPowAveragingWindow)) * nPowTargetSpacing 
+            mainParams.consensus.nLwmaAjustedWeight = 1350;
+            mainParams.consensus.nPowAveragingWindow = 45;
+        }
+
+        checkpointData = //(Checkpoints::CCheckpointData)
             {
                 boost::assign::map_list_of
                 (0, mainParams.consensus.hashGenesisBlock),
@@ -419,6 +431,7 @@ public:
         consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
         consensus.nPowAveragingWindow = 17;
         assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
+        consensus.nMaxFutureBlockTime = 7 * 60;
 
         vAlertPubKey = ParseHex("00");
         nDefaultPort = 17770;
@@ -507,6 +520,7 @@ public:
         consensus.nMajorityWindow = 1000;
         consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f");
         consensus.nPowAveragingWindow = 17;
+        consensus.nMaxFutureBlockTime = 7 * 60; // 7 mins
         assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
         consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down
         consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up
index 855729ff0118dbe438f1186cbf5cba4891a01fab..a072f50cb01e52334feefe5d010f14b6f8882271 100644 (file)
@@ -89,12 +89,18 @@ struct Params {
     int nMajorityWindow;
     int fPowAllowMinDifficultyBlocks;
     NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES];
+
     /** Proof of work parameters */
     uint256 powLimit;
     int64_t nPowAveragingWindow;
     int64_t nPowMaxAdjustDown;
     int64_t nPowMaxAdjustUp;
     int64_t nPowTargetSpacing;
+    int64_t nMaxFutureBlockTime;
+
+    // Verus algorithm's lwma difficulty
+    int64_t nLwmaAjustedWeight;
+
     int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; }
     int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp  )) / 100; }
     int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; }
diff --git a/src/crypto/haraka.c b/src/crypto/haraka.c
new file mode 100644 (file)
index 0000000..ccfd8ce
--- /dev/null
@@ -0,0 +1,574 @@
+/*\r
+The MIT License (MIT)\r
+\r
+Copyright (c) 2016 kste\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy\r
+of this software and associated documentation files (the "Software"), to deal\r
+in the Software without restriction, including without limitation the rights\r
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+copies of the Software, and to permit persons to whom the Software is\r
+furnished to do so, subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in all\r
+copies or substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+SOFTWARE.\r
+\r
+Optimized Implementations for Haraka256 and Haraka512\r
+*/\r
+\r
+#include <stdio.h>\r
+#include "crypto/haraka.h"\r
+\r
+u128 rc[40];\r
+\r
+void load_constants() {\r
+  rc[0] = _mm_set_epi32(0x0684704c,0xe620c00a,0xb2c5fef0,0x75817b9d);\r
+  rc[1] = _mm_set_epi32(0x8b66b4e1,0x88f3a06b,0x640f6ba4,0x2f08f717);\r
+  rc[2] = _mm_set_epi32(0x3402de2d,0x53f28498,0xcf029d60,0x9f029114);\r
+  rc[3] = _mm_set_epi32(0x0ed6eae6,0x2e7b4f08,0xbbf3bcaf,0xfd5b4f79);\r
+  rc[4] = _mm_set_epi32(0xcbcfb0cb,0x4872448b,0x79eecd1c,0xbe397044);\r
+  rc[5] = _mm_set_epi32(0x7eeacdee,0x6e9032b7,0x8d5335ed,0x2b8a057b);\r
+  rc[6] = _mm_set_epi32(0x67c28f43,0x5e2e7cd0,0xe2412761,0xda4fef1b);\r
+  rc[7] = _mm_set_epi32(0x2924d9b0,0xafcacc07,0x675ffde2,0x1fc70b3b);\r
+  rc[8] = _mm_set_epi32(0xab4d63f1,0xe6867fe9,0xecdb8fca,0xb9d465ee);\r
+  rc[9] = _mm_set_epi32(0x1c30bf84,0xd4b7cd64,0x5b2a404f,0xad037e33);\r
+  rc[10] = _mm_set_epi32(0xb2cc0bb9,0x941723bf,0x69028b2e,0x8df69800);\r
+  rc[11] = _mm_set_epi32(0xfa0478a6,0xde6f5572,0x4aaa9ec8,0x5c9d2d8a);\r
+  rc[12] = _mm_set_epi32(0xdfb49f2b,0x6b772a12,0x0efa4f2e,0x29129fd4);\r
+  rc[13] = _mm_set_epi32(0x1ea10344,0xf449a236,0x32d611ae,0xbb6a12ee);\r
+  rc[14] = _mm_set_epi32(0xaf044988,0x4b050084,0x5f9600c9,0x9ca8eca6);\r
+  rc[15] = _mm_set_epi32(0x21025ed8,0x9d199c4f,0x78a2c7e3,0x27e593ec);\r
+  rc[16] = _mm_set_epi32(0xbf3aaaf8,0xa759c9b7,0xb9282ecd,0x82d40173);\r
+  rc[17] = _mm_set_epi32(0x6260700d,0x6186b017,0x37f2efd9,0x10307d6b);\r
+  rc[18] = _mm_set_epi32(0x5aca45c2,0x21300443,0x81c29153,0xf6fc9ac6);\r
+  rc[19] = _mm_set_epi32(0x9223973c,0x226b68bb,0x2caf92e8,0x36d1943a);\r
+  rc[20] = _mm_set_epi32(0xd3bf9238,0x225886eb,0x6cbab958,0xe51071b4);\r
+  rc[21] = _mm_set_epi32(0xdb863ce5,0xaef0c677,0x933dfddd,0x24e1128d);\r
+  rc[22] = _mm_set_epi32(0xbb606268,0xffeba09c,0x83e48de3,0xcb2212b1);\r
+  rc[23] = _mm_set_epi32(0x734bd3dc,0xe2e4d19c,0x2db91a4e,0xc72bf77d);\r
+  rc[24] = _mm_set_epi32(0x43bb47c3,0x61301b43,0x4b1415c4,0x2cb3924e);\r
+  rc[25] = _mm_set_epi32(0xdba775a8,0xe707eff6,0x03b231dd,0x16eb6899);\r
+  rc[26] = _mm_set_epi32(0x6df3614b,0x3c755977,0x8e5e2302,0x7eca472c);\r
+  rc[27] = _mm_set_epi32(0xcda75a17,0xd6de7d77,0x6d1be5b9,0xb88617f9);\r
+  rc[28] = _mm_set_epi32(0xec6b43f0,0x6ba8e9aa,0x9d6c069d,0xa946ee5d);\r
+  rc[29] = _mm_set_epi32(0xcb1e6950,0xf957332b,0xa2531159,0x3bf327c1);\r
+  rc[30] = _mm_set_epi32(0x2cee0c75,0x00da619c,0xe4ed0353,0x600ed0d9);\r
+  rc[31] = _mm_set_epi32(0xf0b1a5a1,0x96e90cab,0x80bbbabc,0x63a4a350);\r
+  rc[32] = _mm_set_epi32(0xae3db102,0x5e962988,0xab0dde30,0x938dca39);\r
+  rc[33] = _mm_set_epi32(0x17bb8f38,0xd554a40b,0x8814f3a8,0x2e75b442);\r
+  rc[34] = _mm_set_epi32(0x34bb8a5b,0x5f427fd7,0xaeb6b779,0x360a16f6);\r
+  rc[35] = _mm_set_epi32(0x26f65241,0xcbe55438,0x43ce5918,0xffbaafde);\r
+  rc[36] = _mm_set_epi32(0x4ce99a54,0xb9f3026a,0xa2ca9cf7,0x839ec978);\r
+  rc[37] = _mm_set_epi32(0xae51a51a,0x1bdff7be,0x40c06e28,0x22901235);\r
+  rc[38] = _mm_set_epi32(0xa0c1613c,0xba7ed22b,0xc173bc0f,0x48a659cf);\r
+  rc[39] = _mm_set_epi32(0x756acc03,0x02288288,0x4ad6bdfd,0xe9c59da1);\r
+}\r
+\r
+void test_implementations() {\r
+  unsigned char *in = (unsigned char *)calloc(64*8, sizeof(unsigned char));\r
+  unsigned char *out256 = (unsigned char *)calloc(32*8, sizeof(unsigned char));\r
+  unsigned char *out512 = (unsigned char *)calloc(32*8, sizeof(unsigned char));\r
+  unsigned char testvector256[32] = {0x80, 0x27, 0xcc, 0xb8, 0x79, 0x49, 0x77, 0x4b,\r
+                                     0x78, 0xd0, 0x54, 0x5f, 0xb7, 0x2b, 0xf7, 0x0c,\r
+                                     0x69, 0x5c, 0x2a, 0x09, 0x23, 0xcb, 0xd4, 0x7b,\r
+                                     0xba, 0x11, 0x59, 0xef, 0xbf, 0x2b, 0x2c, 0x1c};\r
+\r
+ unsigned char testvector512[32] = {0xbe, 0x7f, 0x72, 0x3b, 0x4e, 0x80, 0xa9, 0x98,\r
+                                    0x13, 0xb2, 0x92, 0x28, 0x7f, 0x30, 0x6f, 0x62,\r
+                                    0x5a, 0x6d, 0x57, 0x33, 0x1c, 0xae, 0x5f, 0x34,\r
+                                    0xdd, 0x92, 0x77, 0xb0, 0x94, 0x5b, 0xe2, 0xaa};\r
+\r
+\r
+\r
+  int i;\r
+\r
+  // Input for testvector\r
+  for(i = 0; i < 512; i++) {\r
+    in[i] = i % 64;\r
+  }\r
+\r
+  load_constants();\r
+  haraka512_8x(out512, in);\r
+\r
+  // Verify output\r
+  for(i = 0; i < 32; i++) {\r
+    if (out512[i % 32] != testvector512[i]) {\r
+      printf("Error: testvector incorrect.\n");\r
+      return;\r
+    }\r
+  }\r
+\r
+  free(in);\r
+  free(out256);\r
+  free(out512);\r
+}\r
+\r
+void haraka256(unsigned char *out, const unsigned char *in) {\r
+  __m128i s[2], tmp;\r
+\r
+  s[0] = LOAD(in);\r
+  s[1] = LOAD(in + 16);\r
+\r
+  AES2(s[0], s[1], 0);\r
+  MIX2(s[0], s[1]);\r
+\r
+  AES2(s[0], s[1], 4);\r
+  MIX2(s[0], s[1]);\r
+\r
+  AES2(s[0], s[1], 8);\r
+  MIX2(s[0], s[1]);\r
+\r
+  AES2(s[0], s[1], 12);\r
+  MIX2(s[0], s[1]);\r
+\r
+  AES2(s[0], s[1], 16);\r
+  MIX2(s[0], s[1]);\r
+\r
+  s[0] = _mm_xor_si128(s[0], LOAD(in));\r
+  s[1] = _mm_xor_si128(s[1], LOAD(in + 16));\r
+\r
+  STORE(out, s[0]);\r
+  STORE(out + 16, s[1]);\r
+}\r
+\r
+void haraka256_4x(unsigned char *out, const unsigned char *in) {\r
+  __m128i s[4][2], tmp;\r
+\r
+  s[0][0] = LOAD(in);\r
+  s[0][1] = LOAD(in + 16);\r
+  s[1][0] = LOAD(in + 32);\r
+  s[1][1] = LOAD(in + 48);\r
+  s[2][0] = LOAD(in + 64);\r
+  s[2][1] = LOAD(in + 80);\r
+  s[3][0] = LOAD(in + 96);\r
+  s[3][1] = LOAD(in + 112);\r
+\r
+  // Round 1\r
+  AES2_4x(s[0], s[1], s[2], s[3], 0);\r
+\r
+  MIX2(s[0][0], s[0][1]);\r
+  MIX2(s[1][0], s[1][1]);\r
+  MIX2(s[2][0], s[2][1]);\r
+  MIX2(s[3][0], s[3][1]);\r
+\r
+  // Round 2\r
+  AES2_4x(s[0], s[1], s[2], s[3], 4);\r
+\r
+  MIX2(s[0][0], s[0][1]);\r
+  MIX2(s[1][0], s[1][1]);\r
+  MIX2(s[2][0], s[2][1]);\r
+  MIX2(s[3][0], s[3][1]);\r
+\r
+  // Round 3\r
+  AES2_4x(s[0], s[1], s[2], s[3], 8);\r
+\r
+  MIX2(s[0][0], s[0][1]);\r
+  MIX2(s[1][0], s[1][1]);\r
+  MIX2(s[2][0], s[2][1]);\r
+  MIX2(s[3][0], s[3][1]);\r
+\r
+  // Round 4\r
+  AES2_4x(s[0], s[1], s[2], s[3], 12);\r
+\r
+  MIX2(s[0][0], s[0][1]);\r
+  MIX2(s[1][0], s[1][1]);\r
+  MIX2(s[2][0], s[2][1]);\r
+  MIX2(s[3][0], s[3][1]);\r
+\r
+  // Round 5\r
+  AES2_4x(s[0], s[1], s[2], s[3], 16);\r
+\r
+  MIX2(s[0][0], s[0][1]);\r
+  MIX2(s[1][0], s[1][1]);\r
+  MIX2(s[2][0], s[2][1]);\r
+  MIX2(s[3][0], s[3][1]);\r
+\r
+  // Feed Forward\r
+  s[0][0] = _mm_xor_si128(s[0][0], LOAD(in));\r
+  s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16));\r
+  s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 32));\r
+  s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 48));\r
+  s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 64));\r
+  s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 80));\r
+  s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 96));\r
+  s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 112));\r
+\r
+  STORE(out, s[0][0]);\r
+  STORE(out + 16, s[0][1]);\r
+  STORE(out + 32, s[1][0]);\r
+  STORE(out + 48, s[1][1]);\r
+  STORE(out + 64, s[2][0]);\r
+  STORE(out + 80, s[2][1]);\r
+  STORE(out + 96, s[3][0]);\r
+  STORE(out + 112, s[3][1]);\r
+}\r
+\r
+void haraka256_8x(unsigned char *out, const unsigned char *in) {\r
+  // This is faster on Skylake, the code below is faster on Haswell.\r
+  haraka256_4x(out, in);\r
+  haraka256_4x(out + 128, in + 128);\r
+  return;\r
+  // __m128i s[8][2], tmp;\r
+  //\r
+  // int i;\r
+  //\r
+  // s[0][0] = LOAD(in);\r
+  // s[0][1] = LOAD(in + 16);\r
+  // s[1][0] = LOAD(in + 32);\r
+  // s[1][1] = LOAD(in + 48);\r
+  // s[2][0] = LOAD(in + 64);\r
+  // s[2][1] = LOAD(in + 80);\r
+  // s[3][0] = LOAD(in + 96);\r
+  // s[3][1] = LOAD(in + 112);\r
+  // s[4][0] = LOAD(in + 128);\r
+  // s[4][1] = LOAD(in + 144);\r
+  // s[5][0] = LOAD(in + 160);\r
+  // s[5][1] = LOAD(in + 176);\r
+  // s[6][0] = LOAD(in + 192);\r
+  // s[6][1] = LOAD(in + 208);\r
+  // s[7][0] = LOAD(in + 224);\r
+  // s[7][1] = LOAD(in + 240);\r
+  //\r
+  // // Round 1\r
+  // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0);\r
+  //\r
+  // MIX2(s[0][0], s[0][1]);\r
+  // MIX2(s[1][0], s[1][1]);\r
+  // MIX2(s[2][0], s[2][1]);\r
+  // MIX2(s[3][0], s[3][1]);\r
+  // MIX2(s[4][0], s[4][1]);\r
+  // MIX2(s[5][0], s[5][1]);\r
+  // MIX2(s[6][0], s[6][1]);\r
+  // MIX2(s[7][0], s[7][1]);\r
+  //\r
+  //\r
+  // // Round 2\r
+  // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 4);\r
+  //\r
+  // MIX2(s[0][0], s[0][1]);\r
+  // MIX2(s[1][0], s[1][1]);\r
+  // MIX2(s[2][0], s[2][1]);\r
+  // MIX2(s[3][0], s[3][1]);\r
+  // MIX2(s[4][0], s[4][1]);\r
+  // MIX2(s[5][0], s[5][1]);\r
+  // MIX2(s[6][0], s[6][1]);\r
+  // MIX2(s[7][0], s[7][1]);\r
+  //\r
+  // // Round 3\r
+  // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 8);\r
+  //\r
+  // MIX2(s[0][0], s[0][1]);\r
+  // MIX2(s[1][0], s[1][1]);\r
+  // MIX2(s[2][0], s[2][1]);\r
+  // MIX2(s[3][0], s[3][1]);\r
+  // MIX2(s[4][0], s[4][1]);\r
+  // MIX2(s[5][0], s[5][1]);\r
+  // MIX2(s[6][0], s[6][1]);\r
+  // MIX2(s[7][0], s[7][1]);\r
+  //\r
+  // // Round 4\r
+  // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 12);\r
+  //\r
+  // MIX2(s[0][0], s[0][1]);\r
+  // MIX2(s[1][0], s[1][1]);\r
+  // MIX2(s[2][0], s[2][1]);\r
+  // MIX2(s[3][0], s[3][1]);\r
+  // MIX2(s[4][0], s[4][1]);\r
+  // MIX2(s[5][0], s[5][1]);\r
+  // MIX2(s[6][0], s[6][1]);\r
+  // MIX2(s[7][0], s[7][1]);\r
+  //\r
+  // // Round 5\r
+  // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16);\r
+  //\r
+  // MIX2(s[0][0], s[0][1]);\r
+  // MIX2(s[1][0], s[1][1]);\r
+  // MIX2(s[2][0], s[2][1]);\r
+  // MIX2(s[3][0], s[3][1]);\r
+  // MIX2(s[4][0], s[4][1]);\r
+  // MIX2(s[5][0], s[5][1]);\r
+  // MIX2(s[6][0], s[6][1]);\r
+  // MIX2(s[7][0], s[7][1]);\r
+  //\r
+  // // Feed Forward\r
+  // s[0][0] = _mm_xor_si128(s[0][0], LOAD(in));\r
+  // s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16));\r
+  // s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 32));\r
+  // s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 48));\r
+  // s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 64));\r
+  // s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 80));\r
+  // s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 96));\r
+  // s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 112));\r
+  // s[4][0] = _mm_xor_si128(s[4][0], LOAD(in + 128));\r
+  // s[4][1] = _mm_xor_si128(s[4][1], LOAD(in + 144));\r
+  // s[5][0] = _mm_xor_si128(s[5][0], LOAD(in + 160));\r
+  // s[5][1] = _mm_xor_si128(s[5][1], LOAD(in + 176));\r
+  // s[6][0] = _mm_xor_si128(s[6][0], LOAD(in + 192));\r
+  // s[6][1] = _mm_xor_si128(s[6][1], LOAD(in + 208));\r
+  // s[7][0] = _mm_xor_si128(s[7][0], LOAD(in + 224));\r
+  // s[7][1] = _mm_xor_si128(s[7][1], LOAD(in + 240));\r
+  //\r
+  // STORE(out, s[0][0]);\r
+  // STORE(out + 16, s[0][1]);\r
+  // STORE(out + 32, s[1][0]);\r
+  // STORE(out + 48, s[1][1]);\r
+  // STORE(out + 64, s[2][0]);\r
+  // STORE(out + 80, s[2][1]);\r
+  // STORE(out + 96, s[3][0]);\r
+  // STORE(out + 112, s[3][1]);\r
+  // STORE(out + 128, s[4][0]);\r
+  // STORE(out + 144, s[4][1]);\r
+  // STORE(out + 160, s[5][0]);\r
+  // STORE(out + 176, s[5][1]);\r
+  // STORE(out + 192, s[6][0]);\r
+  // STORE(out + 208, s[6][1]);\r
+  // STORE(out + 224, s[7][0]);\r
+  // STORE(out + 240, s[7][1]);\r
+}\r
+\r
+void haraka512(unsigned char *out, const unsigned char *in) {\r
+  u128 s[4], tmp;\r
+\r
+  s[0] = LOAD(in);\r
+  s[1] = LOAD(in + 16);\r
+  s[2] = LOAD(in + 32);\r
+  s[3] = LOAD(in + 48);\r
+\r
+  AES4(s[0], s[1], s[2], s[3], 0);\r
+  MIX4(s[0], s[1], s[2], s[3]);\r
+\r
+  AES4(s[0], s[1], s[2], s[3], 8);\r
+  MIX4(s[0], s[1], s[2], s[3]);\r
+\r
+  AES4(s[0], s[1], s[2], s[3], 16);\r
+  MIX4(s[0], s[1], s[2], s[3]);\r
+\r
+  AES4(s[0], s[1], s[2], s[3], 24);\r
+  MIX4(s[0], s[1], s[2], s[3]);\r
+\r
+  AES4(s[0], s[1], s[2], s[3], 32);\r
+  MIX4(s[0], s[1], s[2], s[3]);\r
+\r
+  s[0] = _mm_xor_si128(s[0], LOAD(in));\r
+  s[1] = _mm_xor_si128(s[1], LOAD(in + 16));\r
+  s[2] = _mm_xor_si128(s[2], LOAD(in + 32));\r
+  s[3] = _mm_xor_si128(s[3], LOAD(in + 48));\r
+\r
+  TRUNCSTORE(out, s[0], s[1], s[2], s[3]);\r
+}\r
+\r
+void haraka512_4x(unsigned char *out, const unsigned char *in) {\r
+  u128 s[4][4], tmp;\r
+\r
+  s[0][0] = LOAD(in);\r
+  s[0][1] = LOAD(in + 16);\r
+  s[0][2] = LOAD(in + 32);\r
+  s[0][3] = LOAD(in + 48);\r
+  s[1][0] = LOAD(in + 64);\r
+  s[1][1] = LOAD(in + 80);\r
+  s[1][2] = LOAD(in + 96);\r
+  s[1][3] = LOAD(in + 112);\r
+  s[2][0] = LOAD(in + 128);\r
+  s[2][1] = LOAD(in + 144);\r
+  s[2][2] = LOAD(in + 160);\r
+  s[2][3] = LOAD(in + 176);\r
+  s[3][0] = LOAD(in + 192);\r
+  s[3][1] = LOAD(in + 208);\r
+  s[3][2] = LOAD(in + 224);\r
+  s[3][3] = LOAD(in + 240);\r
+\r
+  AES4_4x(s[0], s[1], s[2], s[3], 0);\r
+  MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+\r
+  AES4_4x(s[0], s[1], s[2], s[3], 8);\r
+  MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+\r
+  AES4_4x(s[0], s[1], s[2], s[3], 16);\r
+  MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+\r
+  AES4_4x(s[0], s[1], s[2], s[3], 24);\r
+  MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+\r
+  AES4_4x(s[0], s[1], s[2], s[3], 32);\r
+  MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+\r
+\r
+  s[0][0] = _mm_xor_si128(s[0][0], LOAD(in));\r
+  s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16));\r
+  s[0][2] = _mm_xor_si128(s[0][2], LOAD(in + 32));\r
+  s[0][3] = _mm_xor_si128(s[0][3], LOAD(in + 48));\r
+  s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 64));\r
+  s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 80));\r
+  s[1][2] = _mm_xor_si128(s[1][2], LOAD(in + 96));\r
+  s[1][3] = _mm_xor_si128(s[1][3], LOAD(in + 112));\r
+  s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 128));\r
+  s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 144));\r
+  s[2][2] = _mm_xor_si128(s[2][2], LOAD(in + 160));\r
+  s[2][3] = _mm_xor_si128(s[2][3], LOAD(in + 176));\r
+  s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 192));\r
+  s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 208));\r
+  s[3][2] = _mm_xor_si128(s[3][2], LOAD(in + 224));\r
+  s[3][3] = _mm_xor_si128(s[3][3], LOAD(in + 240));\r
+\r
+  TRUNCSTORE(out, s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  TRUNCSTORE(out + 32, s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  TRUNCSTORE(out + 64, s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  TRUNCSTORE(out + 96, s[3][0], s[3][1], s[3][2], s[3][3]);\r
+}\r
+\r
+void haraka512_8x(unsigned char *out, const unsigned char *in) {\r
+  // This is faster on Skylake, the code below is faster on Haswell.\r
+  haraka512_4x(out, in);\r
+  haraka512_4x(out + 128, in + 256);\r
+\r
+  // u128 s[8][4], tmp;\r
+  //\r
+  // s[0][0] = LOAD(in);\r
+  // s[0][1] = LOAD(in + 16);\r
+  // s[0][2] = LOAD(in + 32);\r
+  // s[0][3] = LOAD(in + 48);\r
+  // s[1][0] = LOAD(in + 64);\r
+  // s[1][1] = LOAD(in + 80);\r
+  // s[1][2] = LOAD(in + 96);\r
+  // s[1][3] = LOAD(in + 112);\r
+  // s[2][0] = LOAD(in + 128);\r
+  // s[2][1] = LOAD(in + 144);\r
+  // s[2][2] = LOAD(in + 160);\r
+  // s[2][3] = LOAD(in + 176);\r
+  // s[3][0] = LOAD(in + 192);\r
+  // s[3][1] = LOAD(in + 208);\r
+  // s[3][2] = LOAD(in + 224);\r
+  // s[3][3] = LOAD(in + 240);\r
+  // s[4][0] = LOAD(in + 256);\r
+  // s[4][1] = LOAD(in + 272);\r
+  // s[4][2] = LOAD(in + 288);\r
+  // s[4][3] = LOAD(in + 304);\r
+  // s[5][0] = LOAD(in + 320);\r
+  // s[5][1] = LOAD(in + 336);\r
+  // s[5][2] = LOAD(in + 352);\r
+  // s[5][3] = LOAD(in + 368);\r
+  // s[6][0] = LOAD(in + 384);\r
+  // s[6][1] = LOAD(in + 400);\r
+  // s[6][2] = LOAD(in + 416);\r
+  // s[6][3] = LOAD(in + 432);\r
+  // s[7][0] = LOAD(in + 448);\r
+  // s[7][1] = LOAD(in + 464);\r
+  // s[7][2] = LOAD(in + 480);\r
+  // s[7][3] = LOAD(in + 496);\r
+  //\r
+  // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0);\r
+  // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+  // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);\r
+  // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);\r
+  // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);\r
+  // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);\r
+  //\r
+  // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 8);\r
+  // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+  // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);\r
+  // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);\r
+  // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);\r
+  // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);\r
+  //\r
+  // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16);\r
+  // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+  // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);\r
+  // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);\r
+  // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);\r
+  // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);\r
+  //\r
+  // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 24);\r
+  // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+  // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);\r
+  // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);\r
+  // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);\r
+  // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);\r
+  //\r
+  // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 32);\r
+  // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);\r
+  // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);\r
+  // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);\r
+  // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);\r
+  // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);\r
+  //\r
+  //\r
+  // s[0][0] = _mm_xor_si128(s[0][0], LOAD(in));\r
+  // s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16));\r
+  // s[0][2] = _mm_xor_si128(s[0][2], LOAD(in + 32));\r
+  // s[0][3] = _mm_xor_si128(s[0][3], LOAD(in + 48));\r
+  // s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 64));\r
+  // s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 80));\r
+  // s[1][2] = _mm_xor_si128(s[1][2], LOAD(in + 96));\r
+  // s[1][3] = _mm_xor_si128(s[1][3], LOAD(in + 112));\r
+  // s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 128));\r
+  // s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 144));\r
+  // s[2][2] = _mm_xor_si128(s[2][2], LOAD(in + 160));\r
+  // s[2][3] = _mm_xor_si128(s[2][3], LOAD(in + 176));\r
+  // s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 192));\r
+  // s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 208));\r
+  // s[3][2] = _mm_xor_si128(s[3][2], LOAD(in + 224));\r
+  // s[3][3] = _mm_xor_si128(s[3][3], LOAD(in + 240));\r
+  // s[4][0] = _mm_xor_si128(s[4][0], LOAD(in + 256));\r
+  // s[4][1] = _mm_xor_si128(s[4][1], LOAD(in + 272));\r
+  // s[4][2] = _mm_xor_si128(s[4][2], LOAD(in + 288));\r
+  // s[4][3] = _mm_xor_si128(s[4][3], LOAD(in + 304));\r
+  // s[5][0] = _mm_xor_si128(s[5][0], LOAD(in + 320));\r
+  // s[5][1] = _mm_xor_si128(s[5][1], LOAD(in + 336));\r
+  // s[5][2] = _mm_xor_si128(s[5][2], LOAD(in + 352));\r
+  // s[5][3] = _mm_xor_si128(s[5][3], LOAD(in + 368));\r
+  // s[6][0] = _mm_xor_si128(s[6][0], LOAD(in + 384));\r
+  // s[6][1] = _mm_xor_si128(s[6][1], LOAD(in + 400));\r
+  // s[6][2] = _mm_xor_si128(s[6][2], LOAD(in + 416));\r
+  // s[6][3] = _mm_xor_si128(s[6][3], LOAD(in + 432));\r
+  // s[7][0] = _mm_xor_si128(s[7][0], LOAD(in + 448));\r
+  // s[7][1] = _mm_xor_si128(s[7][1], LOAD(in + 464));\r
+  // s[7][2] = _mm_xor_si128(s[7][2], LOAD(in + 480));\r
+  // s[7][3] = _mm_xor_si128(s[7][3], LOAD(in + 496));\r
+  //\r
+  // TRUNCSTORE(out, s[0][0], s[0][1], s[0][2], s[0][3]);\r
+  // TRUNCSTORE(out + 32, s[1][0], s[1][1], s[1][2], s[1][3]);\r
+  // TRUNCSTORE(out + 64, s[2][0], s[2][1], s[2][2], s[2][3]);\r
+  // TRUNCSTORE(out + 96, s[3][0], s[3][1], s[3][2], s[3][3]);\r
+  // TRUNCSTORE(out + 128, s[4][0], s[4][1], s[4][2], s[4][3]);\r
+  // TRUNCSTORE(out + 160, s[5][0], s[5][1], s[5][2], s[5][3]);\r
+  // TRUNCSTORE(out + 192, s[6][0], s[6][1], s[6][2], s[6][3]);\r
+  // TRUNCSTORE(out + 224, s[7][0], s[7][1], s[7][2], s[7][3]);\r
+}\r
diff --git a/src/crypto/haraka.h b/src/crypto/haraka.h
new file mode 100644 (file)
index 0000000..ab56424
--- /dev/null
@@ -0,0 +1,111 @@
+/*\r
+The MIT License (MIT)\r
+\r
+Copyright (c) 2016 kste\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy\r
+of this software and associated documentation files (the "Software"), to deal\r
+in the Software without restriction, including without limitation the rights\r
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+copies of the Software, and to permit persons to whom the Software is\r
+furnished to do so, subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in all\r
+copies or substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+SOFTWARE.\r
+\r
+Optimized Implementations for Haraka256 and Haraka512\r
+*/\r
+#ifndef HARAKA_H_\r
+#define HARAKA_H_\r
+\r
+#include "immintrin.h"\r
+\r
+#define NUMROUNDS 5\r
+\r
+#define u64 unsigned long\r
+#define u128 __m128i\r
+\r
+extern u128 rc[40];\r
+\r
+#define LOAD(src) _mm_load_si128((u128 *)(src))\r
+#define STORE(dest,src) _mm_storeu_si128((u128 *)(dest),src)\r
+\r
+#define AES2(s0, s1, rci) \\r
+  s0 = _mm_aesenc_si128(s0, rc[rci]); \\r
+  s1 = _mm_aesenc_si128(s1, rc[rci + 1]); \\r
+  s0 = _mm_aesenc_si128(s0, rc[rci + 2]); \\r
+  s1 = _mm_aesenc_si128(s1, rc[rci + 3]);\r
+\r
+#define AES2_4x(s0, s1, s2, s3, rci) \\r
+  AES2(s0[0], s0[1], rci); \\r
+  AES2(s1[0], s1[1], rci); \\r
+  AES2(s2[0], s2[1], rci); \\r
+  AES2(s3[0], s3[1], rci);\r
+\r
+#define AES2_8x(s0, s1, s2, s3, s4, s5, s6, s7, rci) \\r
+  AES2_4x(s0, s1, s2, s3, rci); \\r
+  AES2_4x(s4, s5, s6, s7, rci);\r
+\r
+#define AES4(s0, s1, s2, s3, rci) \\r
+  s0 = _mm_aesenc_si128(s0, rc[rci]); \\r
+  s1 = _mm_aesenc_si128(s1, rc[rci + 1]); \\r
+  s2 = _mm_aesenc_si128(s2, rc[rci + 2]); \\r
+  s3 = _mm_aesenc_si128(s3, rc[rci + 3]); \\r
+  s0 = _mm_aesenc_si128(s0, rc[rci + 4]); \\r
+  s1 = _mm_aesenc_si128(s1, rc[rci + 5]); \\r
+  s2 = _mm_aesenc_si128(s2, rc[rci + 6]); \\r
+  s3 = _mm_aesenc_si128(s3, rc[rci + 7]); \\r
+\r
+#define AES4_4x(s0, s1, s2, s3, rci) \\r
+  AES4(s0[0], s0[1], s0[2], s0[3], rci); \\r
+  AES4(s1[0], s1[1], s1[2], s1[3], rci); \\r
+  AES4(s2[0], s2[1], s2[2], s2[3], rci); \\r
+  AES4(s3[0], s3[1], s3[2], s3[3], rci);\r
+\r
+#define AES4_8x(s0, s1, s2, s3, s4, s5, s6, s7, rci) \\r
+  AES4_4x(s0, s1, s2, s3, rci); \\r
+  AES4_4x(s4, s5, s6, s7, rci);\r
+\r
+#define MIX2(s0, s1) \\r
+  tmp = _mm_unpacklo_epi32(s0, s1); \\r
+  s1 = _mm_unpackhi_epi32(s0, s1); \\r
+  s0 = tmp;\r
+\r
+#define MIX4(s0, s1, s2, s3) \\r
+  tmp  = _mm_unpacklo_epi32(s0, s1); \\r
+  s0 = _mm_unpackhi_epi32(s0, s1); \\r
+  s1 = _mm_unpacklo_epi32(s2, s3); \\r
+  s2 = _mm_unpackhi_epi32(s2, s3); \\r
+  s3 = _mm_unpacklo_epi32(s0, s2); \\r
+  s0 = _mm_unpackhi_epi32(s0, s2); \\r
+  s2 = _mm_unpackhi_epi32(s1, tmp); \\r
+  s1 = _mm_unpacklo_epi32(s1, tmp);\r
+\r
+#define TRUNCSTORE(out, s0, s1, s2, s3) \\r
+  *(u64*)(out) = (u64*)(s0)[1]; \\r
+  *(u64*)(out + 8) = (u64*)(s1)[1]; \\r
+  *(u64*)(out + 16) = (u64*)(s2)[0]; \\r
+  *(u64*)(out + 24) = (u64*)(s3)[0];\r
+\r
+void load_constants();\r
+void test_implementations();\r
+\r
+void load_constants();\r
+\r
+void haraka256(unsigned char *out, const unsigned char *in);\r
+void haraka256_4x(unsigned char *out, const unsigned char *in);\r
+void haraka256_8x(unsigned char *out, const unsigned char *in);\r
+\r
+void haraka512(unsigned char *out, const unsigned char *in);\r
+void haraka512_4x(unsigned char *out, const unsigned char *in);\r
+void haraka512_8x(unsigned char *out, const unsigned char *in);\r
+\r
+#endif\r
diff --git a/src/crypto/verus_hash.cpp b/src/crypto/verus_hash.cpp
new file mode 100644 (file)
index 0000000..baa5b45
--- /dev/null
@@ -0,0 +1,75 @@
+// (C) 2018 The Verus Developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+/*
+This provides the PoW hash function for Verus, a CPU-optimized hash 
+function with a Haraka V2 core. Unlike Haraka, which is made for short 
+inputs only, Verus Hash takes any length of input and produces a 256 
+bit output.
+*/
+#include <string.h>
+#include "crypto/common.h"
+#include "crypto/verus_hash.h"
+
+void CVerusHash::Hash(void *result, const void *data, size_t len)
+{
+    unsigned char buf[128];
+    unsigned char *bufPtr = buf;
+    int pos = 0, nextOffset = 64;
+    unsigned char *bufPtr2 = bufPtr + nextOffset;
+    unsigned char *ptr = (unsigned char *)data;
+
+    // put our last result or zero at beginning of buffer each time
+    memset(bufPtr, 0, 32);
+
+    // digest up to 32 bytes at a time
+    for ( ; pos < len; pos += 32)
+    {
+        if (len - pos >= 32)
+        {
+            memcpy(bufPtr + 32, ptr + pos, 32);
+        }
+        else
+        {
+            int i = (int)(len - pos);
+            memcpy(bufPtr + 32, ptr + pos, i);
+            memset(bufPtr + 32 + i, 0, 32 - i);
+        }
+        haraka512(bufPtr2, bufPtr);
+        bufPtr2 = bufPtr;
+        bufPtr += nextOffset;
+        nextOffset *= -1;
+    }
+    memcpy(result, bufPtr, 32);
+};
+
+CVerusHash &CVerusHash::Write(const unsigned char *data, size_t len)
+{
+    unsigned char *tmp;
+
+    // digest up to 32 bytes at a time
+    for ( int pos = 0; pos < len; )
+    {
+        int room = 32 - curPos;
+
+        if (len - pos >= room)
+        {
+            memcpy(curBuf + 32 + curPos, data + pos, room);
+            haraka512(result, curBuf);
+            tmp = curBuf;
+            curBuf = result;
+            result = tmp;
+            pos += room;
+            curPos = 0;
+        }
+        else
+        {
+            memcpy(curBuf + 32 + curPos, data + pos, len - pos);
+            curPos += len - pos;
+            pos = len;
+        }
+    }
+    return *this;
+}
+
diff --git a/src/crypto/verus_hash.h b/src/crypto/verus_hash.h
new file mode 100644 (file)
index 0000000..394a5e0
--- /dev/null
@@ -0,0 +1,55 @@
+// (C) 2018 The Verus Developers\r
+// Distributed under the MIT software license, see the accompanying\r
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.\r
+\r
+/*\r
+This provides the PoW hash function for Verus, enabling CPU mining.\r
+*/\r
+#ifndef VERUS_HASH_H_\r
+#define VERUS_HASH_H_\r
+\r
+#include <cstring>\r
+#include <vector>\r
+\r
+extern "C" \r
+{\r
+#include "crypto/haraka.h"\r
+}\r
+\r
+class CVerusHash\r
+{\r
+    public:\r
+        static void Hash(void *result, const void *data, size_t len);\r
+\r
+        CVerusHash() {}\r
+\r
+        CVerusHash &Write(const unsigned char *data, size_t len);\r
+\r
+        CVerusHash &Reset()\r
+        {\r
+            curBuf = buf1;\r
+            result = buf2;\r
+            curPos = 0;\r
+            std::fill(buf1, buf1 + sizeof(buf1), 0);\r
+            std::fill(buf2, buf2 + sizeof(buf2), 0);\r
+        }\r
+\r
+        void Finalize(unsigned char hash[32])\r
+        {\r
+            if (curPos)\r
+            {\r
+                std::fill(curBuf + 32 + curPos, curBuf + 64, 0);\r
+                haraka512(hash, curBuf);\r
+            }\r
+            else\r
+                std::memcpy(hash, result, 32);\r
+        }\r
+\r
+    private:\r
+        // only buf1, the first source, needs to be zero initialized\r
+        unsigned char buf1[64] = {0}, buf2[64];\r
+        unsigned char *curBuf = buf1, *result = buf2;\r
+        size_t curPos = 0;\r
+};\r
+\r
+#endif\r
diff --git a/src/fiat/verus b/src/fiat/verus
new file mode 100644 (file)
index 0000000..e0e37ab
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+./komodo-cli -ac_name=VERUSTEST "$@"
index 06fcced0a8832c812092dfab47d0d6f7cde96706..485655a00d78343cc9ba6d97a9ff83bd2f0da43b 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "crypto/ripemd160.h"
 #include "crypto/sha256.h"
+#include "crypto/verus_hash.h"
 #include "serialize.h"
 #include "uint256.h"
 #include "version.h"
@@ -192,6 +193,37 @@ public:
     }
 };
 
+/** A writer stream (for serialization) that computes a 256-bit Verus hash. */
+class CVerusHashWriter
+{
+private:
+    CVerusHash state;
+
+public:
+    int nType;
+    int nVersion;
+
+    CVerusHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() {}
+
+    CVerusHashWriter& write(const char *pch, size_t size) {
+        state.Write((const unsigned char*)pch, size);
+        return (*this);
+    }
+
+    // invalidates the object for further writing
+    uint256 GetHash() {
+        uint256 result;
+        state.Finalize((unsigned char*)&result);
+        return result;
+    }
+
+    template<typename T>
+    CVerusHashWriter& operator<<(const T& obj) {
+        // Serialize to this stream
+        ::Serialize(*this, obj, nType, nVersion);
+        return (*this);
+    }
+};
 
 /** Compute the 256-bit hash of an object's serialization. */
 template<typename T>
@@ -202,6 +234,15 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
     return ss.GetHash();
 }
 
+/** Compute the 256-bit Verus hash of an object's serialization. */
+template<typename T>
+uint256 SerializeVerusHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
+{
+    CVerusHashWriter ss(nType, nVersion);
+    ss << obj;
+    return ss.GetHash();
+}
+
 unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
 
 void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
index aa55d178269869b04392843d2b54e97716156286..a937a035b8446ea98604fb6fc3aa0f472ab0bec3 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "init.h"
 #include "crypto/common.h"
+#include "primitives/block.h"
 #include "addrman.h"
 #include "amount.h"
 #ifdef ENABLE_MINING
@@ -1099,6 +1100,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
     ECC_Start();
     globalVerifyHandle.reset(new ECCVerifyHandle());
 
+    // set the hash algorithm to use for this chain
+    extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH;
+    if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH)
+        CBlockHeader::SetVerusHash();
+
     // Sanity check
     if (!InitSanityCheck())
         return InitError(_("Initialization sanity check failed. Komodo is shutting down."));
index b1ad32a423c8afd69d1f0634d703252e60c30056..980ac4403f182fd17361b23d1e1ec78804f60929 100644 (file)
@@ -10,6 +10,7 @@
 #include "pubkey.h"
 #include "script/script.h"
 #include "script/standard.h"
+#include "script/script_ext.h"
 #include "sync.h"
 #include "zcash/Address.hpp"
 #include "zcash/NoteEncryption.hpp"
index 2174a8d80ae4a37276bbcb48c346cb2ba93c90d6..e091a447e4151efd983db02e4f6d8055ae62e403 100644 (file)
@@ -1082,7 +1082,8 @@ uint64_t komodo_commission(const CBlock *pblock)
 
 uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr)
 {
-    CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int64_t diff=0; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN;
+    CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int64_t diff=0; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0;
+    uint64_t value,coinage,supply = komodo_current_supply(nHeight);
     txtime = komodo_txtime(&value,txid,vout,address);
     if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 )
         return(0);
index 3f8b498fa6f54664a25004f441123fe9ba8979a5..52377f0b6e659326b7b8f5eb2308387db1012582 100644 (file)
@@ -2,6 +2,7 @@
 #define KOMODO_DEFS_H
 
 #define ASSETCHAINS_MINHEIGHT 128
+#define ASSETCHAINS_MAX_ERAS 3
 #define KOMODO_ELECTION_GAP 2000
 #define ROUNDROBIN_DELAY 61
 #define KOMODO_ASSETCHAIN_MAXLEN 65
index 342d28fe8fe7ace13a79c766939aec70c53a4405..d57005ec921d442abbd0e12a5d0ca8be2073b237 100644 (file)
@@ -54,8 +54,32 @@ char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096];
 uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
 uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC;
 uint32_t ASSETCHAINS_MAGIC = 2387029918;
+int64_t ASSETCHAINS_GENESISTXVAL = 5000000000;
+
+// consensus variables for coinbase timelock control and timelock transaction support
+// time locks are specified enough to enable their use initially to lock specific coinbase transactions for emission control
+// to be verifiable, timelocks require additional data that enables them to be validated and their ownership and
+// release time determined from the blockchain. to do this, every time locked output according to this
+// spec will use an op_return with CLTV at front and anything after |OP_RETURN|PUSH of rest|OPRETTYPE_TIMELOCK|script|
+#define _ASSETCHAINS_TIMELOCKOFF -1
+int64_t ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF;
+uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0;
+
+uint32_t ASSETCHAINS_LASTERA = 1;
+uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS];
+
+#define _ASSETCHAINS_EQUIHASH 0
+uint32_t ASSETCHAINS_NUMALGOS = 2;
+uint32_t ASSETCHAINS_EQUIHASH = _ASSETCHAINS_EQUIHASH;
+uint32_t ASSETCHAINS_VERUSHASH = 1;
+const char *ASSETCHAINS_ALGORITHMS[] = {"equihash", "verushash"};
+uint64_t ASSETCHAINS_NONCEMASK[] = {0xffff,0xffffff};
+uint32_t ASSETCHAINS_NONCESHIFT[] = {32,40};
+uint32_t ASSETCHAINS_HASHESPERROUND[] = {1,512};
+uint32_t ASSETCHAINS_ALGO = _ASSETCHAINS_EQUIHASH;
+
 uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
-uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10;
+uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10;
 
 uint32_t KOMODO_INITDONE;
 char KMDUSERPASS[4096],BTCUSERPASS[4096]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771;
@@ -65,3 +89,155 @@ unsigned int MAX_BLOCK_SIGOPS = 20000;
 
 struct komodo_kv *KOMODO_KV;
 pthread_mutex_t KOMODO_KV_mutex,KOMODO_CC_mutex;
+
+#define MAX_CURRENCIES 32
+char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies
+    "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK",
+    "KMD" };
+
+int32_t komodo_baseid(char *origbase)
+{
+    int32_t i; char base[64];
+    for (i=0; origbase[i]!=0&&i<sizeof(base); i++)
+        base[i] = toupper((int32_t)(origbase[i] & 0xff));
+    base[i] = 0;
+    for (i=0; i<=MAX_CURRENCIES; i++)
+        if ( strcmp(CURRENCIES[i],base) == 0 )
+            return(i);
+    //printf("illegal base.(%s) %s\n",origbase,base);
+    return(-1);
+}
+
+#ifndef SATOSHIDEN
+#define SATOSHIDEN ((uint64_t)100000000L)
+#endif
+int64_t komodo_current_supply(uint32_t nHeight)
+{
+    uint64_t cur_money;
+    int32_t baseid;
+
+    if ( (baseid = komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 )
+        cur_money = ASSETCHAINS_SUPPLY + nHeight * ASSETCHAINS_REWARD[0] / SATOSHIDEN;
+    else 
+    {
+        // figure out max_money by adding up supply to a maximum of 10,000,000 blocks
+        cur_money = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff) + ASSETCHAINS_GENESISTXVAL;
+        if ( ASSETCHAINS_LASTERA == 0 && ASSETCHAINS_REWARD[0] == 0 )
+        {
+            cur_money = ASSETCHAINS_SUPPLY + (nHeight * 10000) / SATOSHIDEN;
+        }
+        else
+        {
+            for ( int j = 0; j <= ASSETCHAINS_LASTERA; j++ )
+            {
+                // if any condition means we have no more rewards, break
+                if (j != 0 && (nHeight <= ASSETCHAINS_ENDSUBSIDY[j - 1] || (ASSETCHAINS_ENDSUBSIDY[j - 1] == 0 && 
+                    (ASSETCHAINS_REWARD[j] == 0 && (j == ASSETCHAINS_LASTERA || ASSETCHAINS_DECAY[j] != SATOSHIDEN)))))
+                    break;
+
+                // add rewards from this era, up to nHeight
+                int64_t reward = ASSETCHAINS_REWARD[j];
+                if ( reward > 0 )
+                {
+                    uint64_t lastEnd = j == 0 ? 0 : ASSETCHAINS_ENDSUBSIDY[j - 1];
+                    uint64_t curEnd = ASSETCHAINS_ENDSUBSIDY[j] == 0 ? nHeight : nHeight > ASSETCHAINS_ENDSUBSIDY[j] ? ASSETCHAINS_ENDSUBSIDY[j] : nHeight;
+                    uint64_t period = ASSETCHAINS_HALVING[j];
+                    uint32_t nSteps = (curEnd - lastEnd) / period;
+                    uint32_t modulo = (curEnd - lastEnd) % period;
+                    uint64_t decay = ASSETCHAINS_DECAY[j];
+
+                    // if exactly SATOSHIDEN, linear decay to zero or to next era, same as:
+                    // (next_era_reward + (starting reward - next_era_reward) / 2) * num_blocks
+                    if ( decay == SATOSHIDEN )
+                    {
+                        int64_t lowestSubsidy, subsidyDifference, stepDifference, stepTriangle;
+                        int64_t denominator, modulo;
+                        int32_t sign = 1;
+
+                        if ( j == ASSETCHAINS_LASTERA )
+                        {
+                            subsidyDifference = reward;
+                            lowestSubsidy = 0;
+                        }
+                        else
+                        {    
+                            // Ex: -ac_eras=3 -ac_reward=0,384,24 -ac_end=1440,260640,0 -ac_halving=1,1440,2103840 -ac_decay 100000000,97750000,0
+                            subsidyDifference = reward - ASSETCHAINS_REWARD[j + 1];
+                            if (subsidyDifference < 0)
+                            {
+                                sign = -1;
+                                subsidyDifference *= sign;
+                                lowestSubsidy = reward;
+                            }
+                            else
+                            {
+                                lowestSubsidy = ASSETCHAINS_REWARD[j + 1];
+                            }
+                        }
+
+                        // if we have not finished the current era, we need to caluclate a total as if we are at the end, with the current
+                        // subsidy. we will calculate the total of a linear era as follows. Each item represents an area calculation:
+                        // a) the rectangle from 0 to the lowest reward in the era * the number of blocks
+                        // b) the rectangle of the remainder of blocks from the lowest point of the era to the highest point of the era if any remainder
+                        // c) the minor triangle from the start of transition from the lowest point to the start of transition to the highest point
+                        // d) one halving triangle (half area of one full step)
+                        //
+                        // we also need:
+                        // e) number of steps = (n - erastart) / halving interval
+                        //
+                        // the total supply from era start up to height is:
+                        // a + b + c + (d * e)
+
+                        // calculate amount in one step's triangular protrusion over minor triangle's hypotenuse
+                        denominator = nSteps * period;
+
+                        // difference of one step vs. total
+                        stepDifference = (period * subsidyDifference) / denominator;
+
+                        // area == coin holding of one step triangle, protruding from minor triangle's hypotenuse
+                        stepTriangle = (period * stepDifference) >> 1;
+
+                        // sign is negative if slope is positive (start is less than end)
+                        if (sign < 0)
+                        {
+                            // use steps minus one for our calculations, and add the potentially partial rectangle
+                            // at the end
+                            cur_money += stepTriangle * (nSteps - 1);
+                            cur_money += stepTriangle * (nSteps - 1) * (nSteps - 1);
+
+                            // difference times number of steps is height of rectangle above lowest subsidy
+                            cur_money += modulo * stepDifference * nSteps;
+                        }
+                        else
+                        {
+                            // if negative slope, the minor triangle is the full number of steps, as the highest
+                            // level step is full. lowest subsidy is just the lowest so far
+                            lowestSubsidy = reward - (stepDifference * nSteps);
+                            
+                            // add the step triangles, one per step
+                            cur_money += stepTriangle * nSteps;
+
+                            // add the minor triangle
+                            cur_money += stepTriangle * nSteps * nSteps;
+                        }
+
+                        // add more for the base rectangle if lowest subsidy is not 0
+                        cur_money += lowestSubsidy * (curEnd - lastEnd);
+                    }
+                    else
+                    {
+                        for ( int k = lastEnd; k < curEnd; k += period )
+                        {
+                            cur_money += period * reward;
+                            // if zero, we do straight halving
+                            reward = decay ? (reward * decay) / SATOSHIDEN : reward >> 1;
+                        }
+                        cur_money += modulo * reward;
+                    }
+                }
+            }
+        }
+    }
+    return((int64_t)(cur_money + (cur_money * ASSETCHAINS_COMMISSION) / SATOSHIDEN));
+}
+
index 36766a1f71bc55aed39d656605230c2e1a0c6920..87cd3490fadbb8c5d00d46b600beed20550cf664 100644 (file)
@@ -13,6 +13,7 @@
  *                                                                            *
  ******************************************************************************/
 #include "komodo_defs.h"
+#include <string.h>
 
 #ifdef _WIN32
 #include <sodium.h>
@@ -801,24 +802,6 @@ char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,
     return(coinaddr);
 }
 
-#define MAX_CURRENCIES 32
-char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies
-    "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK",
-    "KMD" };
-
-int32_t komodo_baseid(char *origbase)
-{
-    int32_t i; char base[64];
-    for (i=0; origbase[i]!=0&&i<sizeof(base); i++)
-        base[i] = toupper((int32_t)(origbase[i] & 0xff));
-    base[i] = 0;
-    for (i=0; i<=MAX_CURRENCIES; i++)
-        if ( strcmp(CURRENCIES[i],base) == 0 )
-            return(i);
-    //printf("illegal base.(%s) %s\n",origbase,base);
-    return(-1);
-}
-
 int32_t komodo_is_issuer()
 {
     if ( ASSETCHAINS_SYMBOL[0] != 0 && komodo_baseid(ASSETCHAINS_SYMBOL) >= 0 )
@@ -1035,6 +1018,49 @@ int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_
     return(offset + opretlen - 1);
 }
 
+// get a pseudo random number that is the same for each block individually at all times and different
+// from all other blocks. the sequence is extremely likely, but not guaranteed to be unique for each block chain
+uint64_t blockPRG(uint32_t nHeight)
+{
+    int i;
+    uint8_t hashSrc[8];
+    uint64_t result, hashSrc64 = (uint64_t)ASSETCHAINS_MAGIC << 32 + nHeight;
+    bits256 hashResult;
+
+    for ( i = 0; i < sizeof(hashSrc); i++ )
+    {
+        hashSrc[i] = hashSrc64 & 0xff;
+        hashSrc64 >>= 8;
+    }
+    vcalc_sha256(0, hashResult.bytes, hashSrc, sizeof(hashSrc));
+
+    for ( i = 0; i < 8; i++ )
+    {
+        result = (result << 8) + hashResult.bytes[i];
+    }
+    return(result);
+}
+
+// given a block height, this returns the unlock time for that block height, derived from
+// the ASSETCHAINS_MAGIC number as well as the block height, providing different random numbers
+// for corresponding blocks across chains, but the same sequence in each chain 
+int64_t komodo_block_unlocktime(uint32_t nHeight)
+{
+    uint64_t fromTime, toTime, unlocktime;
+
+    if ( ASSETCHAINS_TIMEUNLOCKFROM == ASSETCHAINS_TIMEUNLOCKTO )
+        unlocktime = ASSETCHAINS_TIMEUNLOCKTO;
+    else
+    {
+        unlocktime = blockPRG(nHeight) / (0xffffffffffffffff / ((ASSETCHAINS_TIMEUNLOCKTO - ASSETCHAINS_TIMEUNLOCKFROM) + 1));
+        // boundary and power of 2 can make it exceed to time by 1
+        unlocktime = unlocktime + ASSETCHAINS_TIMEUNLOCKFROM;
+        if (unlocktime > ASSETCHAINS_TIMEUNLOCKTO)
+            unlocktime--;
+    }
+    return ((int64_t)unlocktime);
+}
+
 long _stripwhite(char *buf,int accept)
 {
     int32_t i,j,c;
@@ -1499,6 +1525,86 @@ char *argv0names[] =
     (char *)"MNZ", (char *)"MNZ", (char *)"MNZ", (char *)"MNZ", (char *)"BTCH", (char *)"BTCH", (char *)"BTCH", (char *)"BTCH"
 };
 
+int64_t komodo_max_money()
+{
+    return komodo_current_supply(10000000);
+}
+
+uint64_t komodo_ac_block_subsidy(int nHeight)
+{
+    // we have to find our era, start from beginning reward, and determine current subsidy
+    int64_t numerator, denominator, subsidy = 0;
+    int64_t subsidyDifference;
+    int32_t numhalvings, curEra = 0, sign = 1;
+    static uint64_t cached_subsidy; static int32_t cached_numhalvings; static int cached_era;
+
+    // check for backwards compat, older chains with no explicit rewards had 0.0001 block reward
+    if ( ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] == 0 )
+        subsidy = 10000;
+    else if ( (ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] != 0) || ASSETCHAINS_ENDSUBSIDY[0] != 0 )
+    {
+        // if we have an end block in the first era, find our current era
+        if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 )
+        {
+            for ( curEra = 0; curEra <= ASSETCHAINS_LASTERA; curEra++ )
+            {
+                if ( ASSETCHAINS_ENDSUBSIDY[curEra] > nHeight || ASSETCHAINS_ENDSUBSIDY[curEra] == 0 )
+                    break;
+            }
+        }
+        if ( curEra <= ASSETCHAINS_LASTERA )
+        {
+            int64_t nStart = curEra ? ASSETCHAINS_ENDSUBSIDY[curEra - 1] : 0;
+            subsidy = (int64_t)ASSETCHAINS_REWARD[curEra];
+            if ( subsidy || (curEra != ASSETCHAINS_LASTERA && ASSETCHAINS_REWARD[curEra + 1] != 0) )
+            {
+                if ( ASSETCHAINS_HALVING[curEra] != 0 )
+                {
+                    if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 )
+                    {
+                        if ( ASSETCHAINS_DECAY[curEra] == 0 )
+                            subsidy >>= numhalvings;
+                        else if ( ASSETCHAINS_DECAY[curEra] == 100000000 && ASSETCHAINS_ENDSUBSIDY[curEra] != 0 )
+                        {
+                            if ( curEra == ASSETCHAINS_LASTERA )
+                            {
+                                subsidyDifference = subsidy;
+                            }
+                            else
+                            {    
+                                // Ex: -ac_eras=3 -ac_reward=0,384,24 -ac_end=1440,260640,0 -ac_halving=1,1440,2103840 -ac_decay 100000000,97750000,0
+                                subsidyDifference = subsidy - ASSETCHAINS_REWARD[curEra + 1];
+                                if (subsidyDifference < 0)
+                                {
+                                    sign = -1;
+                                    subsidyDifference *= sign;
+                                }
+                            }
+                            denominator = ASSETCHAINS_ENDSUBSIDY[curEra] - nStart;
+                            numerator = denominator - ((ASSETCHAINS_ENDSUBSIDY[curEra] - nHeight) + ((nHeight - nStart) % ASSETCHAINS_HALVING[curEra]));
+                            subsidy = subsidy - sign * ((subsidyDifference * numerator) / denominator);
+                        }
+                        else
+                        {
+                            if ( cached_subsidy > 0 && cached_era == curEra && cached_numhalvings == numhalvings )
+                                subsidy = cached_subsidy;
+                            else
+                            {
+                                for (int i=0; i < numhalvings && subsidy != 0; i++)
+                                    subsidy = (subsidy * ASSETCHAINS_DECAY[curEra]) / 100000000;
+                                cached_subsidy = subsidy;
+                                cached_numhalvings = numhalvings;
+                                cached_era = curEra;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return(subsidy);
+}
+
 void komodo_args(char *argv0)
 {
     extern int64_t MAX_MONEY;
@@ -1534,60 +1640,124 @@ void komodo_args(char *argv0)
     }
     if ( name.c_str()[0] != 0 )
     {
-        MAX_BLOCK_SIGOPS = 60000;
-        ASSETCHAINS_SUPPLY = GetArg("-ac_supply",10);
-        ASSETCHAINS_ENDSUBSIDY = GetArg("-ac_end",0);
-        ASSETCHAINS_REWARD = GetArg("-ac_reward",0);
-        ASSETCHAINS_HALVING = GetArg("-ac_halving",0);
-        ASSETCHAINS_DECAY = GetArg("-ac_decay",0);
-        ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0);
-        ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey","");
-        if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 )
-            ASSETCHAINS_STAKED = 100;
-        if ( ASSETCHAINS_HALVING != 0 && ASSETCHAINS_HALVING < 1440 )
+        std::string selectedAlgo = GetArg("-ac_algo", std::string(ASSETCHAINS_ALGORITHMS[0]));
+
+        for ( int i = 0; i < ASSETCHAINS_NUMALGOS; i++ )
         {
-            ASSETCHAINS_HALVING = 1440;
-            printf("ASSETCHAINS_HALVING must be at least 1440 blocks\n");
+            if (std::string(ASSETCHAINS_ALGORITHMS[i]) == selectedAlgo)
+            {
+                ASSETCHAINS_ALGO = i;
+                // only worth mentioning if it's not equihash
+                if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH)
+                    printf("ASSETCHAINS_ALGO, algorithm set to %s\n", selectedAlgo.c_str());
+                break;
+            }
         }
-        if ( ASSETCHAINS_DECAY == 100000000 && ASSETCHAINS_ENDSUBSIDY == 0 )
+        if (i == ASSETCHAINS_NUMALGOS)
         {
-            ASSETCHAINS_DECAY = 0;
-            printf("ASSETCHAINS_DECAY of 100000000 means linear and that needs ASSETCHAINS_ENDSUBSIDY\n");
+            printf("ASSETCHAINS_ALGO, %s not supported. using equihash\n", selectedAlgo.c_str());
         }
-        else if ( ASSETCHAINS_DECAY > 100000000 )
+
+        ASSETCHAINS_LASTERA = GetArg("-ac_eras", 1);
+        if ( ASSETCHAINS_LASTERA < 1 || ASSETCHAINS_LASTERA > ASSETCHAINS_MAX_ERAS )
         {
-            ASSETCHAINS_DECAY = 0;
-            printf("ASSETCHAINS_DECAY cant be more than 100000000\n");
+            ASSETCHAINS_LASTERA = 1;
+            printf("ASSETCHAINS_LASTERA, if specified, must be between 1 and %u. ASSETCHAINS_LASTERA set to %u\n", ASSETCHAINS_MAX_ERAS, ASSETCHAINS_LASTERA);
         }
+        ASSETCHAINS_LASTERA -= 1;
+
+        ASSETCHAINS_TIMELOCKGTE = GetArg("-ac_timelockgte", _ASSETCHAINS_TIMELOCKOFF);
+        ASSETCHAINS_TIMEUNLOCKFROM = GetArg("-ac_timeunlockfrom", 0);
+        ASSETCHAINS_TIMEUNLOCKTO = GetArg("-ac_timeunlockto", 0);
+        if ( ASSETCHAINS_TIMEUNLOCKFROM > ASSETCHAINS_TIMEUNLOCKTO )
+        {
+            printf("ASSETCHAINS_TIMELOCKGTE - must specify valid ac_timeunlockfrom and ac_timeunlockto\n");
+            ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF;
+            ASSETCHAINS_TIMEUNLOCKFROM = ASSETCHAINS_TIMEUNLOCKTO = 0;
+        }
+
+        Split(GetArg("-ac_end",""),  ASSETCHAINS_ENDSUBSIDY, 0);
+        Split(GetArg("-ac_reward",""),  ASSETCHAINS_REWARD, 0);
+        Split(GetArg("-ac_halving",""),  ASSETCHAINS_HALVING, 0);
+        Split(GetArg("-ac_decay",""),  ASSETCHAINS_DECAY, 0);
+
+        for ( int i = 0; i < ASSETCHAINS_MAX_ERAS; i++ )
+        {
+            if ( ASSETCHAINS_DECAY[i] == 100000000 && ASSETCHAINS_ENDSUBSIDY == 0 )
+            {
+                ASSETCHAINS_DECAY[i] = 0;
+                printf("ERA%u: ASSETCHAINS_DECAY of 100000000 means linear and that needs ASSETCHAINS_ENDSUBSIDY\n", i);
+            }
+            else if ( ASSETCHAINS_DECAY[i] > 100000000 )
+            {
+                ASSETCHAINS_DECAY[i] = 0;
+                printf("ERA%u: ASSETCHAINS_DECAY cant be more than 100000000\n", i);
+            }
+        }
+
+        MAX_BLOCK_SIGOPS = 60000;
+        ASSETCHAINS_SUPPLY = GetArg("-ac_supply",10);
+        ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0);
+        ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey","");
+        if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 )
+            ASSETCHAINS_STAKED = 100;
+
         if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 && ASSETCHAINS_COMMISSION > 0 && ASSETCHAINS_COMMISSION <= 100000000 )
             decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str());
         else if ( ASSETCHAINS_COMMISSION != 0 )
         {
             ASSETCHAINS_COMMISSION = 0;
-            printf("ASSETCHAINS_COMMISSION needs an ASETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n");
+            printf("ASSETCHAINS_COMMISSION needs an ASSETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n");
         }
-        if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_COMMISSION != 0 )
+
+        if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 )
         {
-            fprintf(stderr,"end.%llu blocks, reward %.8f halving.%llu blocks, decay.%llu perc %.4f%% ac_pub=[%02x...]\n",(long long)ASSETCHAINS_ENDSUBSIDY,dstr(ASSETCHAINS_REWARD),(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0]);
+            printf("perc.%llu\n",(long long)ASSETCHAINS_COMMISSION);
+
             extraptr = extrabuf;
             memcpy(extraptr,ASSETCHAINS_OVERRIDE_PUBKEY33,33), extralen = 33;
-            extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ENDSUBSIDY),(void *)&ASSETCHAINS_ENDSUBSIDY);
-            extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_REWARD),(void *)&ASSETCHAINS_REWARD);
-            extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_HALVING),(void *)&ASSETCHAINS_HALVING);
-            extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY),(void *)&ASSETCHAINS_DECAY);
+
+            // if we have one era, this should create the same data structure as it used to, same if we increase _MAX_ERAS
+            for ( int i = 0; i <= ASSETCHAINS_LASTERA; i++ )
+            {
+                printf("ERA%u: end.%llu reward.%llu halving.%llu decay.%llu\n", i,
+                       (long long)ASSETCHAINS_ENDSUBSIDY[i],
+                       (long long)ASSETCHAINS_REWARD[i],
+                       (long long)ASSETCHAINS_HALVING[i],
+                       (long long)ASSETCHAINS_DECAY[i]);
+
+                // TODO: Verify that we don't overrun extrabuf here, which is a 256 byte buffer
+                extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ENDSUBSIDY[i]),(void *)&ASSETCHAINS_ENDSUBSIDY[i]);
+                extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_REWARD[i]),(void *)&ASSETCHAINS_REWARD[i]);
+                extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_HALVING[i]),(void *)&ASSETCHAINS_HALVING[i]);
+                extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY[i]),(void *)&ASSETCHAINS_DECAY[i]);
+            }
+
+            // hash in lock above for time locked coinbase transactions above a certain reward value only if the lock above
+            // param was specified, otherwise, for compatibility, do nothing
+            if ( ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF )
+            {
+                extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_TIMELOCKGTE),(void *)&ASSETCHAINS_TIMELOCKGTE);
+                extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_TIMEUNLOCKFROM),(void *)&ASSETCHAINS_TIMEUNLOCKFROM);
+                extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_TIMEUNLOCKTO),(void *)&ASSETCHAINS_TIMEUNLOCKTO);
+            }
+
+            if ( ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH )
+            {
+                extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ALGO),(void *)&ASSETCHAINS_ALGO);
+            }
+
             val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffffff) << 40);
             extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val);
         }
+
         addn = GetArg("-seednode","");
         if ( strlen(addn.c_str()) > 0 )
             ASSETCHAINS_SEED = 1;
-        strncpy(ASSETCHAINS_SYMBOL,name.c_str(),64);
-        if ( (baseid= komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 )
-            MAX_MONEY = komodo_maxallowed(baseid);
-        else if ( ASSETCHAINS_REWARD == 0 )
-            MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN;
-        else MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + ASSETCHAINS_REWARD * (ASSETCHAINS_ENDSUBSIDY==0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY);
-        MAX_MONEY += (MAX_MONEY * ASSETCHAINS_COMMISSION) / SATOSHIDEN;
+        strncpy(ASSETCHAINS_SYMBOL,name.c_str(),sizeof(ASSETCHAINS_SYMBOL)-1);
+
+        MAX_MONEY = komodo_max_money();
+
         //printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN);
         ASSETCHAINS_P2PPORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen);
         while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 )
index 511a7413c5cb5ff8c9af5b4c70012bbf005ececb..b626a6151f232537b744b0aa43c4d99fcf2b0b2a 100644 (file)
@@ -901,6 +901,49 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
     return nSigOps;
 }
 
+/**
+ * Ensure that a coinbase transaction is structured according to the consensus rules of the
+ * chain
+ */
+bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeight)
+{
+    // if time locks are on, ensure that this coin base is time locked exactly as it should be
+    if ((uint64_t)(tx.GetValueOut()) >= ASSETCHAINS_TIMELOCKGTE)
+    {
+        CScriptID scriptHash;
+
+        // to be valid, it must be a P2SH transaction and have an op_return in vout[1] that 
+        // holds the full output script, which may include multisig, etc., but starts with 
+        // the time lock verify of the correct time lock for this block height
+        if (tx.vout.size() == 2 &&
+            CScriptExt(tx.vout[0].scriptPubKey).IsPayToScriptHash(&scriptHash) &&
+            tx.vout[1].scriptPubKey.size() >= 7 && // minimum for any possible future to prevent out of bounds
+            tx.vout[1].scriptPubKey.data()[0] == OP_RETURN)
+        {
+            opcodetype op;
+            std::vector<uint8_t> opretData = std::vector<uint8_t>();
+            CScript::const_iterator it = tx.vout[1].scriptPubKey.begin() + 1;
+            if (tx.vout[1].scriptPubKey.GetOp2(it, op, &opretData))
+            {
+                if (opretData.size() > 0 && opretData.data()[0] == OPRETTYPE_TIMELOCK)
+                {
+                    int64_t unlocktime;
+                    CScriptExt opretScript = CScriptExt(opretData.begin() + 1, opretData.end());
+
+                    if (CScriptID(opretScript) == scriptHash &&
+                        opretScript.IsCheckLockTimeVerify(&unlocktime) &&
+                        komodo_block_unlocktime(nHeight) == unlocktime)
+                    {
+                        return(true);
+                    }
+                }
+            }
+        }
+        return(false);
+    }
+    return(true);
+}
+
 /**
  * Check a transaction contextually against a set of consensus rules valid at a given block height.
  *
@@ -970,6 +1013,13 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
                              REJECT_INVALID, "bad-txns-invalid-joinsplit-signature");
         }
     }
+
+    if (tx.IsCoinBase())
+    {
+        if (!ContextualCheckCoinbaseTransaction(tx, nHeight))
+            return state.DoS(100, error("CheckTransaction(): invalid script data for coinbase time lock"),
+                                REJECT_INVALID, "bad-txns-invalid-script-data-for-coinbase-time-lock");
+    }
     return true;
 }
 
@@ -1707,12 +1757,12 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW)
 
 //uint64_t komodo_moneysupply(int32_t height);
 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
+extern uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS];
 extern uint32_t ASSETCHAINS_MAGIC;
-extern uint64_t ASSETCHAINS_STAKED,ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY;
+extern uint64_t ASSETCHAINS_STAKED,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY;
 
 CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
 {
-    static uint64_t cached_subsidy; static int32_t cached_numhalvings;
     int32_t numhalvings,i; uint64_t numerator; CAmount nSubsidy = 3 * COIN;
     if ( ASSETCHAINS_SYMBOL[0] == 0 )
     {
@@ -1726,45 +1776,8 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
     {
         if ( nHeight == 1 )
             return(ASSETCHAINS_SUPPLY * COIN + (ASSETCHAINS_MAGIC & 0xffffff));
-        else if ( ASSETCHAINS_ENDSUBSIDY == 0 || nHeight < ASSETCHAINS_ENDSUBSIDY )
-        {
-            if ( ASSETCHAINS_REWARD == 0 )
-                return(10000);
-            else if ( ASSETCHAINS_ENDSUBSIDY != 0 && nHeight >= ASSETCHAINS_ENDSUBSIDY )
-                return(0);
-            else
-            {
-                nSubsidy = ASSETCHAINS_REWARD;
-                if ( ASSETCHAINS_HALVING != 0 )
-                {
-                    if ( (numhalvings= (nHeight / ASSETCHAINS_HALVING)) > 0 )
-                    {
-                        if ( numhalvings >= 64 && ASSETCHAINS_DECAY == 0 )
-                            return(0);
-                        if ( ASSETCHAINS_DECAY == 0 )
-                            nSubsidy >>= numhalvings;
-                        else if ( ASSETCHAINS_DECAY == 100000000 && ASSETCHAINS_ENDSUBSIDY != 0 )
-                        {
-                            numerator = (ASSETCHAINS_ENDSUBSIDY - nHeight);
-                            nSubsidy = (nSubsidy * numerator) / ASSETCHAINS_ENDSUBSIDY;
-                        }
-                        else
-                        {
-                            if ( cached_subsidy > 0 && cached_numhalvings == numhalvings )
-                                nSubsidy = cached_subsidy;
-                            else
-                            {
-                                for (i=0; i<numhalvings&&nSubsidy!=0; i++)
-                                    nSubsidy = (nSubsidy * ASSETCHAINS_DECAY) / 100000000;
-                                cached_subsidy = nSubsidy;
-                                cached_numhalvings = numhalvings;
-                            }
-                        }
-                    }
-                }
-            }
-            return(nSubsidy);
-        } else return(0);
+        else
+            return(komodo_ac_block_subsidy(nHeight));
     }
     /*
      // Mining slow start
@@ -1789,7 +1802,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
     
     // Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years.
     //nSubsidy >>= halvings;
-    return nSubsidy;
+    //return nSubsidy;
 }
 
 bool IsInitialBlockDownload()
@@ -3869,6 +3882,7 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
     if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
         return state.DoS(100, error("CheckBlock: first tx is not coinbase"),
                          REJECT_INVALID, "bad-cb-missing");
+
     for (unsigned int i = 1; i < block.vtx.size(); i++)
         if (block.vtx[i].IsCoinBase())
             return state.DoS(100, error("CheckBlock: more than one coinbase"),
@@ -3918,14 +3932,23 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
     {
         cout << block.nBits << " block.nBits vs. calc " << GetNextWorkRequired(pindexPrev, &block, consensusParams) << endl;
         return state.DoS(100, error("%s: incorrect proof of work", __func__),
-                         REJECT_INVALID, "bad-diffbits");
+                        REJECT_INVALID, "bad-diffbits");
     }
     
     // Check timestamp against prev
     if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
+    {
         return state.Invalid(error("%s: block's timestamp is too early", __func__),
-                             REJECT_INVALID, "time-too-old");
-    
+                        REJECT_INVALID, "time-too-old");
+    }
+
+    // Check that timestamp is not too far in the future
+    if (block.GetBlockTime() > GetAdjustedTime() + consensusParams.nMaxFutureBlockTime)
+    {
+        return state.Invalid(error("%s: block timestamp too far in the future", __func__),
+                        REJECT_INVALID, "time-too-new");
+    }
+
     if (fCheckpointsEnabled)
     {
         // Check that the block chain matches the known block chain up to a checkpoint
index ef46cd83d1c5c631f4f847477a6ca4597f80b942..3a43b5fba95470f19bcd55b358f2b0f98abc7bd5 100644 (file)
@@ -22,6 +22,7 @@
 #include "script/script.h"
 #include "script/serverchecker.h"
 #include "script/standard.h"
+#include "script/script_ext.h"
 #include "spentindex.h"
 #include "sync.h"
 #include "tinyformat.h"
index 2d60d30ca6a066ec006c0acc44540a0e0ce5d4ba..65d88ce8425fd36718b5cc7c97b165538325f872 100644 (file)
@@ -21,7 +21,7 @@ struct AtomicCounter {
         --value;
     }
 
-    int get() const {
+    uint64_t get() const {
         return value.load();
     }
 };
index a62f39846db77e7da2d7c3a5fd9a50a9fbbbd0be..0f6b79d9125038be4455813add641059ed08b71c 100644 (file)
 #include "consensus/validation.h"
 #ifdef ENABLE_MINING
 #include "crypto/equihash.h"
+#include "crypto/verus_hash.h"
 #endif
 #include "hash.h"
+
 #include "main.h"
 #include "metrics.h"
 #include "net.h"
@@ -106,7 +108,10 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
 #include "komodo_defs.h"
 
 extern int32_t ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
-extern uint64_t ASSETCHAINS_REWARD,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED;
+extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED;
+extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
+extern const char *ASSETCHAINS_ALGORITHMS[];
+extern int32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
 extern std::string NOTARY_PUBKEY;
 extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
@@ -119,6 +124,7 @@ int32_t komodo_baseid(char *origbase);
 //int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t tokomodo);
 //int32_t komodo_isrealtime(int32_t *kmdheightp);
 int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag);
+int64_t komodo_block_unlocktime(uint32_t nHeight);
 uint64_t komodo_commission(const CBlock *block);
 int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig);
 
@@ -188,8 +194,22 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
         CBlockIndex* pindexPrev = chainActive.Tip();
         const int nHeight = pindexPrev->nHeight + 1;
         uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus());
-        pblock->nTime = GetAdjustedTime();
+
         const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
+        uint32_t proposedTime = GetAdjustedTime();
+        if (proposedTime == nMedianTimePast)
+        {
+            // too fast or stuck, this addresses the too fast issue, while moving
+            // forward as quickly as possible
+            for (int i; i < 100; i++)
+            {
+                proposedTime = GetAdjustedTime();
+                if (proposedTime == nMedianTimePast)
+                    MilliSleep(10);
+            }
+        }
+        pblock->nTime = GetAdjustedTime();
+
         CCoinsViewCache view(pcoinsTip);
         uint32_t expired; uint64_t commission;
         
@@ -436,17 +456,34 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
         CMutableTransaction txNew = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight);
         txNew.vin.resize(1);
         txNew.vin[0].prevout.SetNull();
+        txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
+
         txNew.vout.resize(1);
         txNew.vout[0].scriptPubKey = scriptPubKeyIn;
-        txNew.vout[0].nValue = GetBlockSubsidy(nHeight,chainparams.GetConsensus());
-        txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+        txNew.vout[0].nValue = GetBlockSubsidy(nHeight,chainparams.GetConsensus()) + nFees;
         txNew.nExpiryHeight = 0;
-        // Add fees
-        txNew.vout[0].nValue += nFees;
-        txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
-                
-        pblock->vtx[0] = txNew;
-        if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission((CBlock*)&pblocktemplate->block)) != 0 )
+        txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+
+        // check if coinbase transactions must be time locked at current subsidy and prepend the time lock
+        // to transaction if so, cast for GTE operator
+        if ((uint64_t)(txNew.vout[0].nValue) >= ASSETCHAINS_TIMELOCKGTE)
+        {
+            int32_t opretlen, p2shlen, scriptlen;
+            CScriptExt opretScript = CScriptExt();
+
+            txNew.vout.resize(2);
+
+            // prepend time lock to original script unless original script is P2SH, in which case, we will leave the coins
+            // protected only by the time lock rather than 100% inaccessible
+            opretScript.AddCheckLockTimeVerify(komodo_block_unlocktime(nHeight));
+            if (!scriptPubKeyIn.IsPayToScriptHash())
+                opretScript += scriptPubKeyIn;
+
+            txNew.vout[0].scriptPubKey = CScriptExt().PayToScriptHash(CScriptID(opretScript));
+            txNew.vout[1].scriptPubKey = CScriptExt().OpReturnScript(opretScript, OPRETTYPE_TIMELOCK);
+            txNew.vout[1].nValue = 0;
+        } // timelocks and commissions are currently incompatible due to validation complexity of the combination
+        else if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission((CBlock*)&pblocktemplate->block)) != 0 )
         {
             int32_t i; uint8_t *ptr;
             txNew.vout.resize(2);
@@ -458,13 +495,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
                 ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i];
             ptr[34] = OP_CHECKSIG;
             //printf("autocreate commision vout\n");
-            pblock->vtx[0] = txNew;
         }
+
+        pblock->vtx[0] = txNew;
         pblocktemplate->vTxFees[0] = -nFees;
+
         // Randomise nonce
         arith_uint256 nonce = UintToArith256(GetRandHash());
-        // Clear the top and bottom 16 bits (for local use as thread flags and counters)
-        nonce <<= 32;
+
+        // Clear the top 16 and bottom 16 or 24 bits (for local use as thread flags and counters)
+        nonce <<= ASSETCHAINS_NONCESHIFT[ASSETCHAINS_ALGO];
         nonce >>= 16;
         pblock->nNonce = ArithToUint256(nonce);
         
@@ -685,6 +725,213 @@ extern int32_t KOMODO_LASTMINED;
 int32_t roundrobin_delay;
 arith_uint256 HASHTarget,HASHTarget_POW;
 
+#ifdef ENABLE_WALLET
+void static BitcoinMiner_noeq(CWallet *pwallet)
+#else
+void static BitcoinMiner_noeq()
+#endif
+{
+    LogPrintf("KomodoMiner started\n");
+    SetThreadPriority(THREAD_PRIORITY_LOWEST);
+    RenameThread("komodo-miner");
+
+#ifdef ENABLE_WALLET
+    // Each thread has its own key
+    CReserveKey reservekey(pwallet);
+#endif
+
+    const CChainParams& chainparams = Params();
+    // Each thread has its own counter
+    unsigned int nExtraNonce = 0;
+    std::vector<unsigned char> solnPlaceholder = std::vector<unsigned char>();
+    solnPlaceholder.resize(Eh200_9.SolutionWidth);
+
+    uint8_t *script; uint64_t total,checktoshis; int32_t i,j;
+
+    while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.Tip()->nHeight != 235300 &&
+    {
+        sleep(1);
+        if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 )
+            break;
+    }
+    miningTimer.start();
+
+    try {
+        fprintf(stderr,"Komodo miner mining %s with %s\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
+        while (true)
+        {
+            if (chainparams.MiningRequiresPeers())
+            {
+                miningTimer.stop();
+                do {
+                    bool fvNodesEmpty;
+                    {
+                        LOCK(cs_vNodes);
+                        fvNodesEmpty = vNodes.empty();
+                    }
+                    if (!fvNodesEmpty )
+                        break;
+                    MilliSleep(1000);
+                } while (true);
+                miningTimer.start();
+            }
+
+            // Create new block
+            unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
+            CBlockIndex* pindexPrev = chainActive.Tip();
+            if ( Mining_height != pindexPrev->nHeight+1 )
+            {
+                Mining_height = pindexPrev->nHeight+1;
+                Mining_start = (uint32_t)time(NULL);
+            }
+
+            //fprintf(stderr,"%s create new block ht.%d\n",ASSETCHAINS_SYMBOL,Mining_height);
+
+#ifdef ENABLE_WALLET
+            CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey);
+#else
+            CBlockTemplate *ptr = CreateNewBlockWithKey();
+#endif
+            if ( ptr == 0 )
+            {
+                static uint32_t counter;
+                if ( counter++ < 100 )
+                    fprintf(stderr,"created illegal block, retry\n");
+                continue;
+            }
+            unique_ptr<CBlockTemplate> pblocktemplate(ptr);
+            if (!pblocktemplate.get())
+            {
+                if (GetArg("-mineraddress", "").empty()) {
+                    LogPrintf("Error in KomodoMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
+                } else {
+                    // Should never reach here, because -mineraddress validity is checked in init.cpp
+                    LogPrintf("Error in KomodoMiner: Invalid -mineraddress\n");
+                }
+                return;
+            }
+            CBlock *pblock = &pblocktemplate->block;
+            if ( ASSETCHAINS_SYMBOL[0] != 0 )
+            {
+                if ( ASSETCHAINS_REWARD[0] == 0 && !ASSETCHAINS_LASTERA )
+                {
+                    if ( pblock->vtx.size() == 1 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT )
+                    {
+                        static uint32_t counter;
+                        if ( counter++ < 10 )
+                            fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",ASSETCHAINS_SYMBOL);
+                        sleep(10);
+                        continue;
+                    } else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
+                }
+            }
+            IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
+            LogPrintf("Running %s miner with %u transactions in block (%u bytes)\n",ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO],
+                       pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
+            //
+            // Search
+            //
+            uint32_t savebits; int64_t nStart = GetTime();
+
+            pblock->nSolution = solnPlaceholder;
+            savebits = pblock->nBits;
+            arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
+            arith_uint256 mask(ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO]);
+
+            Mining_start = 0;
+            while (true)
+            {
+                // for speed check multiples at a time
+                for (int i = 0; i < ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO]; i++)
+                {
+                    solutionTargetChecks.increment();
+
+                    // Update nNonce and nTime
+                    pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1);
+
+                    if ( UintToArith256(pblock->GetHash()) <= hashTarget )
+                    {
+                        SetThreadPriority(THREAD_PRIORITY_NORMAL);
+
+                        LogPrintf("KomodoMiner using %s algorithm:\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
+                        LogPrintf("proof-of-work found  \n  hash: %s  \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex());
+                        printf("FOUND BLOCK %d!  \n  hash: %s  \ntarget: %s\n", Mining_height, pblock->GetHash().GetHex().c_str(), hashTarget.GetHex().c_str());
+#ifdef ENABLE_WALLET
+                        ProcessBlockFound(pblock, *pwallet, reservekey);
+#else
+                        ProcessBlockFound(pblock));
+#endif
+                        SetThreadPriority(THREAD_PRIORITY_LOWEST);
+
+                        // In regression test mode, stop mining after a block is found.
+                        if (chainparams.MineBlocksOnDemand()) {
+                            throw boost::thread_interrupted();
+                        }
+                        break;
+                    }
+                    // check if we're wrapping around on the nonce
+                    if ((UintToArith256(pblock->nNonce) & mask) == mask)
+                    {
+                        fprintf(stderr,"%lx, break\n", ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO]);
+                        break;
+                    }
+                }
+
+                // Check for stop or if block needs to be rebuilt
+                boost::this_thread::interruption_point();
+
+                if (vNodes.empty() && chainparams.MiningRequiresPeers())
+                {
+                    if ( Mining_height > ASSETCHAINS_MINHEIGHT )
+                    {
+                        fprintf(stderr,"no nodes, break\n");
+                        break;
+                    }
+                }
+
+                if ((UintToArith256(pblock->nNonce) & mask) == mask)
+                {
+                    fprintf(stderr,"%lx, break\n", ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO]);
+                    break;
+                }
+
+                if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
+                {
+                    fprintf(stderr,"timeout, break\n");
+                    break;
+                }
+
+                if ( pindexPrev != chainActive.Tip() )
+                {
+                    fprintf(stderr,"Tip advanced, break\n");
+                    break;
+                }
+
+                pblock->nBits = savebits;
+                UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
+                if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
+                {
+                    // Changing pblock->nTime can change work required on testnet:
+                    hashTarget.SetCompact(pblock->nBits);
+                }
+            }
+        }
+    }
+    catch (const boost::thread_interrupted&)
+    {
+        miningTimer.stop();
+        LogPrintf("KomodoMiner terminated\n");
+        throw;
+    }
+    catch (const std::runtime_error &e)
+    {
+        miningTimer.stop();
+        LogPrintf("KomodoMiner runtime error: %s\n", e.what());
+        return;
+    }
+    miningTimer.stop();
+}
+
 #ifdef ENABLE_WALLET
 void static BitcoinMiner(CWallet *pwallet)
 #else
@@ -807,7 +1054,7 @@ void static BitcoinMiner()
             CBlock *pblock = &pblocktemplate->block;
             if ( ASSETCHAINS_SYMBOL[0] != 0 )
             {
-                if ( ASSETCHAINS_REWARD == 0 )
+                if ( ASSETCHAINS_REWARD[0] == 0 && !ASSETCHAINS_LASTERA )
                 {
                     if ( pblock->vtx.size() == 1 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT )
                     {
@@ -912,6 +1159,7 @@ void static BitcoinMiner()
                  }*/
                 // Hash state
                 KOMODO_CHOSEN_ONE = 0;
+                
                 crypto_generichash_blake2b_state state;
                 EhInitialiseState(n, k, state);
                 // I = the block header minus nonce and solution.
@@ -1190,9 +1438,15 @@ void static BitcoinMiner()
         minerThreads = new boost::thread_group();
         for (int i = 0; i < nThreads; i++) {
 #ifdef ENABLE_WALLET
+        if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
             minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
+        else
+            minerThreads->create_thread(boost::bind(&BitcoinMiner_noeq, pwallet));
 #else
+        if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
             minerThreads->create_thread(&BitcoinMiner);
+        else
+            minerThreads->create_thread(&BitcoinMiner_noeq);
 #endif
         }
     }
index bd2410616b282c308c20cf37a949fd752b743516..11c4b17ab371952b4ddfbb96ffd39f766790ce48 100644 (file)
 #endif // ENABLE_RUST
 uint32_t komodo_chainactive_timestamp();
 
+extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH;
+unsigned int lwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params);
+unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
+
 unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
 {
+    if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH)
+        return lwmaGetNextWorkRequired(pindexLast, pblock, params);
+
     unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
     // Genesis block
     if (pindexLast == NULL )
@@ -81,8 +88,60 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
     return bnNew.GetCompact();
 }
 
+unsigned int lwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
+{
+    return lwmaCalculateNextWorkRequired(pindexLast, params);
+}
+
+unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params)
+{
+    unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
+
+    // Find the first block in the averaging interval as we total the linearly weighted average
+    const CBlockIndex* pindexFirst = pindexLast;
+    const CBlockIndex* pindexNext;
+    arith_uint256 nextTarget {0}, sumTarget {0}, bnTmp;
+    int64_t t = 0, solvetime, k = params.nLwmaAjustedWeight, N = params.nPowAveragingWindow;
+
+    for (int i = 0, j = N - 1; pindexFirst && i < N; i++, j--) {
+        pindexNext = pindexFirst;
+        pindexFirst = pindexFirst->pprev;
+        if (!pindexFirst)
+            break;
+
+        solvetime = pindexNext->GetBlockTime() - pindexFirst->GetBlockTime();
+
+        // weighted sum
+        t += solvetime * j;
+
+        // Target sum divided by a factor, (k N^2).
+        // The factor is a part of the final equation. However we divide 
+        // here to avoid potential overflow.
+        bnTmp.SetCompact(pindexNext->nBits);
+        sumTarget += bnTmp / (k * N * N);
+    }
+
+    // Check we have enough blocks
+    if (!pindexFirst)
+        return nProofOfWorkLimit;
+
+    // Keep t reasonable in case strange solvetimes occurred.
+    if (t < N * k / 3)
+        t = N * k / 3;
+
+    bnTmp = UintToArith256(params.powLimit);
+    nextTarget = t * sumTarget;
+    if (nextTarget > bnTmp)
+        nextTarget = bnTmp;
+
+    return nextTarget.GetCompact();
+}
+
 bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params)
 {
+    if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH)
+        return true;
+
     unsigned int n = params.EquihashN();
     unsigned int k = params.EquihashK();
 
@@ -110,6 +169,7 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param
 
     bool isValid;
     EhIsValidSolution(n, k, state, pblock->nSolution, isValid);
+
     if (!isValid)
         return error("CheckEquihashSolution(): invalid solution");
 
index c2300c82a0b1ba819ead33aba547f87d914cdcdb..58164ad8a37126e9ba9580e65cc62676ebb96c47 100644 (file)
 #include "utilstrencodings.h"
 #include "crypto/common.h"
 
-uint256 CBlockHeader::GetHash() const
+// default hash algorithm for block
+uint256 (CBlockHeader::*CBlockHeader::hashFunction)() const = &CBlockHeader::GetSHA256DHash;
+
+uint256 CBlockHeader::GetSHA256DHash() const
 {
     return SerializeHash(*this);
 }
 
+uint256 CBlockHeader::GetVerusHash() const
+{
+    if (hashPrevBlock == uint256())
+        // always use SHA256D for genesis block
+        return SerializeHash(*this);
+    else
+        return SerializeVerusHash(*this);
+}
+
+void CBlockHeader::SetSHA256DHash()
+{
+    CBlockHeader::hashFunction = &CBlockHeader::GetSHA256DHash;
+}
+
+void CBlockHeader::SetVerusHash()
+{
+    CBlockHeader::hashFunction = &CBlockHeader::GetVerusHash;
+}
+
 uint256 CBlock::BuildMerkleTree(bool* fMutated) const
 {
     /* WARNING! If you're reading this because you're learning about crypto
index 6b3f13a865dee428bc84c95e94ec52aaf4d61c21..7b5a06fe48b77a820eea88f32cbeff967dd67091 100644 (file)
@@ -23,6 +23,10 @@ public:
     // header
     static const size_t HEADER_SIZE=4+32+32+32+4+4+32; // excluding Equihash solution
     static const int32_t CURRENT_VERSION=4;
+    static uint256 (CBlockHeader::*hashFunction)() const;
+    
+    static void SetHashAlgo();
+
     int32_t nVersion;
     uint256 hashPrevBlock;
     uint256 hashMerkleRoot;
@@ -69,7 +73,16 @@ public:
         return (nBits == 0);
     }
 
-    uint256 GetHash() const;
+    uint256 GetHash() const
+    {
+        return (this->*hashFunction)();
+    }
+
+    uint256 GetSHA256DHash() const;
+    static void SetSHA256DHash();
+
+    uint256 GetVerusHash() const;
+    static void SetVerusHash();
 
     int64_t GetBlockTime() const
     {
index 170e45d59979b103595f0e3b33c50bebfb1ebd48..eba8e8237da5f27be64b16663e0d453b9e98eb08 100644 (file)
@@ -269,6 +269,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
             COINBASE_MATURITY = _COINBASE_MATURITY;
         quint32 numBlocksToMaturity = COINBASE_MATURITY +  1;
         strHTML += "<br>" + tr("Generated coins must mature %1 blocks 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)) + "<br>";
+        // we need to display any possible CLTV lock time
     }
 
     //
index aea5694f237724ab2c8cb08e0ac8cc312516745c..a419b614e745f2a8ef4ac3ea7e7bf73a5601f550 100644 (file)
@@ -32,6 +32,8 @@
 
 using namespace std;
 
+extern int32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH;
+
 /**
  * Return average network hashes per second based on the last 'lookup' blocks,
  * or over the difficulty averaging window if 'lookup' is nonpositive.
@@ -371,8 +373,15 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
     obj.push_back(Pair("difficulty",       (double)GetNetworkDifficulty()));
     obj.push_back(Pair("errors",           GetWarnings("statusbar")));
     obj.push_back(Pair("genproclimit",     (int)GetArg("-genproclimit", -1)));
-    obj.push_back(Pair("localsolps"  ,     getlocalsolps(params, false)));
-    obj.push_back(Pair("networksolps",     getnetworksolps(params, false)));
+    if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
+    {
+        obj.push_back(Pair("localsolps"  ,     getlocalsolps(params, false)));
+        obj.push_back(Pair("networksolps",     getnetworksolps(params, false)));
+    }
+    else
+    {
+        obj.push_back(Pair("localhashps"  ,     getlocalsolps(params, false)));
+    }
     obj.push_back(Pair("networkhashps",    getnetworksolps(params, false)));
     obj.push_back(Pair("pooledtx",         (uint64_t)mempool.size()));
     obj.push_back(Pair("testnet",          Params().TestnetToBeDeprecatedFieldRPC()));
diff --git a/src/script/script_ext.cpp b/src/script/script_ext.cpp
new file mode 100644 (file)
index 0000000..655d256
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2018 The Verus developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "script_ext.h"
+
+using namespace std;
+
+bool CScriptExt::IsPayToScriptHash(CScriptID *scriptID) const
+{
+    if (((CScript *)this)->IsPayToScriptHash())
+    {
+        *scriptID = CScriptID(uint160(std::vector<unsigned char>(this->begin() + 2, this->end() - 1)));
+        return true;
+    }
+    return false;
+}
+
+// P2PKH script, adds to whatever is already in the script (for example CLTV)
+const CScriptExt &CScriptExt::AddPayToPubKeyHash(const CKeyID &key) const
+{
+    *((CScript *)this) << OP_DUP;
+    *((CScript *)this) << OP_HASH160;
+    *((CScript *)this) << ToByteVector(key);
+    *((CScript *)this) << OP_EQUALVERIFY;
+    *((CScript *)this) << OP_CHECKSIG;
+    return *this;
+}
+
+// push data into an op_return script with an opret type indicator, fails if the op_return is too large
+const CScriptExt &CScriptExt::OpReturnScript(const vector<unsigned char> &data, unsigned char opretType) const
+{
+    ((CScript *)this)->clear();
+    if (data.size() < MAX_SCRIPT_ELEMENT_SIZE)
+    {
+        vector<unsigned char> scratch = vector<unsigned char>(data);
+        scratch.insert(scratch.begin(), opretType);
+        *((CScript *)this) << OP_RETURN;
+        *((CScript *)this) << scratch;
+    }
+    return *this;
+}
+
+// P2SH script, adds to whatever is already in the script (for example CLTV)
+const CScriptExt &CScriptExt::PayToScriptHash(const CScriptID &scriptID) const
+{
+    ((CScript *)this)->clear();
+    *((CScript *)this) << OP_HASH160;
+    *((CScript *)this) << ToByteVector(scriptID);
+    *((CScript *)this) << OP_EQUAL;
+    return *this;
+}
+
+// P2SH script, adds to whatever is already in the script (for example CLTV)
+const CScriptExt &CScriptExt::AddCheckLockTimeVerify(int64_t unlocktime) const
+{
+    if (unlocktime > 0)
+    {
+        *((CScript *)this) << CScriptNum::serialize(unlocktime);
+        *((CScript *)this) << OP_CHECKLOCKTIMEVERIFY;
+        *((CScript *)this) << OP_DROP;
+        return *this;
+    }
+}
+
+// combined CLTV script and P2PKH
+const CScriptExt &CScriptExt::TimeLockSpend(const CKeyID &key, int64_t unlocktime) const
+{
+    ((CScript *)this)->clear();
+    this->AddCheckLockTimeVerify(unlocktime);
+    this->AddPayToPubKeyHash(key);
+    return *this;
+}
+
+// if the front of the script has check lock time verify. this is a fairly simple check.
+// accepts NULL as parameter if unlockTime is not needed.
+bool CScriptExt::IsCheckLockTimeVerify(int64_t *unlockTime) const
+{
+    opcodetype op;
+    std::vector<unsigned char> unlockTimeParam = std::vector<unsigned char>();
+    CScript::const_iterator it = this->begin();
+
+    if (this->GetOp2(it, op, &unlockTimeParam))
+    {
+        if (unlockTimeParam.size() >= 0 && unlockTimeParam.size() < 6 &&
+            *(this->data() + unlockTimeParam.size() + 1) == OP_CHECKLOCKTIMEVERIFY)
+        {
+            int i = unlockTimeParam.size() - 1;
+            for (*unlockTime = 0; i >= 0; i--)
+            {
+                *unlockTime <<= 8;
+                *unlockTime |= *((unsigned char *)unlockTimeParam.data() + i);
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+bool CScriptExt::IsCheckLockTimeVerify() const
+{
+    int64_t ult;
+    return this->IsCheckLockTimeVerify(&ult);
+}
+
diff --git a/src/script/script_ext.h b/src/script/script_ext.h
new file mode 100644 (file)
index 0000000..ece0cf5
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2018 The Verus developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_SCRIPT_SCRIPT_EXT_H
+#define BITCOIN_SCRIPT_SCRIPT_EXT_H
+
+#include "script.h"
+#include "standard.h"
+#include "pubkey.h"
+
+#define OPRETTYPE_TIMELOCK 1
+
+class CScriptExt : public CScript
+{
+    public:
+        CScriptExt() { }
+        CScriptExt(const CScript& b) : CScript(b.begin(), b.end()) { }
+        CScriptExt(const_iterator pbegin, const_iterator pend) : CScript(pbegin, pend) { }
+        CScriptExt(const unsigned char* pbegin, const unsigned char* pend) : CScript(pbegin, pend) { }
+
+        // overload to return the hash of the referenced script
+        bool IsPayToScriptHash(CScriptID *scriptID) const;
+
+        // P2PKH script, adds to whatever is already in the script (for example CLTV)
+        const CScriptExt &AddPayToPubKeyHash(const CKeyID &key) const;
+
+        // push data into an op_return script with an opret type indicator, fails if the op_return is too large
+        const CScriptExt &OpReturnScript(const std::vector<unsigned char> &data, unsigned char opretType) const;
+
+        // P2SH script
+        const CScriptExt &PayToScriptHash(const CScriptID &scriptID) const;
+
+        // P2SH script, adds to whatever is already in the script (for example CLTV)
+        const CScriptExt &AddCheckLockTimeVerify(int64_t unlocktime) const;
+
+        // combined CLTV script and P2PKH
+        const CScriptExt &TimeLockSpend(const CKeyID &key, int64_t unlocktime) const;
+
+        // if the front of the script has check lock time verify. this is a fairly simple check.
+        // accepts NULL as parameter if unlockTime is not needed.
+        bool IsCheckLockTimeVerify(int64_t *unlockTime) const;
+
+        bool IsCheckLockTimeVerify() const;
+};
+
+#endif
+
index c9d831a18578fac4e06b00208a7c39c4f260912e..0da31dd102c9a4bfd6a51f99f51422465788a779 100644 (file)
@@ -18,6 +18,8 @@
 #include "komodo_defs.h"
 
 #include <stdarg.h>
+#include <sstream>
+#include <vector>
 
 #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
 #include <pthread.h>
@@ -362,6 +364,40 @@ void ParseParameters(int argc, const char* const argv[])
     }
 }
 
+void Split(const std::string& strVal, uint64_t *outVals, const uint64_t nDefault)
+{
+    stringstream ss(strVal);
+    vector<uint64_t> vec;
+
+    uint64_t i, nLast, numVals = 0;
+
+    while ( ss.peek() == ' ' )
+        ss.ignore();
+
+    while ( ss >> i )
+    {
+        outVals[numVals] = i;
+        numVals += 1;
+
+        while ( ss.peek() == ' ' )
+            ss.ignore();
+        if ( ss.peek() == ',' )
+            ss.ignore();
+        while ( ss.peek() == ' ' )
+            ss.ignore();
+    }
+
+    if ( numVals > 0 )
+        nLast = outVals[numVals - 1];
+    else
+        nLast = nDefault;
+
+    for ( i = numVals; i < ASSETCHAINS_MAX_ERAS; i++ )
+    {
+        outVals[i] = nLast;
+    }
+}
+
 std::string GetArg(const std::string& strArg, const std::string& strDefault)
 {
     if (mapArgs.count(strArg))
@@ -933,8 +969,9 @@ std::string LicenseInfo()
     return "\n" +
            FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" +
            FormatParagraph(strprintf(_("Copyright (C) 2015-%i The Zcash Developers"), COPYRIGHT_YEAR)) + "\n" +
-        FormatParagraph(strprintf(_("Copyright (C) 2015-%i jl777 and SuperNET developers"), COPYRIGHT_YEAR)) + "\n" +
-        "\n" +
+           FormatParagraph(strprintf(_("Copyright (C) 2015-%i jl777 and SuperNET developers"), COPYRIGHT_YEAR)) + "\n" +
+           FormatParagraph(strprintf(_("Copyright (C) 2018-%i The Verus developers"), COPYRIGHT_YEAR)) + "\n" +
+           "\n" +
            FormatParagraph(_("This is experimental software.")) + "\n" +
            "\n" +
            FormatParagraph(_("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.")) + "\n" +
index a9f5ba1f897c07ce217fbc70b2a4f1f37d801d30..14ba4a3b34ce4b57265b19336750260cd8a01c53 100644 (file)
@@ -157,6 +157,17 @@ inline bool IsSwitchChar(char c)
 #endif
 }
 
+/**
+ * Return string argument or default value
+ *
+ * @param strVal string to split
+ * @param outVals array of numbers from string or default
+ *      if the string is null, nDefault is used for all array entries
+ *      else if the string has fewer than _MAX_ERAS entries, then the last 
+ *      entry fills remaining entries
+ */
+void Split(const std::string& strVal, uint64_t *outVals, uint64_t nDefault);
+
 /**
  * Return string argument or default value
  *
diff --git a/src/wallet-utility b/src/wallet-utility
new file mode 100644 (file)
index 0000000..85ec51e
Binary files /dev/null and b/src/wallet-utility differ
index 42875d8680cc7ad94b4c14e002a020a1c0de87f1..9e326ea78837b3b44cd24ca7eff3f6495d595e50 100644 (file)
@@ -16,6 +16,9 @@ uint16_t BITCOIND_RPCPORT = 7771;
 uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
 uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC;
 uint32_t ASSETCHAINS_MAGIC = 2387029918;
+uint32_t ASSETCHAINS_EQUIHASH = 0;
+uint32_t ASSETCHAINS_ALGO = 0;
+
 unsigned int MAX_BLOCK_SIGOPS = 20000;
 
 void show_help()
index 77a27c69a68b6555ecf47392464e729096052fe0..60b99682110ecb3f4db313270bf0256dec52b195 100644 (file)
@@ -1206,7 +1206,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
         bool fExisted = mapWallet.count(tx.GetHash()) != 0;
         if (fExisted && !fUpdate) return false;
         auto noteData = FindMyNotes(tx);
-        if (fExisted || IsMine(tx) || IsFromMe(tx) || noteData.size() > 0)
+        if (fExisted || IsMineOrWatch(tx) || IsFromMe(tx) || noteData.size() > 0)
         {
             CWalletTx wtx(this,tx);
 
@@ -1458,14 +1458,162 @@ CAmount CWallet::GetChange(const CTxOut& txout) const
     return (IsChange(txout) ? txout.nValue : 0);
 }
 
-bool CWallet::IsMine(const CTransaction& tx) const
+bool CWallet::IsMine(const CTransaction& tx)
 {
-    BOOST_FOREACH(const CTxOut& txout, tx.vout)
-        if (IsMine(txout))
+    for (int i = 0; i < tx.vout.size(); i++)
+    {
+        if (IsMine(tx, i) == ISMINE_SPENDABLE)
+            return true;
+    }
+    return false;
+}
+
+bool CWallet::IsMineOrWatch(const CTransaction& tx)
+{
+    for (int i = 0; i < tx.vout.size(); i++)
+    {
+        if (IsMine(tx, i) & ISMINE_ALL)
             return true;
+    }
     return false;
 }
 
+// special case handling for CLTV scripts, this does not error check to ensure the script is CLTV and is
+// only internal to the wallet for that reason. if it is the first time we see this script, we add it to the wallet.
+isminetype CWallet::IsCLTVMine(CScriptExt &script, CScriptID &scriptID, int64_t locktime)
+{
+    uint8_t pushOp = script.data()[0];
+    uint32_t scriptStart = pushOp + 3;
+
+    // check post CLTV script
+    CScriptExt postfix = CScriptExt(script.size() > scriptStart ? script.begin() + scriptStart : script.end(), script.end());
+
+    // check again with postfix subscript
+    isminetype ret = ::IsMine(*this, postfix);
+    if (ret == ISMINE_SPENDABLE)
+    {
+        // once we get here, we should have this script in our
+        // wallet, either as watch only if still time locked, or spendable
+        CBlockIndex &tip = *(chainActive.Tip());
+        if (!(locktime < LOCKTIME_THRESHOLD ? tip.nHeight >= locktime : tip.GetBlockTime() >= locktime))
+        {
+            ret = ISMINE_WATCH_ONLY;
+            if (!this->HaveWatchOnly(script))
+            {
+                this->AddWatchOnly(script);
+            }
+        } else
+        {
+            if (this->HaveWatchOnly(script))
+                this->RemoveWatchOnly(script);
+            if (!this->HaveCScript(scriptID))
+                this->AddCScript(script);
+        }
+    }
+    return ret;
+}
+
+typedef vector<unsigned char> valtype;
+unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore);
+
+// special case handling for non-standard/Verus OP_RETURN script outputs, which need the transaction
+// to determine ownership
+isminetype CWallet::IsMine(const CTransaction& tx, uint32_t voutNum)
+{
+    vector<valtype> vSolutions;
+    txnouttype whichType;
+    const CScriptExt scriptPubKey = CScriptExt(tx.vout[voutNum].scriptPubKey);
+
+    if (!Solver(scriptPubKey, whichType, vSolutions)) {
+        if (this->HaveWatchOnly(scriptPubKey))
+            return ISMINE_WATCH_ONLY;
+        return ISMINE_NO;
+    }
+
+    CKeyID keyID;
+    CScriptID scriptID;
+    CScriptExt subscript;
+    int voutNext = voutNum + 1;
+
+    switch (whichType)
+    {
+        case TX_NONSTANDARD:
+        case TX_NULL_DATA:
+            break;
+
+        case TX_PUBKEY:
+            keyID = CPubKey(vSolutions[0]).GetID();
+            if (this->HaveKey(keyID))
+                return ISMINE_SPENDABLE;
+            break;
+
+        case TX_PUBKEYHASH:
+            keyID = CKeyID(uint160(vSolutions[0]));
+            if (this->HaveKey(keyID))
+                return ISMINE_SPENDABLE;
+            break;
+
+        case TX_SCRIPTHASH:
+            scriptID = CScriptID(uint160(vSolutions[0]));
+            if (this->GetCScript(scriptID, subscript)) 
+            {
+                // if this is a CLTV, handle it differently
+                int64_t lockTime;
+                if (subscript.IsCheckLockTimeVerify(&lockTime))
+                {
+                    return this->IsCLTVMine(subscript, scriptID, lockTime);
+                }
+                else
+                {
+                    isminetype ret = ::IsMine(*this, subscript);
+                    if (ret == ISMINE_SPENDABLE)
+                        return ret;
+                }
+            }
+            else if (tx.vout.size() > (voutNext = voutNum + 1) &&
+                tx.vout[voutNext].scriptPubKey.size() > 7 &&
+                tx.vout[voutNext].scriptPubKey.data()[0] == OP_RETURN)
+            {
+                // get the opret script from next vout, verify that the front is CLTV and hash matches
+                // if so, remove it and use the solver
+                opcodetype op;
+                std::vector<uint8_t> opretData;
+                CScript::const_iterator it = tx.vout[voutNext].scriptPubKey.begin() + 1;
+                if (tx.vout[voutNext].scriptPubKey.GetOp2(it, op, &opretData))
+                {
+                    if (opretData.size() > 0 && opretData.data()[0] == OPRETTYPE_TIMELOCK)
+                    {
+                        int64_t unlocktime;
+                        CScriptExt opretScript = CScriptExt(opretData.begin() + 1, opretData.end());
+
+                        if (CScriptID(opretScript) == scriptID &&
+                            opretScript.IsCheckLockTimeVerify(&unlocktime))
+                        {
+                            return this->IsCLTVMine(opretScript, scriptID, unlocktime);
+                        }
+                    }
+                }
+            }
+            break;
+
+        case TX_MULTISIG:
+            // Only consider transactions "mine" if we own ALL the
+            // keys involved. Multi-signature transactions that are
+            // partially owned (somebody else has a key that can spend
+            // them) enable spend-out-from-under-you attacks, especially
+            // in shared-wallet situations.
+            vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
+            if (HaveKeys(keys, *this) == keys.size())
+                return ISMINE_SPENDABLE;
+            break;
+    }
+
+    if (this->HaveWatchOnly(scriptPubKey))
+        return ISMINE_WATCH_ONLY;
+
+    return ISMINE_NO;
+}
+
 bool CWallet::IsFromMe(const CTransaction& tx) const
 {
     if (GetDebit(tx, ISMINE_ALL) > 0) {
index f77a55a047e8a997ca16516e6fcb6028a815a7d3..bacdd0308d12ccf6bf2e6c4002672bef4823a3d0 100644 (file)
@@ -762,6 +762,7 @@ protected:
 private:
     template <class T>
     void SyncMetaData(std::pair<typename TxSpendMap<T>::iterator, typename TxSpendMap<T>::iterator>);
+    isminetype IsCLTVMine(CScriptExt &script, CScriptID &scriptID, int64_t locktime);
 
 protected:
     bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx);
@@ -1050,10 +1051,12 @@ public:
     isminetype IsMine(const CTxIn& txin) const;
     CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
     isminetype IsMine(const CTxOut& txout) const;
+    isminetype IsMine(const CTransaction& tx, uint32_t voutNum);
     CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
     bool IsChange(const CTxOut& txout) const;
     CAmount GetChange(const CTxOut& txout) const;
-    bool IsMine(const CTransaction& tx) const;
+    bool IsMine(const CTransaction& tx);
+    bool IsMineOrWatch(const CTransaction& tx);
     /** should probably be renamed to IsRelevantToMe */
     bool IsFromMe(const CTransaction& tx) const;
     CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
This page took 0.249993 seconds and 4 git commands to generate.