Algo change update. Implemented - 192/7 Param Change, LWMA-1 Diff Adjustment, Configurable Block Maturity, Updated version

This commit is contained in:
Glitch 2019-10-12 00:13:03 +02:00
parent f247a95b40
commit 2a7543f90b
27 changed files with 769 additions and 476 deletions

View File

@ -1,7 +1,7 @@
Bitcoin Private
----------------
**Bitcoin Private v1.0.14**
**Bitcoin Private v1.0.15**
P2P Port: 7933

View File

@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1)
define(_CLIENT_VERSION_MINOR, 0)
define(_CLIENT_VERSION_REVISION, 14)
define(_CLIENT_VERSION_REVISION, 15)
define(_CLIENT_VERSION_BUILD, 50)
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))

View File

@ -1,5 +1,5 @@
---
name: "BTCP-1.0.14"
name: "BTCP-1.0.15"
enable_cache: true
distro: "debian"
suites:

View File

@ -37,6 +37,8 @@ public:
CMainParams() {
strNetworkID = "main";
strCurrencyUnits = "BTCP";
consensus.coinbaseMaturity = 100;
consensus.fCoinbaseMustBeProtected = true;
consensus.nSubsidySlowStartInterval = 2;
consensus.nSubsidyHalvingInterval = 840000;
@ -51,7 +53,6 @@ public:
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.nPowDifficultyBombHeight = 600000;
consensus.nHeightDiffBombRemoved = 599999;
@ -154,8 +155,20 @@ public:
// total number of tx / (checkpoint block height / (24 * 24))
};
// ZCL + BTC -> BTCP
nForkStartHeight = 272991;
nForkHeightRange = 5467;
// Equihash 192,7
nEquihashParamsUpdate = 615500;
nEquihashNnew = 192;
nEquihashKnew = 7;
// LWMA-1
lwmaActivationHeight = 615518;
lwmaAveragingWindow = 120;
}
};
static CMainParams mainParams;
@ -168,13 +181,19 @@ public:
CTestNetParams() {
strNetworkID = "test";
strCurrencyUnits = "BTCPT";
consensus.coinbaseMaturity = 10;
consensus.fCoinbaseMustBeProtected = true;
consensus.nMajorityEnforceBlockUpgrade = 51;
consensus.nMajorityRejectBlockOutdated = 75;
consensus.nMajorityWindow = 400;
consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.powLimit = uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.prePowLimit = consensus.powLimit;
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
consensus.nPowAveragingWindow = 17;
//assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
consensus.nPowMaxAdjustDown = 32; // 32% adjustment down
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
@ -184,8 +203,8 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
consensus.nPowDifficultyBombHeight = 600000;
consensus.nHeightDiffBombRemoved = 599999;
consensus.nPowDifficultyBombHeight = 102;
consensus.nHeightDiffBombRemoved = 101;
consensus.nUnmovedBurnHeight = 480000;
consensus.zResetHeight = 455500;
@ -200,17 +219,15 @@ public:
nPruneAfterHeight = 1000;
//! Modify the testnet genesis block so the timestamp is valid for a later start.
genesis.nTime = 1479443947;
genesis.nTime = 1527600786;
genesis.nBits = 0x2007ffff;
genesis.nNonce = uint256S("0x0000000000000000000000000000000000000000000000000000000000000013");
genesis.nSolution = ParseHex("002b24e10a5d2ab32b053a20ca6ebed779be1d935b1500eeea5c87aec684c6f934196fdfca6539de0cf1141544bffc5c0d1d4bab815fb5d8c2b195ccdf0755599ee492b9d98e3b79a178949f45485ad80dba38ec0461102adaa369b757ebb2bf8d75b5f67a341d666406d862a102c69800f20a7075be360a7eb2d315d78e4ce32c741f3baf7bf3e1e651976f734f367b1f126f62503b34d06d6e99b3659b2a47f5cfcf71c87e24e5023151d4af87454e7638a19b846350dd5fbc53e4ce1cce2597992b36cbcae0c24717e412c8df9ddca3e90c7629bd8c157c66d8906486943cf78e24d55dd4152f45eff49acf9fb9fddef81f2ee55892b38db940c404eaacf819588b83f0f761f1ba5b31a0ea1f8f4c5210638bbb59a2d8ddff9535f546b42a7eac5f3ee87616a075bddc3118b7f2c041f4b1e8dbcd11eea95835403066b5bb50cd23122dcb12166d75aafcfc1ca8f30580b4d48a5aa305657a06b4b650ed4633f2fa496235082feff65f70e19871f41b70632b53e57ddf38c207d631e5a56fa50bb71150f99427f73d82a439a5f70dfc7d8bbfc39d330ca7924527a5deb8950b9fa7020cfde5e07b84546e96764519ef6dd3fdc3a974abd342bdc7e4ee76bc11d5519541015afba1a0517fd347196aa326b0905a5916b83515c16f8f13105479c29f1eff3bc024ddbb07dcc672247cedc0d4ba32332ead0f13c58f50170642e16e076c34f5e75e3e8f5ac7f5238d67564fd385efecf972b0abf939a99bc7ef8f3a21cac21d2168706bbad3f4af66bb01cf61cfbc352a23797b62dcb5480bf2b7b277af233f5ce42a144d47119a89e1d114fa0bec2f13475b6b1df907bc3a429f1771afa3857bf16bfca3f76a5df14da62dc157fff4225bda73c3cfefa989edc24673bf932a024593da4c38b1a4628dd77ad919f4f7b7fb76976e696db69c89016ab30d9aa2d509f78d913d00ca9ac881aa759fc019b8c5e3eac6fddb4e0f044595e10d4997e29c79800f77cf1d97583d534db0f2726cba3739e7371eeffa2aca12b0d290ac45f44973f32f7675a5b49c94c4b608da2926555d16b7eb3670e12345a63f88797e5a5e21252c2c9463d7896001031a81bac0354336b35c5a10c93d9ae3054f6f6e4492f7c1f09a9d75034d5d0b220a9bb231e583659d5b6923a4e879326194de5c9805a02cb648508a8f9b6cd26dc17d322a478c1c599e1ec3adf2da6ce7a7e3a073b55cf30cf6b124f7700409abe14af8c60ab178579623916f165dbfd26f37056bf33c34f3af30939e1277376e4c5cba339f36381a05ef6481db033fb4c07a19e8655f8b12f9ab3c602e127b4ab1ee48e1c6a91382b54ed36ef9bb21b3bfa80a9107864dcb594dcad250e402b312607e648639631a3d1aeb17cfe3370202720ca8a46db15af92e8b46062b5bd035b24c35a592e5620d632faf1bf19a86df179fe52dd4cdbecd3cb7a336ca7489e4d1dc9433f1163c89d88c5eac36fc562496dc7583fe67c559c9a71cf89e9a0a59d5a14764926852d44a88d2ddb361d612ec06f9de874473eaf1d36b3a41911ac072b7826e6acea3d8425dc271833dba2ec17d1a270e49becbf21330ba2f0edc4b05f4df01623f3c82246ae23ea2c022434ef09611aa19ba35c3ecbad965af3ad9bc6c9b0d3b059c239ffbf9272d0150c151b4510d659cbd0e4a9c32945c612681b70ee4dcbeefeacde630b127115fd9af16cef4afefe611c9dfcc63e6833bf4dab79a7e1ae3f70321429557ab9da48bf93647830b5eb5780f23476d3d4d06a39ae532da5b2f30f151587eb5df19ec1acf099e1ac506e071eb52c3c3cc88ccf6622b2913acf07f1b772b5012e39173211e51773f3eb42d667fff1d902c5c87bd507837b3fd993e70ac9706a0");
genesis.nNonce = uint256S("0000000000000000000000000000000000000000000000000000000000000006");
genesis.nSolution = ParseHex("00596d6b34675ec5b6cde00c8c6149cd57b1159aa7401864f4812f83c5ef10f6a41645890dab4bfb97bf208c5eea90106c62e2d353f4844f1a2587a4da14e327f54e910c9eaf27057d8541cdd0cc6e8281b9a9830492b85e2c49c6c34228f140b157417d7a1e6e489c0ad515a96c50466bd6b184b631c9ae162b86d2c02b1f6e2cdc0727daabb07dc2d7fb3bce35d16699984a50a69f736196077b4c65e60b25e2f81efcc83f20db0130237474c79359126d218fc3a0d97109dbbb72733a67421964202fbb907e53d0256e70e9021e086ba802609b07f52ff0cba0f840acedcd5b0e4a9b78988102a743a4a4662aefb5e8c93a5f72d9273ff5ffd98602ed491eb812930bfdc5305eca05f7d55a91d30aa50f0ea6a4ef03efc2e4904825ff6fd08e1d73dee68031a147a745dbe26be0bf9425c757a78d27ff365d8b711a879bcf2b010deb6f19310270bd6b1ef31d27ab0183d0c712ce07f77fc475897f6a3f89c68bdea23a2a1844e0ed732c0ff1ea033ec235d4dd6a3176019202ccc418e7d4103ab8c35509733d88eab8bd7b81621910ee0d4f6c0a5d6fcc55c679de391a46ee33c7e70264ec677c4605bcfb75928e99c8392110a72cd5350c93fd68f5556e78f764815656706dc9517e4f73b216eb6c0c7048dce0724482678b501339b0b3171ead3e63d7abaa6fc1b7ecb564e16fd1c3426bd27de21203e5f49b13470342a676d11317c92add495dae964b31484265498f677dccc7a33986c17635b6c55929320fee4635aa8c2637cfa693dc723bcb37ad57bfbf1434e9ac7db0d5fb5be71314ac2cb21d5f61db1ff12703f889031396ed8d75a3a95dd86415dfd263ff1131091f07bfa9ca1aea9e46b84be070abeab0fb7d333f05b5509e74ed6bb58b8e624087d71710cb651f6a9a13ddc217354ba8219e08c4e48536e7e1c065d9da950096a655dce913878ec4e53093cf5701578f2bde402d94eb2e639f55bf07efd3cdeca23a29b38fd19e121f347bf1a05578ff4d24635d4bb702691838f2cca42bda0768e59727f94648d49cdda8de424a0398f3650d47155dac50da21dad9820feac063a99a33174462296cc7375735cfd9c7c1d484c938e299c7dc3ee288143131bbab60af230d4a4187d1ebfafa2c91f29a66392509fafea3042b97c965982140eb2219773469030159a0986f1a157fb64a25aaf9c0688973e79b45dc042e52c25ea5009d90c805f04572074335c2be9547159dbc1e15859eee935165f2b7c5b3dd89acbfd3c744d56b34afe18a734ee81894a168330ec99898e2ad042a036cccd1a36ece9c724cf476d404a65c4d8b1e2cbbe52c905b12abb5db83be05efe15723001c7a031e7e65230e2e4e4590df79e816e12fc684f51b04dc56e9d7c27da9a2cd9ead17ac1e58ae6798651f2cd80369547a0bd24f43fec3613784c0cc17bef71e4af22a2384a6728cc7fec4982c568671f12f63b0dbed8d11c0f5edcbc851991334b12da00d9cb5334f18a4f71915713cde326b93c31bd5d9c1501eb22d99b4650e087676d72ecd09dd45586561a050628365937fafa52b158cf81adce6e3cdee46e9626c85f28e0f59397f435e529ac4965d30d0afb9812d72407ec5239cfb3d56d8b6077866befb41f427c7dd7ee782c34e3d983d047edb71e48befcf582262bec7670298c66e690d5112760944486fdac7be99296e047be9369f7e555f5b06587123f541f6451cfd71e57f71173c87b51c08e80b2397f8c69dc3c7528576551ccfc6f2c7501f4df00a331855ee03e9f4ed9f021626ee3d6e36793b650336e5054904ebffedf83e367082381aee40c43422d81c0f0e4a00478673864dc31086ecb661e9dafac47e3b8697f4f52aeeefaccda3fd42f6e4194ab5186b7e");
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x03e1c4bb705c871bf9bfda3e74b7f8f86bff267993c215a89d5795e3708e5e1f"));
assert(consensus.hashGenesisBlock == uint256S("0x05098b06c3be62b6b7ebcb2ffee3dad6989c4b613cb0be3e09f8df0e4ec65d2e"));
vFixedSeeds.clear();
vSeeds.clear();
vSeeds.push_back(CDNSSeedData("btcprivate.org", "dnsseed.testnet.btcprivate.org"));
vSeeds.push_back(CDNSSeedData("btcprivate.co", "dnsseed.testnet1.btcprivate.co"));
// guarantees the first 2 characters, when base58 encoded, are "n1"
base58Prefixes[PUBKEY_ADDRESS] = {0x19,0x57};
@ -228,7 +245,7 @@ public:
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
fMiningRequiresPeers = true;
fMiningRequiresPeers = false;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
@ -242,8 +259,19 @@ public:
0
};
// ZCL + BTC -> BTCP
nForkStartHeight = 10;
nForkHeightRange = 300;
nForkHeightRange = 0;
// Equihash 192,7
nEquihashParamsUpdate = 30;
nEquihashNnew = 192;
nEquihashKnew = 7;
// LWMA-1
lwmaActivationHeight = 48;
lwmaAveragingWindow = 120;
}
};
static CTestNetParams testNetParams;
@ -256,6 +284,8 @@ public:
CRegTestParams() {
strNetworkID = "regtest";
strCurrencyUnits = "REG";
consensus.coinbaseMaturity = 10;
consensus.fCoinbaseMustBeProtected = false;
consensus.nSubsidySlowStartInterval = 0;
consensus.nSubsidyHalvingInterval = 840000;
@ -274,8 +304,8 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;
consensus.nPowDifficultyBombHeight = 600000;
consensus.nHeightDiffBombRemoved = 599999;
consensus.nPowDifficultyBombHeight = 152;
consensus.nHeightDiffBombRemoved = 151;
consensus.nUnmovedBurnHeight = 480000;
consensus.zResetHeight = 455500;
@ -315,8 +345,20 @@ public:
0
};
// ZCL + BTC -> BTCP
nForkStartHeight = 50;
nForkHeightRange = 0;
// Equihash 192,7
nEquihashParamsUpdate = 100;
nEquihashNnew = 192;
nEquihashKnew = 7;
// LWMA-1
lwmaActivationHeight = 168;
lwmaAveragingWindow = 120;
}
};
static CRegTestParams regTestParams;

View File

@ -9,6 +9,7 @@
#include "chainparamsbase.h"
#include "checkpoints.h"
#include "consensus/params.h"
#include "crypto/equihash.h"
#include "primitives/block.h"
#include "protocol.h"
@ -62,8 +63,28 @@ public:
bool RequireStandard() const { return fRequireStandard; }
int64_t MaxTipAge() const { return nMaxTipAge; }
int64_t PruneAfterHeight() const { return nPruneAfterHeight; }
unsigned int EquihashN() const { return nEquihashN; }
unsigned int EquihashK() const { return nEquihashK; }
unsigned int EquihashN(int height) const
{
if(height >= nEquihashParamsUpdate)
return nEquihashNnew;
return nEquihashN;
}
unsigned int EquihashK(int height) const
{
if(height >= nEquihashParamsUpdate)
return nEquihashKnew;
return nEquihashK;
}
unsigned int EquihashSolutionWidth(int height) const
{
return EhSolutionWidth(EquihashN(height), EquihashK(height));
}
std::string CurrencyUnits() const { return strCurrencyUnits; }
/** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
@ -81,6 +102,10 @@ public:
uint64_t ForkStartHeight() const { return nForkStartHeight; };
uint64_t ForkHeightRange() const { return nForkHeightRange; };
uint64_t EquihashParamsUpdate() const { return nEquihashParamsUpdate; };
uint64_t LwmaHeight() const { return lwmaActivationHeight; };
uint64_t LwmaAveragingWin() const { return lwmaAveragingWindow; };
protected:
CChainParams() {}
@ -109,6 +134,15 @@ protected:
uint64_t nForkStartHeight;
uint64_t nForkHeightRange;
uint64_t nEquihashParamsUpdate;
unsigned int nEquihashNnew;
unsigned int nEquihashKnew;
// LWMA-1
uint64_t lwmaActivationHeight;
int64_t lwmaAveragingWindow;
};
/**

View File

@ -19,7 +19,7 @@
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 1
#define CLIENT_VERSION_MINOR 0
#define CLIENT_VERSION_REVISION 14
#define CLIENT_VERSION_REVISION 15
#define CLIENT_VERSION_BUILD 50
//! Set to true for release, false for prerelease or test build

View File

@ -17,7 +17,7 @@ static const unsigned int MAX_BLOCK_SIGOPS = 50000;
/** The maximum size of a transaction (network rule) */
static const unsigned int MAX_TX_SIZE = 100000;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
/** (Moved to Consensus Params) */
/** Flags for LockTime() */
enum {

View File

@ -32,6 +32,8 @@ struct BIP9Deployment {
* Parameters that influence chain consensus.
*/
struct Params {
int coinbaseMaturity;
uint256 hashGenesisBlock;
bool fCoinbaseMustBeProtected;

View File

@ -35,7 +35,11 @@ int Equihash<N,K>::InitialiseState(eh_HashState& base_state)
uint32_t le_N = htole32(N);
uint32_t le_K = htole32(K);
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
memcpy(personalization, "ZcashPoW", 8);
if(N==192 && K==7)
memcpy(personalization, "BTCP_PoW", 8);
else
memcpy(personalization, "ZcashPoW", 8);
memcpy(personalization+8, &le_N, 4);
memcpy(personalization+12, &le_K, 4);
return crypto_generichash_blake2b_init_salt_personal(&base_state,
@ -792,6 +796,31 @@ template bool Equihash<200,9>::OptimisedSolve(const eh_HashState& base_state,
#endif
template bool Equihash<200,9>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
// Explicit instantiations for Equihash<192,7>
template int Equihash<192,7>::InitialiseState(eh_HashState& base_state);
#ifdef ENABLE_MINING
template bool Equihash<192,7>::BasicSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled);
template bool Equihash<192,7>::OptimisedSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled);
#endif
template bool Equihash<192,7>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
// Explicit instantiations for Equihash<144,5>
template int Equihash<144,5>::InitialiseState(eh_HashState& base_state);
#ifdef ENABLE_MINING
template bool Equihash<144,5>::BasicSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled);
template bool Equihash<144,5>::OptimisedSolve(const eh_HashState& base_state,
const std::function<bool(std::vector<unsigned char>)> validBlock,
const std::function<bool(EhSolverCancelCheck)> cancelled);
#endif
template bool Equihash<144,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
// Explicit instantiations for Equihash<96,5>
template int Equihash<96,5>::InitialiseState(eh_HashState& base_state);
#ifdef ENABLE_MINING

View File

@ -199,12 +199,19 @@ static Equihash<96,3> Eh96_3;
static Equihash<200,9> Eh200_9;
static Equihash<96,5> Eh96_5;
static Equihash<48,5> Eh48_5;
static Equihash<144,5> Eh144_5;
static Equihash<192,7> Eh192_7;
#define EhInitialiseState(n, k, base_state) \
if (n == 96 && k == 3) { \
Eh96_3.InitialiseState(base_state); \
} else if (n == 200 && k == 9) { \
Eh200_9.InitialiseState(base_state); \
} else if (n == 192 && k == 7) { \
Eh192_7.InitialiseState(base_state); \
} else if (n == 144 && k == 5) { \
Eh144_5.InitialiseState(base_state); \
} else if (n == 96 && k == 5) { \
Eh96_5.InitialiseState(base_state); \
} else if (n == 48 && k == 5) { \
@ -222,6 +229,10 @@ inline bool EhBasicSolve(unsigned int n, unsigned int k, const eh_HashState& bas
return Eh96_3.BasicSolve(base_state, validBlock, cancelled);
} else if (n == 200 && k == 9) {
return Eh200_9.BasicSolve(base_state, validBlock, cancelled);
} else if (n == 192 && k == 7) {
return Eh192_7.BasicSolve(base_state, validBlock, cancelled);
} else if (n == 144 && k == 5) {
return Eh144_5.BasicSolve(base_state, validBlock, cancelled);
} else if (n == 96 && k == 5) {
return Eh96_5.BasicSolve(base_state, validBlock, cancelled);
} else if (n == 48 && k == 5) {
@ -246,6 +257,10 @@ inline bool EhOptimisedSolve(unsigned int n, unsigned int k, const eh_HashState&
return Eh96_3.OptimisedSolve(base_state, validBlock, cancelled);
} else if (n == 200 && k == 9) {
return Eh200_9.OptimisedSolve(base_state, validBlock, cancelled);
} else if (n == 192 && k == 7) {
return Eh192_7.OptimisedSolve(base_state, validBlock, cancelled);
} else if (n == 144 && k == 5) {
return Eh144_5.OptimisedSolve(base_state, validBlock, cancelled);
} else if (n == 96 && k == 5) {
return Eh96_5.OptimisedSolve(base_state, validBlock, cancelled);
} else if (n == 48 && k == 5) {
@ -268,6 +283,10 @@ inline bool EhOptimisedSolveUncancellable(unsigned int n, unsigned int k, const
ret = Eh96_3.IsValidSolution(base_state, soln); \
} else if (n == 200 && k == 9) { \
ret = Eh200_9.IsValidSolution(base_state, soln); \
} else if (n == 192 && k == 7) { \
ret = Eh192_7.IsValidSolution(base_state, soln); \
} else if (n == 144 && k == 5) { \
ret = Eh144_5.IsValidSolution(base_state, soln); \
} else if (n == 96 && k == 5) { \
ret = Eh96_5.IsValidSolution(base_state, soln); \
} else if (n == 48 && k == 5) { \
@ -276,4 +295,26 @@ inline bool EhOptimisedSolveUncancellable(unsigned int n, unsigned int k, const
throw std::invalid_argument("Unsupported Equihash parameters"); \
}
inline unsigned int EhSolutionWidth(int n, int k)
{
unsigned int ret;
if (n == 96 && k == 3) {
ret = Eh96_3.SolutionWidth;
} else if (n == 200 && k == 9) {
ret = Eh200_9.SolutionWidth;
} else if (n == 192 && k == 7) {
ret = Eh192_7.SolutionWidth;
} else if (n == 144 && k == 5) {
ret = Eh144_5.SolutionWidth;
} else if (n == 96 && k == 5) {
ret = Eh96_5.SolutionWidth;
} else if (n == 48 && k == 5) {
ret = Eh48_5.SolutionWidth;
} else {
throw std::invalid_argument("Unsupported Equihash parameters");
}
return ret;
}
#endif // BITCOIN_EQUIHASH_H

View File

@ -1695,7 +1695,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
if (coins->IsCoinBase()) {
// Ensure that coinbases are matured
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) {
if (nSpendHeight - coins->nHeight < consensusParams.coinbaseMaturity) {
return state.Invalid(
error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
@ -3128,9 +3128,21 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
REJECT_INVALID, "version-too-low");
// Check Equihash solution is valid
if (fCheckPOW && !CheckEquihashSolution(&block, Params()))
return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),
REJECT_INVALID, "invalid-solution");
if (fCheckPOW) {
const CChainParams& chainparams = Params();
int oldSize = chainparams.EquihashSolutionWidth(chainparams.EquihashParamsUpdate() - 1);
int newSize = chainparams.EquihashSolutionWidth(chainparams.EquihashParamsUpdate());
if (block.nSolution.size() != oldSize && block.nSolution.size() != newSize)
return state.DoS(100, error("CheckBlockHeader(): Equihash solution has invalid size have %d need [%d, %d]",
block.nSolution.size(), oldSize, newSize),
REJECT_INVALID, "invalid-solution-size");
if (!CheckEquihashSolution(&block, chainparams))
return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),
REJECT_INVALID, "invalid-solution");
}
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus()))
@ -3138,6 +3150,7 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
REJECT_INVALID, "high-hash");
// Check timestamp
const CChainParams& chainparams = Params();
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),
REJECT_INVALID, "time-too-new");
@ -3220,7 +3233,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state,
return true;
}
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev, bool fCheckPow)
{
const CChainParams& chainParams = Params();
const Consensus::Params& consensusParams = chainParams.GetConsensus();
@ -3245,7 +3258,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
// Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, error("%s: incorrect proof of work", __func__),
return state.DoS(100, error("%s: incorrect proof of work (nHeight: %d, hash: %s)", __func__, nHeight, hash.ToString()),
REJECT_INVALID, "bad-diffbits");
// Check timestamp against prev
@ -3253,6 +3266,12 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return state.Invalid(error("%s: block's timestamp is too early", __func__),
REJECT_INVALID, "time-too-old");
// Check that equihash solution has the proper length
if (fCheckPow && block.nSolution.size() != chainParams.EquihashSolutionWidth(nHeight))
return state.Invalid(error("%s: incorrect equihash solution size have %d need %d",
__func__, block.nSolution.size(), chainParams.EquihashSolutionWidth(nHeight)),
REJECT_INVALID, "equihash-solution-size");
if (fCheckpointsEnabled)
{
// Don't accept any forks from the main chain prior to last checkpoint
@ -3567,7 +3586,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
auto verifier = libzcash::ProofVerifier::Disabled();
// NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
if (!ContextualCheckBlockHeader(block, state, pindexPrev, fCheckPOW))
return false;
if (!CheckBlock(block, state, verifier, fCheckPOW, fCheckMerkleRoot))

View File

@ -429,7 +429,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state,
bool fCheckPOW = true, bool fCheckMerkleRoot = true);
/** Context-dependent validity checks */
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev);
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev, bool fCheckPow = true);
bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev);
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
@ -587,7 +587,7 @@ std::string GetUTXOFileName(int nHeight);
//
inline bool isForkBlock(int nHeight)
{
return (nHeight > forkStartHeight && nHeight <= forkStartHeight + forkHeightRange);
return (forkHeightRange > 0 && nHeight > forkStartHeight && nHeight <= forkStartHeight + forkHeightRange);
}
inline bool looksLikeForkBlockHeader(const CBlockHeader& header)

View File

@ -298,7 +298,7 @@ int printMetrics(size_t cols, bool mining)
if ((height > 0) && (height <= consensusParams.GetLastFoundersRewardBlockHeight())) {
subsidy -= subsidy/5;
}
if (std::max(0, COINBASE_MATURITY - (tipHeight - height)) > 0) {
if (std::max(0, consensusParams.coinbaseMaturity - (tipHeight - height)) > 0) {
immature += subsidy;
} else {
mature += subsidy;

View File

@ -692,11 +692,17 @@ void static BitcoinMiner()
// Each thread has its own counter
unsigned int nExtraNonce = 0;
unsigned int n = chainparams.EquihashN();
unsigned int k = chainparams.EquihashK();
CBlockIndex* pindexPrev = chainActive.Tip();
unsigned int n = chainparams.EquihashN(pindexPrev->nHeight + 1);
unsigned int k = chainparams.EquihashK(pindexPrev->nHeight + 1);
std::string solver = GetArg("-equihashsolver", "default");
// TODO: parameterize n & k tromp solver and remove temporary workaround below
if (n == 200 && k == 9) solver = "default";
if (n == 192 && k == 7) solver = "tromp";
assert(solver == "tromp" || solver == "default");
LogPrint("pow", "Using Equihash solver \"%s\" with n = %u, k = %u\n", solver, n, k);
std::mutex m_cs;
@ -731,7 +737,7 @@ void static BitcoinMiner()
miningTimer.start();
}
CBlockIndex* pindexPrev = chainActive.Tip();
pindexPrev = chainActive.Tip();
CBlock *pblock = nullptr;
unsigned int nTransactionsUpdatedLast = 0;
@ -740,6 +746,9 @@ void static BitcoinMiner()
//
unique_ptr<CBlockTemplate> pblocktemplate;
n = chainparams.EquihashN(pindexPrev->nHeight + 1);
k = chainparams.EquihashK(pindexPrev->nHeight + 1);
bool isNextBlockFork = isForkBlock(pindexPrev->nHeight+1);
if (isNextBlockFork) {
@ -827,8 +836,8 @@ void static BitcoinMiner()
pblock->nNonce.size());
// (x_1, x_2, ...) = A(I, V, n, k)
LogPrint("pow", "Running Equihash solver \"%s\" with nNonce = %s\n",
solver, pblock->nNonce.ToString());
LogPrint("pow", "Running Equihash solver \"%s\" (%u,%u) with nNonce = %s\n",
solver,n, k, pblock->nNonce.ToString());
std::function<bool(std::vector<unsigned char>)> validBlock =
[&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams
@ -877,6 +886,13 @@ void static BitcoinMiner()
return cancelSolver;
};
// TODO: parameterize n & k tromp solver and remove temporary workaround below
if (n == 200 && k == 9) solver = "default";
if (n == 192 && k == 7) solver = "tromp";
assert(solver == "tromp" || solver == "default");
// TODO: factor this out into a function with the same API for each solver.
if (solver == "tromp") {
// Create solver and initialize it.

View File

@ -21,12 +21,30 @@
#include "librustzcash.h"
#endif // ENABLE_RUST
/**
* Manually increase difficulty by a multiplier. Note that because of the use of compact bits, this will
* only be an approx increase, not a 100% precise increase.
*/
unsigned int IncreaseDifficultyBy(unsigned int nBits, int64_t multiplier, const Consensus::Params& params) {
arith_uint256 target;
target.SetCompact(nBits);
target /= multiplier;
const arith_uint256 pow_limit = UintToArith256(params.powLimit);
if (target > pow_limit) {
target = pow_limit;
}
return target.GetCompact();
}
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
const CChainParams& chainparams = Params();
int nHeight = pindexLast->nHeight + 1;
arith_uint256 proofOfWorkLimit;
if(!isForkEnabled(nHeight))
if (!isForkEnabled(nHeight))
proofOfWorkLimit = UintToArith256(params.prePowLimit);
else
proofOfWorkLimit = UintToArith256(params.powLimit);
@ -37,14 +55,41 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
if (pindexLast == NULL)
return nProofOfWorkLimit;
// right at fork
else if(isForkBlock(nHeight) && !isForkBlock(nHeight - params.nPowAveragingWindow))
return nProofOfWorkLimit;
// For upgrade mainnet forks, we'll adjust the difficulty down for the first nPowAveragingWindow blocks
if (nHeight >= chainparams.EquihashParamsUpdate() &&
nHeight < chainparams.EquihashParamsUpdate() + params.nPowAveragingWindow) {
if (pblock && pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing * 12) {
// If > 30 mins, allow min difficulty
LogPrintf("HC Returning level 1 difficulty %i at height %i\n", nProofOfWorkLimit, nHeight);
return nProofOfWorkLimit;
} else if (pblock && pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing * 6) {
// If > 15 mins, allow low estimate difficulty
unsigned int difficulty = IncreaseDifficultyBy(nProofOfWorkLimit, 128, params);
LogPrintf("HC Returning level 2 difficulty %i at height %i\n", nProofOfWorkLimit, nHeight);
return difficulty;
} else if (pblock && pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing * 2) {
// If > 5 mins, allow high estimate difficulty
unsigned int difficulty = IncreaseDifficultyBy(nProofOfWorkLimit, 256, params);
LogPrintf("HC Returning level 3 difficulty %i at height %i\n", nProofOfWorkLimit, nHeight);
return difficulty;
} else {
// If < 5 mins, fall through, and return the normal difficulty.
LogPrintf("HC Falling through at height %i\n", nHeight);
}
}
// LWMA-1 activated
if (pindexLast->nHeight > chainparams.LwmaHeight())
return LwmaCalculateNextWorkRequired(pindexLast, params);
// right post fork
else if(!isForkBlock(nHeight) && isForkBlock(nHeight - params.nPowAveragingWindow))
if (!isForkBlock(nHeight) && isForkBlock(nHeight - params.nPowAveragingWindow))
return nProofOfWorkLimit;
// right at fork
if (isForkBlock(nHeight) && !isForkBlock(nHeight - params.nPowAveragingWindow))
return nProofOfWorkLimit;
// Find the first block in the averaging interval
const CBlockIndex* pindexFirst = pindexLast;
@ -66,6 +111,83 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params, proofOfWorkLimit, isFork);
}
// LWMA-1 for BTC/Zcash clones
// LWMA has the best response*stability. It rises slowly & drops fast when needed.
// Copyright (c) 2017-2018 The Bitcoin Gold developers
// Copyright (c) 2018-2019 Zawy
// Copyright (c) 2018 iamstenman (Microbitcoin)
// MIT License
// Algorithm by Zawy, a modification of WT-144 by Tom Harding
// For any changes, patches, updates, etc see
// https://github.com/zawy12/difficulty-algorithms/issues/3#issuecomment-442129791
// FTL should be lowered to about N*T/20.
// FTL in BTC clones is MAX_FUTURE_BLOCK_TIME in chain.h.
// FTL in Zcash & Dash clones need to change the 2*60*60 here:
// if (block.GetBlockTime() > nAdjustedTime + 2 * 60 * 60)
// which is around line 3700 in main.cpp in ZEC and validation.cpp in Dash
// If your coin uses network time instead of node local time, lowering FTL < about 125% of the
// "revert to node time" rule (70 minutes in BCH, ZEC, & BTC) allows 33% Sybil attack,
// so revert rule must be ~ FTL/2 instead of 70 minutes. See:
// https://github.com/zcash/zcash/issues/4021
unsigned int LwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params)
{
const CChainParams& chainparams = Params();
// For T=600, 300, 150 (ie 10, 5, 2.5min blocks) use approximately N=60, 90, 120
const int64_t T = params.nPowTargetSpacing;
const int64_t N = chainparams.LwmaAveragingWin();
// Define a k that will be used to get a proper average after weighting the solvetimes.
const int64_t k = N * (N + 1) * T / 2;
const int64_t height = pindexLast->nHeight;
const arith_uint256 powLimit = UintToArith256(params.powLimit);
// 'New' coins should just give away first N blocks before using this algorithm.
if (height > chainparams.LwmaHeight() && height <= chainparams.LwmaHeight() + N) { return powLimit.GetCompact(); }
arith_uint256 avgTarget, nextTarget;
int64_t thisTimestamp, previousTimestamp;
int64_t sumWeightedSolvetimes = 0, j = 0;
const CBlockIndex* blockPreviousTimestamp = pindexLast->GetAncestor(height - N);
previousTimestamp = blockPreviousTimestamp->GetBlockTime();
// Loop through N most recent blocks.
for (int64_t i = height - N + 1; i <= height; i++) {
const CBlockIndex* block = pindexLast->GetAncestor(i);
// Prevent solvetimes from being negative in a safe way. It must be done like this.
// In particular, do not attempt anything like if(solvetime < 0) {solvetime=0;}
// The +1 ensures new coins do not calculate nextTarget = 0.
thisTimestamp = (block->GetBlockTime() > previousTimestamp) ?
block->GetBlockTime() : previousTimestamp + 1;
// A 6*T limit will prevent large drops in difficulty from long solvetimes.
int64_t solvetime = std::min(6 * T, thisTimestamp - previousTimestamp);
// The following is part of "preventing negative solvetimes".
previousTimestamp = thisTimestamp;
// Give linearly higher weight to more recent solvetimes.
j++;
sumWeightedSolvetimes += solvetime * j;
arith_uint256 target;
target.SetCompact(block->nBits);
avgTarget += target / N / k; // Dividing by k here prevents an overflow below.
}
// Desired equation in next line was nextTarget = avgTarget * sumWeightSolvetimes / k
// but 1/k was moved to line above to prevent overflow in new coins
nextTarget = avgTarget * sumWeightedSolvetimes;
if (nextTarget > powLimit) { nextTarget = powLimit; }
return nextTarget.GetCompact();
}
// (Original)
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
int64_t nLastBlockTime, int64_t nFirstBlockTime,
const Consensus::Params& params, const arith_uint256 bnPowLimit, bool isFork)
@ -101,8 +223,20 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params)
{
unsigned int n = params.EquihashN();
unsigned int k = params.EquihashK();
uint64_t forkHeight = params.EquihashParamsUpdate();
unsigned int solution_size = pblock->nSolution.size();
unsigned int n;
unsigned int k;
if (solution_size == params.EquihashSolutionWidth(forkHeight)) {
n = params.EquihashN(forkHeight);
k = params.EquihashK(forkHeight);
} else if (forkHeight > 0 && solution_size == params.EquihashSolutionWidth(forkHeight - 1)) {
n = params.EquihashN(forkHeight - 1);
k = params.EquihashK(forkHeight - 1);
} else {
return error("CheckEquihashsolution(): invalid solution size");
}
// Hash state
crypto_generichash_blake2b_state state;

View File

@ -16,7 +16,10 @@ class CChainParams;
class uint256;
class arith_uint256;
unsigned int IncreaseDifficultyBy(unsigned int nBits, int64_t multiplier, const Consensus::Params& params);
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&);
unsigned int LwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
int64_t nLastBlockTime, int64_t nFirstBlockTime,
const Consensus::Params&, const arith_uint256, bool isFork = false);

View File

@ -17,11 +17,11 @@ typedef unsigned char uchar;
// algorithm parameters, prefixed with W to reduce include file conflicts
#ifndef WN
#define WN 200
#define WN 192
#endif
#ifndef WK
#define WK 9
#define WK 7
#endif
#define NDIGITS (WK+1)
@ -65,7 +65,7 @@ int verifyrec(const crypto_generichash_blake2b_state *ctx, u32 *indices, uchar *
return vrf1;
for (int i=0; i < WN/8; i++)
hash[i] = hash0[i] ^ hash1[i];
int i, b = r * DIGITBITS;
int i, b = r < WK ? r * DIGITBITS : WN;
for (i = 0; i < b/8; i++)
if (hash[i])
return POW_NONZERO_XOR;

View File

@ -35,7 +35,7 @@ typedef u32 au32;
#endif
#ifndef RESTBITS
#define RESTBITS 8
#define RESTBITS 4
#endif
// 2_log of number of buckets
@ -57,7 +57,6 @@ static const u32 NBUCKETS = 1<<BUCKBITS;
// 2_log of number of slots per bucket
static const u32 SLOTBITS = RESTBITS+1+1;
static const u32 SLOTRANGE = 1<<SLOTBITS;
static const u32 SLOTMSB = 1<<(SLOTBITS-1);
// number of slots per bucket
static const u32 NSLOTS = SLOTRANGE * SAVEMEM;
// number of per-xhash slots
@ -74,52 +73,31 @@ static const u32 MAXSOLS = 8;
// tree node identifying its children as two different slots in
// a bucket on previous layer with the same rest bits (x-tra hash)
struct tree {
u32 bid_s0_s1; // manual bitfields
u32 bid_s0_s1; // manual bitfields
tree(const u32 idx) {
bid_s0_s1 = idx;
}
tree(const u32 bid, const u32 s0, const u32 s1) {
#ifdef SLOTDIFF
u32 ds10 = (s1 - s0) & SLOTMASK;
if (ds10 & SLOTMSB) {
bid_s0_s1 = (((bid << SLOTBITS) | s1) << (SLOTBITS-1)) | (SLOTMASK & ~ds10);
} else {
bid_s0_s1 = (((bid << SLOTBITS) | s0) << (SLOTBITS-1)) | (ds10 - 1);
tree(const u32 idx) {
bid_s0_s1 = idx;
}
tree(const u32 bid, const u32 s0, const u32 s1) {
bid_s0_s1 = (((bid << SLOTBITS) | s0) << SLOTBITS) | s1;
}
u32 getindex() const {
return bid_s0_s1;
}
u32 bucketid() const {
return bid_s0_s1 >> (2 * SLOTBITS);
}
u32 slotid0() const {
return (bid_s0_s1 >> SLOTBITS) & SLOTMASK;
}
u32 slotid1() const {
return bid_s0_s1 & SLOTMASK;
}
#else
bid_s0_s1 = (((bid << SLOTBITS) | s0) << SLOTBITS) | s1;
#endif
}
u32 getindex() const {
return bid_s0_s1;
}
u32 bucketid() const {
#ifdef SLOTDIFF
return bid_s0_s1 >> (2 * SLOTBITS - 1);
#else
return bid_s0_s1 >> (2 * SLOTBITS);
#endif
}
u32 slotid0() const {
#ifdef SLOTDIFF
return (bid_s0_s1 >> (SLOTBITS-1)) & SLOTMASK;
#else
return (bid_s0_s1 >> SLOTBITS) & SLOTMASK;
#endif
}
u32 slotid1() const {
#ifdef SLOTDIFF
return (slotid0() + 1 + (bid_s0_s1 & (SLOTMASK>>1))) & SLOTMASK;
#else
return bid_s0_s1 & SLOTMASK;
#endif
}
};
union hashunit {
u32 word;
uchar bytes[sizeof(u32)];
u32 word;
uchar bytes[sizeof(u32)];
};
#define WORDS(bits) ((bits + 31) / 32)
@ -127,13 +105,13 @@ union hashunit {
#define HASHWORDS1 WORDS(WN - 2*DIGITBITS + RESTBITS)
struct slot0 {
tree attr;
hashunit hash[HASHWORDS0];
tree attr;
hashunit hash[HASHWORDS0];
};
struct slot1 {
tree attr;
hashunit hash[HASHWORDS1];
tree attr;
hashunit hash[HASHWORDS1];
};
// a bucket is NSLOTS treenodes
@ -146,25 +124,25 @@ typedef bucket1 digit1[NBUCKETS];
// size (in bytes) of hash in round 0 <= r < WK
u32 hashsize(const u32 r) {
const u32 hashbits = WN - (r+1) * DIGITBITS + RESTBITS;
return (hashbits + 7) / 8;
const u32 hashbits = WN - (r+1) * DIGITBITS + RESTBITS;
return (hashbits + 7) / 8;
}
u32 hashwords(u32 bytes) {
return (bytes + 3) / 4;
return (bytes + 3) / 4;
}
// manages hash and tree data
struct htalloc {
u32 *heap0;
u32 *heap1;
bucket0 *trees0[(WK+1)/2];
bucket1 *trees1[WK/2];
u32 alloced;
htalloc() {
alloced = 0;
}
void alloctrees() {
u32 *heap0;
u32 *heap1;
bucket0 *trees0[(WK+1)/2];
bucket1 *trees1[WK/2];
u32 alloced;
htalloc() {
alloced = 0;
}
void alloctrees() {
// optimize xenoncat's fixed memory layout, avoiding any waste
// digit trees hashes trees hashes
// 0 0 A A A A A A . . . . . .
@ -176,123 +154,123 @@ struct htalloc {
// 6 0 2 4 6 . G G 1 3 5 F F F
// 7 0 2 4 6 . G G 1 3 5 7 H H
// 8 0 2 4 6 8 . I 1 3 5 7 H H
assert(DIGITBITS >= 16); // ensures hashes shorten by 1 unit every 2 digits
heap0 = (u32 *)alloc(1, sizeof(digit0));
heap1 = (u32 *)alloc(1, sizeof(digit1));
for (int r=0; r<WK; r++)
if ((r&1) == 0)
trees0[r/2] = (bucket0 *)(heap0 + r/2);
else
trees1[r/2] = (bucket1 *)(heap1 + r/2);
}
void dealloctrees() {
free(heap0);
free(heap1);
}
void *alloc(const u32 n, const u32 sz) {
void *mem = calloc(n, sz);
assert(mem);
alloced += n * sz;
return mem;
}
assert(DIGITBITS >= 16); // ensures hashes shorten by 1 unit every 2 digits
heap0 = (u32 *)alloc(1, sizeof(digit0));
heap1 = (u32 *)alloc(1, sizeof(digit1));
for (int r=0; r<WK; r++)
if ((r&1) == 0)
trees0[r/2] = (bucket0 *)(heap0 + r/2);
else
trees1[r/2] = (bucket1 *)(heap1 + r/2);
}
void dealloctrees() {
free(heap0);
free(heap1);
}
void *alloc(const u32 n, const u32 sz) {
void *mem = calloc(n, sz);
assert(mem);
alloced += n * sz;
return mem;
}
};
typedef au32 bsizes[NBUCKETS];
u32 min(const u32 a, const u32 b) {
return a < b ? a : b;
return a < b ? a : b;
}
struct equi {
crypto_generichash_blake2b_state blake_ctx;
htalloc hta;
bsizes *nslots; // PUT IN BUCKET STRUCT
proof *sols;
au32 nsols;
u32 nthreads;
u32 xfull;
u32 hfull;
u32 bfull;
pthread_barrier_t barry;
equi(const u32 n_threads) {
assert(sizeof(hashunit) == 4);
nthreads = n_threads;
const int err = pthread_barrier_init(&barry, NULL, nthreads);
assert(!err);
hta.alloctrees();
nslots = (bsizes *)hta.alloc(2 * NBUCKETS, sizeof(au32));
sols = (proof *)hta.alloc(MAXSOLS, sizeof(proof));
}
~equi() {
hta.dealloctrees();
free(nslots);
free(sols);
}
void setstate(const crypto_generichash_blake2b_state *ctx) {
blake_ctx = *ctx;
memset(nslots, 0, NBUCKETS * sizeof(au32)); // only nslots[0] needs zeroing
nsols = 0;
}
u32 getslot(const u32 r, const u32 bucketi) {
#ifdef EQUIHASH_TROMP_ATOMIC
return std::atomic_fetch_add_explicit(&nslots[r&1][bucketi], 1U, std::memory_order_relaxed);
#else
return nslots[r&1][bucketi]++;
#endif
}
u32 getnslots(const u32 r, const u32 bid) { // SHOULD BE METHOD IN BUCKET STRUCT
au32 &nslot = nslots[r&1][bid];
const u32 n = min(nslot, NSLOTS);
nslot = 0;
return n;
}
void orderindices(u32 *indices, u32 size) {
if (indices[0] > indices[size]) {
for (u32 i=0; i < size; i++) {
const u32 tmp = indices[i];
indices[i] = indices[size+i];
indices[size+i] = tmp;
}
crypto_generichash_blake2b_state blake_ctx;
htalloc hta;
bsizes *nslots; // PUT IN BUCKET STRUCT
proof *sols;
au32 nsols;
u32 nthreads;
u32 xfull;
u32 hfull;
u32 bfull;
pthread_barrier_t barry;
equi(const u32 n_threads) {
assert(sizeof(hashunit) == 4);
nthreads = n_threads;
const int err = pthread_barrier_init(&barry, NULL, nthreads);
assert(!err);
hta.alloctrees();
nslots = (bsizes *)hta.alloc(2 * NBUCKETS, sizeof(au32));
sols = (proof *)hta.alloc(MAXSOLS, sizeof(proof));
}
}
void listindices0(u32 r, const tree t, u32 *indices) {
if (r == 0) {
*indices = t.getindex();
return;
~equi() {
hta.dealloctrees();
free(nslots);
free(sols);
}
const bucket1 &buck = hta.trees1[--r/2][t.bucketid()];
const u32 size = 1 << r;
u32 *indices1 = indices + size;
listindices1(r, buck[t.slotid0()].attr, indices);
listindices1(r, buck[t.slotid1()].attr, indices1);
orderindices(indices, size);
}
void listindices1(u32 r, const tree t, u32 *indices) {
const bucket0 &buck = hta.trees0[--r/2][t.bucketid()];
const u32 size = 1 << r;
u32 *indices1 = indices + size;
listindices0(r, buck[t.slotid0()].attr, indices);
listindices0(r, buck[t.slotid1()].attr, indices1);
orderindices(indices, size);
}
void candidate(const tree t) {
proof prf;
listindices1(WK, t, prf); // assume WK odd
qsort(prf, PROOFSIZE, sizeof(u32), &compu32);
for (u32 i=1; i<PROOFSIZE; i++)
if (prf[i] <= prf[i-1])
return;
void setstate(const crypto_generichash_blake2b_state *ctx) {
blake_ctx = *ctx;
memset(nslots, 0, NBUCKETS * sizeof(au32)); // only nslots[0] needs zeroing
nsols = 0;
}
u32 getslot(const u32 r, const u32 bucketi) {
#ifdef EQUIHASH_TROMP_ATOMIC
u32 soli = std::atomic_fetch_add_explicit(&nsols, 1U, std::memory_order_relaxed);
return std::atomic_fetch_add_explicit(&nslots[r&1][bucketi], 1U, std::memory_order_relaxed);
#else
u32 soli = nsols++;
return nslots[r&1][bucketi]++;
#endif
if (soli < MAXSOLS)
listindices1(WK, t, sols[soli]); // assume WK odd
}
void showbsizes(u32 r) {
}
u32 getnslots(const u32 r, const u32 bid) { // SHOULD BE METHOD IN BUCKET STRUCT
au32 &nslot = nslots[r&1][bid];
const u32 n = min(nslot, NSLOTS);
nslot = 0;
return n;
}
void orderindices(u32 *indices, u32 size) {
if (indices[0] > indices[size]) {
for (u32 i=0; i < size; i++) {
const u32 tmp = indices[i];
indices[i] = indices[size+i];
indices[size+i] = tmp;
}
}
}
void listindices0(u32 r, const tree t, u32 *indices) {
if (r == 0) {
*indices = t.getindex();
return;
}
const bucket1 &buck = hta.trees1[--r/2][t.bucketid()];
const u32 size = 1 << r;
u32 *indices1 = indices + size;
listindices1(r, buck[t.slotid0()].attr, indices);
listindices1(r, buck[t.slotid1()].attr, indices1);
orderindices(indices, size);
}
void listindices1(u32 r, const tree t, u32 *indices) {
const bucket0 &buck = hta.trees0[--r/2][t.bucketid()];
const u32 size = 1 << r;
u32 *indices1 = indices + size;
listindices0(r, buck[t.slotid0()].attr, indices);
listindices0(r, buck[t.slotid1()].attr, indices1);
orderindices(indices, size);
}
void candidate(const tree t) {
proof prf;
listindices1(WK, t, prf); // assume WK odd
qsort(prf, PROOFSIZE, sizeof(u32), &compu32);
for (u32 i=1; i<PROOFSIZE; i++)
if (prf[i] <= prf[i-1])
return;
#ifdef EQUIHASH_TROMP_ATOMIC
u32 soli = std::atomic_fetch_add_explicit(&nsols, 1U, std::memory_order_relaxed);
#else
u32 soli = nsols++;
#endif
if (soli < MAXSOLS)
listindices1(WK, t, sols[soli]); // assume WK odd
}
void showbsizes(u32 r) {
#if defined(HIST) || defined(SPARK) || defined(LOGSPARK)
u32 binsizes[65];
u32 binsizes[65];
memset(binsizes, 0, 65 * sizeof(u32));
for (u32 bucketid = 0; bucketid < NBUCKETS; bucketid++) {
u32 bsize = min(nslots[r&1][bucketid], NSLOTS) >> (SLOTBITS-6);
@ -314,331 +292,317 @@ struct equi {
}
// printf("\n");
#endif
}
struct htlayout {
htalloc hta;
u32 prevhashunits;
u32 nexthashunits;
u32 dunits;
u32 prevbo;
u32 nextbo;
htlayout(equi *eq, u32 r): hta(eq->hta), prevhashunits(0), dunits(0) {
u32 nexthashbytes = hashsize(r);
nexthashunits = hashwords(nexthashbytes);
prevbo = 0;
nextbo = nexthashunits * sizeof(hashunit) - nexthashbytes; // 0-3
if (r) {
u32 prevhashbytes = hashsize(r-1);
prevhashunits = hashwords(prevhashbytes);
prevbo = prevhashunits * sizeof(hashunit) - prevhashbytes; // 0-3
dunits = prevhashunits - nexthashunits;
}
}
u32 getxhash0(const slot0* pslot) const {
struct htlayout {
htalloc hta;
u32 prevhashunits;
u32 nexthashunits;
u32 dunits;
u32 prevbo;
u32 nextbo;
htlayout(equi *eq, u32 r): hta(eq->hta), prevhashunits(0), dunits(0) {
u32 nexthashbytes = hashsize(r);
nexthashunits = hashwords(nexthashbytes);
prevbo = 0;
nextbo = nexthashunits * sizeof(hashunit) - nexthashbytes; // 0-3
if (r) {
u32 prevhashbytes = hashsize(r-1);
prevhashunits = hashwords(prevhashbytes);
prevbo = prevhashunits * sizeof(hashunit) - prevhashbytes; // 0-3
dunits = prevhashunits - nexthashunits;
}
}
u32 getxhash0(const slot0* pslot) const {
#if WN == 200 && RESTBITS == 4
return pslot->hash->bytes[prevbo] >> 4;
return pslot->hash->bytes[prevbo] >> 4;
#elif WN == 200 && RESTBITS == 8
return (pslot->hash->bytes[prevbo] & 0xf) << 4 | pslot->hash->bytes[prevbo+1] >> 4;
return (pslot->hash->bytes[prevbo] & 0xf) << 4 | pslot->hash->bytes[prevbo+1] >> 4;
#elif WN == 200 && RESTBITS == 9
return (pslot->hash->bytes[prevbo] & 0x1f) << 4 | pslot->hash->bytes[prevbo+1] >> 4;
return (pslot->hash->bytes[prevbo] & 0x1f) << 4 | pslot->hash->bytes[prevbo+1] >> 4;
#elif WN == 144 && RESTBITS == 4
return pslot->hash->bytes[prevbo] & 0xf;
return pslot->hash->bytes[prevbo] & 0xf;
#elif WN == 192 && RESTBITS == 4
return pslot->hash->bytes[prevbo] & 0xf;
#else
#error non implemented
#endif
}
u32 getxhash1(const slot1* pslot) const {
}
u32 getxhash1(const slot1* pslot) const {
#if WN == 200 && RESTBITS == 4
return pslot->hash->bytes[prevbo] & 0xf;
return pslot->hash->bytes[prevbo] & 0xf;
#elif WN == 200 && RESTBITS == 8
return pslot->hash->bytes[prevbo];
return pslot->hash->bytes[prevbo];
#elif WN == 200 && RESTBITS == 9
return (pslot->hash->bytes[prevbo]&1) << 8 | pslot->hash->bytes[prevbo+1];
return (pslot->hash->bytes[prevbo]&1) << 8 | pslot->hash->bytes[prevbo+1];
#elif WN == 144 && RESTBITS == 4
return pslot->hash->bytes[prevbo] & 0xf;
return pslot->hash->bytes[prevbo] & 0xf;
#elif WN == 192 && RESTBITS == 4
return pslot->hash->bytes[prevbo] & 0xf;
#else
#error non implemented
#endif
}
bool equal(const hashunit *hash0, const hashunit *hash1) const {
return hash0[prevhashunits-1].word == hash1[prevhashunits-1].word;
}
};
}
bool equal(const hashunit *hash0, const hashunit *hash1) const {
return hash0[prevhashunits-1].word == hash1[prevhashunits-1].word;
}
};
struct collisiondata {
struct collisiondata {
#ifdef XBITMAP
#if NSLOTS > 64
#error cant use XBITMAP with more than 64 slots
#endif
u64 xhashmap[NRESTS];
u64 xmap;
#else
#if RESTBITS <= 6
typedef uchar xslot;
typedef uchar xslot;
#else
typedef u16 xslot;
typedef u16 xslot;
#endif
xslot nxhashslots[NRESTS];
xslot xhashslots[NRESTS][XFULL];
xslot *xx;
u32 n0;
u32 n1;
#endif
u32 s0;
xslot nxhashslots[NRESTS];
xslot xhashslots[NRESTS][XFULL];
xslot *xx;
u32 n0;
u32 n1;
u32 s0;
void clear() {
#ifdef XBITMAP
memset(xhashmap, 0, NRESTS * sizeof(u64));
#else
memset(nxhashslots, 0, NRESTS * sizeof(xslot));
#endif
}
bool addslot(u32 s1, u32 xh) {
#ifdef XBITMAP
xmap = xhashmap[xh];
xhashmap[xh] |= (u64)1 << s1;
s0 = -1;
return true;
#else
n1 = (u32)nxhashslots[xh]++;
if (n1 >= XFULL)
return false;
xx = xhashslots[xh];
xx[n1] = s1;
n0 = 0;
return true;
#endif
}
bool nextcollision() const {
#ifdef XBITMAP
return xmap != 0;
#else
return n0 < n1;
#endif
}
u32 slot() {
#ifdef XBITMAP
const u32 ffs = __builtin_ffsll(xmap);
s0 += ffs; xmap >>= ffs;
return s0;
#else
return (u32)xx[n0++];
#endif
}
};
void clear() {
memset(nxhashslots, 0, NRESTS * sizeof(xslot));
}
bool addslot(u32 s1, u32 xh) {
n1 = (u32)nxhashslots[xh]++;
if (n1 >= XFULL)
return false;
xx = xhashslots[xh];
xx[n1] = s1;
n0 = 0;
return true;
}
bool nextcollision() const {
return n0 < n1;
}
u32 slot() {
return (u32)xx[n0++];
}
};
void digit0(const u32 id) {
uchar hash[HASHOUT];
crypto_generichash_blake2b_state state;
htlayout htl(this, 0);
const u32 hashbytes = hashsize(0);
for (u32 block = id; block < NBLOCKS; block += nthreads) {
state = blake_ctx;
u32 leb = htole32(block);
crypto_generichash_blake2b_update(&state, (uchar *)&leb, sizeof(u32));
crypto_generichash_blake2b_final(&state, hash, HASHOUT);
for (u32 i = 0; i<HASHESPERBLAKE; i++) {
const uchar *ph = hash + i * WN/8;
void digit0(const u32 id) {
uchar hash[HASHOUT];
crypto_generichash_blake2b_state state;
htlayout htl(this, 0);
const u32 hashbytes = hashsize(0);
for (u32 block = id; block < NBLOCKS; block += nthreads) {
state = blake_ctx;
u32 leb = htole32(block);
crypto_generichash_blake2b_update(&state, (uchar *)&leb, sizeof(u32));
crypto_generichash_blake2b_final(&state, hash, HASHOUT);
for (u32 i = 0; i<HASHESPERBLAKE; i++) {
const uchar *ph = hash + i * WN/8;
#if BUCKBITS == 16 && RESTBITS == 4
const u32 bucketid = ((u32)ph[0] << 8) | ph[1];
const u32 bucketid = ((u32)ph[0] << 8) | ph[1];
#elif BUCKBITS == 12 && RESTBITS == 8
const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4;
const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4;
#elif BUCKBITS == 11 && RESTBITS == 9
const u32 bucketid = ((u32)ph[0] << 3) | ph[1] >> 5;
const u32 bucketid = ((u32)ph[0] << 3) | ph[1] >> 5;
#elif BUCKBITS == 20 && RESTBITS == 4
const u32 bucketid = ((((u32)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4;
const u32 bucketid = ((((u32)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4;
#elif BUCKBITS == 12 && RESTBITS == 4
const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4;
const u32 bucketid = ((u32)ph[0] << 4) | ph[1] >> 4;
const u32 xhash = ph[1] & 0xf;
#elif BUCKBITS == 20 && RESTBITS == 4
const u32 bucketid = ((((u32)ph[0] << 8) | ph[1]) << 4) | ph[2] >> 4;
#else
#error not implemented
#endif
const u32 slot = getslot(0, bucketid);
if (slot >= NSLOTS) {
bfull++;
continue;
const u32 slot = getslot(0, bucketid);
if (slot >= NSLOTS) {
bfull++;
continue;
}
slot0 &s = hta.trees0[0][bucketid][slot];
s.attr = tree(block * HASHESPERBLAKE + i);
memcpy(s.hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes);
}
}
slot0 &s = hta.trees0[0][bucketid][slot];
s.attr = tree(block * HASHESPERBLAKE + i);
memcpy(s.hash->bytes+htl.nextbo, ph+WN/8-hashbytes, hashbytes);
}
}
}
void digitodd(const u32 r, const u32 id) {
htlayout htl(this, r);
collisiondata cd;
for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) {
cd.clear();
slot0 *buck = htl.hta.trees0[(r-1)/2][bucketid]; // optimize by updating previous buck?!
u32 bsize = getnslots(r-1, bucketid); // optimize by putting bucketsize with block?!
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?!
if (!cd.addslot(s1, htl.getxhash0(pslot1))) {
xfull++;
continue;
}
for (; cd.nextcollision(); ) {
const u32 s0 = cd.slot();
const slot0 *pslot0 = buck + s0;
if (htl.equal(pslot0->hash, pslot1->hash)) {
hfull++;
continue;
}
u32 xorbucketid;
const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes;
void digitodd(const u32 r, const u32 id) {
htlayout htl(this, r);
collisiondata cd;
for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) {
cd.clear();
slot0 *buck = htl.hta.trees0[(r-1)/2][bucketid]; // optimize by updating previous buck?!
u32 bsize = getnslots(r-1, bucketid); // optimize by putting bucketsize with block?!
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot0 *pslot1 = buck + s1; // optimize by updating previous pslot1?!
if (!cd.addslot(s1, htl.getxhash0(pslot1))) {
xfull++;
continue;
}
for (; cd.nextcollision(); ) {
const u32 s0 = cd.slot();
const slot0 *pslot0 = buck + s0;
if (htl.equal(pslot0->hash, pslot1->hash)) {
hfull++;
continue;
}
u32 xorbucketid;
const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes;
#if WN == 200 && BUCKBITS == 12 && RESTBITS == 8
xorbucketid = (((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 8)
xorbucketid = (((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 8)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]);
#elif WN == 200 && BUCKBITS == 11 && RESTBITS == 9
xorbucketid = (((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 7)
xorbucketid = (((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) & 0xf) << 7)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 1;
#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4
xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8)
xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4)
| (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4;
#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4;
#elif WN == 192 && BUCKBITS == 20 && RESTBITS == 4
xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4)
| (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4;
#else
#error not implemented
#endif
const u32 xorslot = getslot(r, xorbucketid);
if (xorslot >= NSLOTS) {
bfull++;
continue;
}
slot1 &xs = htl.hta.trees1[r/2][xorbucketid][xorslot];
xs.attr = tree(bucketid, s0, s1);
for (u32 i=htl.dunits; i < htl.prevhashunits; i++)
xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word;
const u32 xorslot = getslot(r, xorbucketid);
if (xorslot >= NSLOTS) {
bfull++;
continue;
}
slot1 &xs = htl.hta.trees1[r/2][xorbucketid][xorslot];
xs.attr = tree(bucketid, s0, s1);
for (u32 i=htl.dunits; i < htl.prevhashunits; i++)
xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word;
}
}
}
}
}
}
void digiteven(const u32 r, const u32 id) {
htlayout htl(this, r);
collisiondata cd;
for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) {
cd.clear();
slot1 *buck = htl.hta.trees1[(r-1)/2][bucketid]; // OPTIMIZE BY UPDATING PREVIOUS
u32 bsize = getnslots(r-1, bucketid);
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS
if (!cd.addslot(s1, htl.getxhash1(pslot1))) {
xfull++;
continue;
}
for (; cd.nextcollision(); ) {
const u32 s0 = cd.slot();
const slot1 *pslot0 = buck + s0;
if (htl.equal(pslot0->hash, pslot1->hash)) {
hfull++;
continue;
}
u32 xorbucketid;
const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes;
void digiteven(const u32 r, const u32 id) {
htlayout htl(this, r);
collisiondata cd;
for (u32 bucketid=id; bucketid < NBUCKETS; bucketid += nthreads) {
cd.clear();
slot1 *buck = htl.hta.trees1[(r-1)/2][bucketid]; // OPTIMIZE BY UPDATING PREVIOUS
u32 bsize = getnslots(r-1, bucketid);
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot1 *pslot1 = buck + s1; // OPTIMIZE BY UPDATING PREVIOUS
if (!cd.addslot(s1, htl.getxhash1(pslot1))) {
xfull++;
continue;
}
for (; cd.nextcollision(); ) {
const u32 s0 = cd.slot();
const slot1 *pslot0 = buck + s0;
if (htl.equal(pslot0->hash, pslot1->hash)) {
hfull++;
continue;
}
u32 xorbucketid;
const uchar *bytes0 = pslot0->hash->bytes, *bytes1 = pslot1->hash->bytes;
#if WN == 200 && BUCKBITS == 12 && RESTBITS == 8
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4;
#elif WN == 200 && BUCKBITS == 11 && RESTBITS == 9
xorbucketid = ((u32)(bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) << 3)
xorbucketid = ((u32)(bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) << 3)
| (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 5;
#elif WN == 144 && BUCKBITS == 20 && RESTBITS == 4
xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8)
xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4)
| (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4;
#elif WN == 96 && BUCKBITS == 12 && RESTBITS == 4
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
xorbucketid = ((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 4)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2]) >> 4;
#elif WN == 192 && BUCKBITS == 20 && RESTBITS == 4
xorbucketid = ((((u32)(bytes0[htl.prevbo+1] ^ bytes1[htl.prevbo+1]) << 8)
| (bytes0[htl.prevbo+2] ^ bytes1[htl.prevbo+2])) << 4)
| (bytes0[htl.prevbo+3] ^ bytes1[htl.prevbo+3]) >> 4;
#else
#error not implemented
#endif
const u32 xorslot = getslot(r, xorbucketid);
if (xorslot >= NSLOTS) {
bfull++;
continue;
}
slot0 &xs = htl.hta.trees0[r/2][xorbucketid][xorslot];
xs.attr = tree(bucketid, s0, s1);
for (u32 i=htl.dunits; i < htl.prevhashunits; i++)
xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word;
const u32 xorslot = getslot(r, xorbucketid);
if (xorslot >= NSLOTS) {
bfull++;
continue;
}
slot0 &xs = htl.hta.trees0[r/2][xorbucketid][xorslot];
xs.attr = tree(bucketid, s0, s1);
for (u32 i=htl.dunits; i < htl.prevhashunits; i++)
xs.hash[i-htl.dunits].word = pslot0->hash[i].word ^ pslot1->hash[i].word;
}
}
}
}
}
}
void digitK(const u32 id) {
collisiondata cd;
htlayout htl(this, WK);
u32 nc = 0;
for (u32 bucketid = id; bucketid < NBUCKETS; bucketid += nthreads) {
cd.clear();
slot0 *buck = htl.hta.trees0[(WK-1)/2][bucketid];
u32 bsize = getnslots(WK-1, bucketid);
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot0 *pslot1 = buck + s1;
if (!cd.addslot(s1, htl.getxhash0(pslot1))) // assume WK odd
continue;
for (; cd.nextcollision(); ) {
const u32 s0 = cd.slot();
if (htl.equal(buck[s0].hash, pslot1->hash))
nc++, candidate(tree(bucketid, s0, s1));
void digitK(const u32 id) {
collisiondata cd;
htlayout htl(this, WK);
u32 nc = 0;
for (u32 bucketid = id; bucketid < NBUCKETS; bucketid += nthreads) {
cd.clear();
slot0 *buck = htl.hta.trees0[(WK-1)/2][bucketid];
u32 bsize = getnslots(WK-1, bucketid);
for (u32 s1 = 0; s1 < bsize; s1++) {
const slot0 *pslot1 = buck + s1;
if (!cd.addslot(s1, htl.getxhash0(pslot1))) // assume WK odd
continue;
for (; cd.nextcollision(); ) {
const u32 s0 = cd.slot();
if (htl.equal(buck[s0].hash, pslot1->hash))
nc++, candidate(tree(bucketid, s0, s1));
}
}
}
}
}
//printf(" %d candidates ", nc);
}
}
};
typedef struct {
u32 id;
pthread_t thread;
equi *eq;
u32 id;
pthread_t thread;
equi *eq;
} thread_ctx;
void barrier(pthread_barrier_t *barry) {
const int rc = pthread_barrier_wait(barry);
if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
const int rc = pthread_barrier_wait(barry);
if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
// printf("Could not wait on barrier\n");
pthread_exit(NULL);
}
pthread_exit(NULL);
}
}
void *worker(void *vp) {
thread_ctx *tp = (thread_ctx *)vp;
equi *eq = tp->eq;
thread_ctx *tp = (thread_ctx *)vp;
equi *eq = tp->eq;
if (tp->id == 0)
// printf("Digit 0\n");
barrier(&eq->barry);
eq->digit0(tp->id);
barrier(&eq->barry);
if (tp->id == 0) {
eq->xfull = eq->bfull = eq->hfull = 0;
eq->showbsizes(0);
}
barrier(&eq->barry);
for (u32 r = 1; r < WK; r++) {
if (tp->id == 0)
// printf("Digit %d", r);
barrier(&eq->barry);
r&1 ? eq->digitodd(r, tp->id) : eq->digiteven(r, tp->id);
// printf("Digit 0\n");
barrier(&eq->barry);
eq->digit0(tp->id);
barrier(&eq->barry);
if (tp->id == 0) {
// printf(" x%d b%d h%d\n", eq->xfull, eq->bfull, eq->hfull);
eq->xfull = eq->bfull = eq->hfull = 0;
eq->showbsizes(r);
eq->xfull = eq->bfull = eq->hfull = 0;
eq->showbsizes(0);
}
barrier(&eq->barry);
}
if (tp->id == 0)
for (u32 r = 1; r < WK; r++) {
if (tp->id == 0)
// printf("Digit %d", r);
barrier(&eq->barry);
r&1 ? eq->digitodd(r, tp->id) : eq->digiteven(r, tp->id);
barrier(&eq->barry);
if (tp->id == 0) {
// printf(" x%d b%d h%d\n", eq->xfull, eq->bfull, eq->hfull);
eq->xfull = eq->bfull = eq->hfull = 0;
eq->showbsizes(r);
}
barrier(&eq->barry);
}
if (tp->id == 0)
// printf("Digit %d\n", WK);
eq->digitK(tp->id);
barrier(&eq->barry);
pthread_exit(NULL);
return 0;
}
eq->digitK(tp->id);
barrier(&eq->barry);
pthread_exit(NULL);
return 0;
}

View File

@ -202,10 +202,13 @@ UniValue generate(const UniValue& params, bool fHelp)
}
unsigned int nExtraNonce = 0;
UniValue blockHashes(UniValue::VARR);
unsigned int n = Params().EquihashN();
unsigned int k = Params().EquihashK();
const CChainParams& chainparams = Params();
unsigned int n;
unsigned int k;
while (nHeight < nHeightEnd)
{
n = chainparams.EquihashN(nHeight + 1);
k = chainparams.EquihashK(nHeight + 1);
#ifdef ENABLE_WALLET
std::unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
#else
@ -250,7 +253,7 @@ UniValue generate(const UniValue& params, bool fHelp)
solutionTargetChecks.increment();
return CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus());
};
bool found = EhBasicSolveUncancellable(n, k, curr_state, validBlock);
bool found = EhOptimisedSolveUncancellable(n, k, curr_state, validBlock);
ehSolverRuns.increment();
if (found) {
goto endloop;

View File

@ -79,7 +79,7 @@ void ThreadSendAlert()
// These versions are protocol versions
// 170002 : 1.0.0
alert.nMinVer = 170005;
alert.nMaxVer = 180005;
alert.nMaxVer = 180006;
//
// main.cpp:

View File

@ -755,8 +755,9 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends)
mtx2.vin[0].nSequence = 0;
{
auto consensus = Params().GetConsensus();
CTransaction tx2(mtx2);
BOOST_CHECK(Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, Params().GetConsensus()));
BOOST_CHECK(Consensus::CheckTxInputs(tx2, state, cache, 100+consensus.coinbaseMaturity, consensus));
}
mtx2.vout.resize(1);
@ -768,10 +769,10 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends)
CTransaction tx2(mtx2);
if(consensus.fCoinbaseMustBeProtected) {
BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, consensus));
BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, cache, 100+consensus.coinbaseMaturity, consensus));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-coinbase-spend-has-transparent-outputs");
} else {
BOOST_CHECK(Consensus::CheckTxInputs(tx2, state, cache, 100+COINBASE_MATURITY, consensus));
BOOST_CHECK(Consensus::CheckTxInputs(tx2, state, cache, 100+consensus.coinbaseMaturity, consensus));
}
}
}

View File

@ -179,7 +179,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in
continue;
const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash);
if (fSanityCheck) assert(coins);
if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) {
if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < Params().GetConsensus().coinbaseMaturity)) {
transactionsToRemove.push_back(tx);
break;
}

View File

@ -9,7 +9,7 @@
* network protocol versioning
*/
static const int PROTOCOL_VERSION = 180005;
static const int PROTOCOL_VERSION = 180006;
//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;

View File

@ -748,7 +748,8 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) {
wallet.AddSpendingKey(sk);
// Generate a chain
size_t numBlocks = WITNESS_CACHE_SIZE + 10;
// Uses mainnet maturity. Otherwise, SelectParams(CBaseChainParams::TESTNET); coinbaseMaturity = 10;
size_t numBlocks = 100 + 10;
blocks.resize(numBlocks);
indices.resize(numBlocks);
for (size_t i = 0; i < numBlocks; i++) {

View File

@ -640,6 +640,8 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
const CBlock* pblockIn,
ZCIncrementalMerkleTree& tree)
{
const unsigned int maxWitnessCacheSize = Params().GetConsensus().coinbaseMaturity;
{
LOCK(cs_wallet);
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
@ -661,13 +663,13 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
if (nd->witnesses.size() > 0) {
nd->witnesses.push_front(nd->witnesses.front());
}
if (nd->witnesses.size() > WITNESS_CACHE_SIZE) {
if (nd->witnesses.size() > maxWitnessCacheSize) {
nd->witnesses.pop_back();
}
}
}
}
if (nWitnessCacheSize < WITNESS_CACHE_SIZE) {
if (nWitnessCacheSize < maxWitnessCacheSize) {
nWitnessCacheSize += 1;
}
@ -3631,7 +3633,8 @@ int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
return 0;
return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
auto params = Params().GetConsensus();
return max(0, (params.coinbaseMaturity+1) - GetDepthInMainChain());
}

View File

@ -58,7 +58,7 @@ static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
//! Size of witness cache
// Should be large enough that we can expect not to reorg beyond our cache
// unless there is some exceptional network disruption.
static const unsigned int WITNESS_CACHE_SIZE = COINBASE_MATURITY;
// (Inlined, see `IncrementNoteWitnesses`)
class CAccountingEntry;
class CBlockIndex;

View File

@ -138,8 +138,9 @@ double benchmark_solve_equihash()
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << I;
unsigned int n = Params(CBaseChainParams::MAIN).EquihashN();
unsigned int k = Params(CBaseChainParams::MAIN).EquihashK();
const CChainParams& params = Params(CBaseChainParams::MAIN);
unsigned int n = params.EquihashN(params.EquihashParamsUpdate());
unsigned int k = params.EquihashK(params.EquihashParamsUpdate());
crypto_generichash_blake2b_state eh_state;
EhInitialiseState(n, k, eh_state);
crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size());