diff --git a/src/Difficulty.cc b/src/Difficulty.cc new file mode 100644 index 000000000..de799236e --- /dev/null +++ b/src/Difficulty.cc @@ -0,0 +1,29 @@ +/* + The MIT License (MIT) + + Copyright (c) [2019] [BTC.COM] + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +#include "Difficulty.h" + +void BitsToTarget(uint32_t bits, uint256 &target) { + target = ArithToUint256(arith_uint256{}.SetCompact(bits)); +} diff --git a/src/Difficulty.h b/src/Difficulty.h new file mode 100644 index 000000000..508959344 --- /dev/null +++ b/src/Difficulty.h @@ -0,0 +1,104 @@ +/* + The MIT License (MIT) + + Copyright (c) [2019] [BTC.COM] + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +#pragma once + +#include "arith_uint256.h" +#include "uint256.h" + +#include +#include +#include +#include + +void BitsToTarget(uint32_t bits, uint256 &target); + +template +struct Difficulty { + static const uint64_t GetDiffOneBits() { return DiffOneBits; } + + static const arith_uint256 &GetDiffOneTarget() { + static const auto DiffOneTarget = arith_uint256{}.SetCompact(DiffOneBits); + return DiffOneTarget; + } + + static const std::array &GetDiffToTargetTable() { + static const auto DiffToTargetTable = GenerateDiffToTargetTable(); + return DiffToTargetTable; + } + + static std::array GenerateDiffToTargetTable() { + std::array table; + uint32_t shifts = 0; + for (auto &target : table) { + target = ArithToUint256(GetDiffOneTarget() >> (shifts++)); + } + return table; + } + + static uint64_t TargetToDiff(uint256 &target) { + arith_uint256 t = UintToArith256(target); + return (GetDiffOneTarget() / t).GetLow64(); + } + + static uint64_t TargetToDiff(const std::string &str) { + auto target = uint256S(str); + return TargetToDiff(target); + } + + static void + DiffToTarget(uint64_t diff, uint256 &target, bool useTable = true) { + static const auto MaxTarget = uint256S( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + if (diff == 0) { + target = MaxTarget; + return; + } + + if (useTable) { + // try to find by table + static const auto &DiffToTargetTable = GetDiffToTargetTable(); + auto p = static_cast(log2(diff)); + if (p < TableSize && diff == (1ull << p)) { + target = DiffToTargetTable[p]; + return; + } + } + + // If it is not found in the table, it will be calculated. + target = ArithToUint256(GetDiffOneTarget() / diff); + } + + static void BitsToDifficulty(uint32_t bits, double *difficulty) { + arith_uint256 target; + target.SetCompact(bits); + *difficulty = GetDiffOneTarget().getdouble() / target.getdouble(); + } + + static void BitsToDifficulty(uint32_t bits, uint64_t *difficulty) { + arith_uint256 target; + target.SetCompact(bits); + *difficulty = (GetDiffOneTarget() / target).GetLow64(); + } +}; diff --git a/src/bitcoin/BitcoinUtils.h b/src/bitcoin/BitcoinUtils.h index c16940c76..2d4b913a4 100644 --- a/src/bitcoin/BitcoinUtils.h +++ b/src/bitcoin/BitcoinUtils.h @@ -43,8 +43,6 @@ #include #endif -#include "CommonBitcoin.h" - #if defined(CHAIN_TYPE_BCH) || defined(CHAIN_TYPE_BSV) // header that defined DecodeDestination & IsValidDestinationString @@ -114,19 +112,21 @@ std::vector BlockMerkleBranch(const CBlock &block, uint32_t position); #endif uint256 ComputeCoinbaseMerkleRoot( - const std::vector &coinbaseBin, const vector &merkleBranch); + const std::vector &coinbaseBin, + const std::vector &merkleBranch); std::string EncodeHexBlock(const CBlock &block); std::string EncodeHexBlockHeader(const CBlockHeader &blkHeader); int64_t GetBlockReward(int nHeight, const Consensus::Params &consensusParams); -bool checkBitcoinRPC(const string &rpcAddr, const string &rpcUserpass); +bool checkBitcoinRPC( + const std::string &rpcAddr, const std::string &rpcUserpass); -int32_t getBlockHeightFromCoinbase(const string &coinbase1); +int32_t getBlockHeightFromCoinbase(const std::string &coinbase1); -string getNotifyHashStr(const uint256 &hash); -string getNotifyUint32Str(const uint32_t var); +std::string getNotifyHashStr(const uint256 &hash); +std::string getNotifyUint32Str(const uint32_t var); inline uint16_t SwapUint(uint16_t v) { return (v >> 8) | (v << 8); diff --git a/src/bitcoin/CommonBitcoin.cc b/src/bitcoin/CommonBitcoin.cc deleted file mode 100644 index 8daa0edd5..000000000 --- a/src/bitcoin/CommonBitcoin.cc +++ /dev/null @@ -1,98 +0,0 @@ -/* - The MIT License (MIT) - - Copyright (c) [2016] [BTC.COM] - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ - -#include "CommonBitcoin.h" -#include - -#ifdef CHAIN_TYPE_LTC -static const uint32_t BITS_DIFF1 = 0x1f00ffff; -#elif defined(CHAIN_TYPE_ZEC) -static const uint32_t BITS_DIFF1 = 0x1f07ffff; -#else -static const uint32_t BITS_DIFF1 = 0x1d00ffff; -#endif - -static const auto TARGET_DIFF1 = arith_uint256().SetCompact(BITS_DIFF1); -static const auto MAX_TARGET = uint256S( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - -uint64_t TargetToDiff(uint256 &target) { - arith_uint256 t = UintToArith256(target); - return (TARGET_DIFF1 / t).GetLow64(); -} - -uint64_t TargetToDiff(const string &str) { - uint256 t = uint256S(str); - return TargetToDiff(t); -} - -void BitsToTarget(uint32_t bits, uint256 &target) { - target = ArithToUint256(arith_uint256().SetCompact(bits)); -} - -uint32_t GetDiff1Bits() { - return BITS_DIFF1; -} - -static std::array GenerateDiff2TargetTable() { - std::array table; - uint32_t shifts = 0; - for (auto &target : table) { - target = ArithToUint256(TARGET_DIFF1 >> (shifts++)); - } - return table; -} - -static const auto kDiff2TargetTable = GenerateDiff2TargetTable(); - -void DiffToTarget(uint64_t diff, uint256 &target, bool useTable) { - if (diff == 0) { - target = MAX_TARGET; - return; - } - - if (useTable) { - // try to find by table - const uint64_t p = (uint64_t)log2(diff); - if (p < kDiff2TargetTable.size() && diff == (1ull << p)) { - target = kDiff2TargetTable[p]; - return; - } - } - - // If it is not found in the table, it will be calculated. - target = ArithToUint256(TARGET_DIFF1 / diff); -} - -void BitsToDifficulty(uint32_t bits, double *difficulty) { - arith_uint256 target; - target.SetCompact(bits); - *difficulty = TARGET_DIFF1.getdouble() / target.getdouble(); -} - -void BitsToDifficulty(uint32_t bits, uint64_t *difficulty) { - arith_uint256 target; - target.SetCompact(bits); - *difficulty = (TARGET_DIFF1 / target).GetLow64(); -} diff --git a/src/bitcoin/CommonBitcoin.h b/src/bitcoin/CommonBitcoin.h index 3e652d6f0..5f39d9c61 100644 --- a/src/bitcoin/CommonBitcoin.h +++ b/src/bitcoin/CommonBitcoin.h @@ -24,21 +24,14 @@ #ifndef POOL_COMMON_BITCOIN_H_ #define POOL_COMMON_BITCOIN_H_ -#include "Common.h" - -#include - -////////////////////////////// for Bitcoin ////////////////////////////// -uint64_t TargetToDiff(uint256 &target); -uint64_t TargetToDiff(const string &str); - -void BitsToTarget(uint32_t bits, uint256 &target); -void DiffToTarget(uint64_t diff, uint256 &target, bool useTable = true); -void BitsToDifficulty(uint32_t bits, double *difficulty); -void BitsToDifficulty(uint32_t bits, uint64_t *difficulty); - -uint32_t GetDiff1Bits(); - -////////////////////////////// for Bitcoin ////////////////////////////// +#include "Difficulty.h" + +#ifdef CHAIN_TYPE_LTC +using BitcoinDifficulty = Difficulty<0x1f00ffff>; +#elif defined(CHAIN_TYPE_ZEC) +using BitcoinDifficulty = Difficulty<0x1f07ffff>; +#else +using BitcoinDifficulty = Difficulty<0x1d00ffff>; +#endif #endif diff --git a/src/bitcoin/StratumBitcoin.h b/src/bitcoin/StratumBitcoin.h index 634efe05d..c88d49dad 100644 --- a/src/bitcoin/StratumBitcoin.h +++ b/src/bitcoin/StratumBitcoin.h @@ -190,7 +190,7 @@ class ShareBitcoin : public sharebase::BitcoinMsg { } double networkDifficulty = 1.0; // 0.0; - BitsToDifficulty(blkbits(), &networkDifficulty); + BitcoinDifficulty::BitsToDifficulty(blkbits(), &networkDifficulty); if (networkDifficulty < (double)sharediff()) { return 1.0; @@ -223,7 +223,7 @@ class ShareBitcoin : public sharebase::BitcoinMsg { std::string toString() const { double networkDifficulty = 0.0; - BitsToDifficulty(blkbits(), &networkDifficulty); + BitcoinDifficulty::BitsToDifficulty(blkbits(), &networkDifficulty); return Strings::Format( "share(jobId: %u, ip: %s, userId: %d, " diff --git a/src/bitcoin/StratumMinerBitcoin.cc b/src/bitcoin/StratumMinerBitcoin.cc index e0098db95..6cd9aefa2 100644 --- a/src/bitcoin/StratumMinerBitcoin.cc +++ b/src/bitcoin/StratumMinerBitcoin.cc @@ -288,7 +288,7 @@ void StratumMinerBitcoin::handleRequest_Submit( // calc jobTarget uint256 jobTarget; - DiffToTarget(share.sharediff(), jobTarget); + BitcoinDifficulty::DiffToTarget(share.sharediff(), jobTarget); // we send share to kafka by default, but if there are lots of invalid // shares in a short time, we just drop them. diff --git a/src/bitcoin/StratumServerBitcoin.cc b/src/bitcoin/StratumServerBitcoin.cc index 51320486c..6a3940e3e 100644 --- a/src/bitcoin/StratumServerBitcoin.cc +++ b/src/bitcoin/StratumServerBitcoin.cc @@ -524,8 +524,9 @@ int ServerBitcoin::checkShare( // print out high diff share, 2^10 = 1024 if ((bnBlockHash >> 10) <= bnNetworkTarget) { LOG(INFO) << "high diff share, blkhash: " << blkHash.ToString() - << ", diff: " << TargetToDiff(blkHash) - << ", networkDiff: " << TargetToDiff(sjob->networkTarget_) + << ", diff: " << BitcoinDifficulty::TargetToDiff(blkHash) + << ", networkDiff: " + << BitcoinDifficulty::TargetToDiff(sjob->networkTarget_) << ", by: " << workFullName; } diff --git a/src/bitcoin/StratumSessionBitcoin.cc b/src/bitcoin/StratumSessionBitcoin.cc index 230681cc0..2ddd081e0 100644 --- a/src/bitcoin/StratumSessionBitcoin.cc +++ b/src/bitcoin/StratumSessionBitcoin.cc @@ -64,7 +64,7 @@ void StratumSessionBitcoin::sendSetDifficulty( #ifdef CHAIN_TYPE_ZEC // {"id": null, "method": "mining.set_target", "params": ["TARGET"]} uint256 target; - DiffToTarget(difficulty, target); + BitcoinDifficulty::DiffToTarget(difficulty, target); s = Strings::Format( "{\"id\":null,\"method\":\"mining.set_target\"" @@ -443,8 +443,8 @@ void StratumSessionBitcoin::handleRequest_SuggestTarget( return; } - suggestedDiff_ = - formatDifficulty(TargetToDiff(jparams.children()->at(0).str())); + suggestedDiff_ = formatDifficulty( + BitcoinDifficulty::TargetToDiff(jparams.children()->at(0).str())); responseTrue(idStr); } diff --git a/src/bitcoin/WatcherBitcoin.cc b/src/bitcoin/WatcherBitcoin.cc index 34048dc1c..10798e8ef 100644 --- a/src/bitcoin/WatcherBitcoin.cc +++ b/src/bitcoin/WatcherBitcoin.cc @@ -355,8 +355,9 @@ void PoolWatchClientBitcoin::handleStratumMessage(const string &line) { // 2 times. // @see double poolDiff, jobDiff; - BitsToDifficulty(poolStratumJob->nBits_, &poolDiff); - BitsToDifficulty(nBits, &jobDiff); + BitcoinDifficulty::BitsToDifficulty( + poolStratumJob->nBits_, &poolDiff); + BitcoinDifficulty::BitsToDifficulty(nBits, &jobDiff); double multiple = jobDiff / poolDiff; if (multiple < 0.5 || multiple > 2.0) { LOG(WARNING) << "<" << poolName_ diff --git a/src/sia/CommonSia.h b/src/sia/CommonSia.h new file mode 100644 index 000000000..3760dea26 --- /dev/null +++ b/src/sia/CommonSia.h @@ -0,0 +1,29 @@ +/* + The MIT License (MIT) + + Copyright (c) [2019] [BTC.COM] + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +#pragma once + +#include "Difficulty.h" + +using SiaDifficulty = Difficulty<0x1d00ffff>; diff --git a/src/sia/StratumSessionSia.cc b/src/sia/StratumSessionSia.cc index f7b30f37a..d488b4b3d 100644 --- a/src/sia/StratumSessionSia.cc +++ b/src/sia/StratumSessionSia.cc @@ -68,9 +68,9 @@ void StratumSessionSia::sendMiningNotify( uint256 shareTarget; if (jobDifficulty == 0) { shareTarget = siaJob->networkTarget_; - jobDifficulty = TargetToDiff(shareTarget); + jobDifficulty = SiaDifficulty::TargetToDiff(shareTarget); } else { - DiffToTarget(jobDifficulty, shareTarget); + SiaDifficulty::DiffToTarget(jobDifficulty, shareTarget); } string strShareTarget = shareTarget.GetHex(); LOG(INFO) << "new sia stratum job mining.notify: share difficulty=" diff --git a/src/sia/StratumSia.h b/src/sia/StratumSia.h index bd32e15cc..c42d7f217 100644 --- a/src/sia/StratumSia.h +++ b/src/sia/StratumSia.h @@ -24,7 +24,7 @@ #ifndef STRATUM_SIA_H_ #define STRATUM_SIA_H_ -#include "bitcoin/CommonBitcoin.h" +#include "sia/CommonSia.h" #include "Stratum.h" #include #include "sia/sia.pb.h" @@ -94,7 +94,7 @@ class ShareSia : public sharebase::SiaMsg { } double networkDifficulty = 0.0; - BitsToDifficulty(blkbits(), &networkDifficulty); + SiaDifficulty::BitsToDifficulty(blkbits(), &networkDifficulty); // Network diff may less than share diff on testnet or regression test // network. On regression test network, the network diff may be zero. But no @@ -121,7 +121,7 @@ class ShareSia : public sharebase::SiaMsg { string toString() const { double networkDifficulty = 0.0; - BitsToDifficulty(blkbits(), &networkDifficulty); + SiaDifficulty::BitsToDifficulty(blkbits(), &networkDifficulty); return Strings::Format( "share(jobId: %u, ip: %s, userId: %d, " diff --git a/test/TestCommon.cc b/test/TestCommon.cc index f2f2ee709..71d5addb8 100644 --- a/test/TestCommon.cc +++ b/test/TestCommon.cc @@ -96,8 +96,8 @@ TEST(Common, BitsToTarget) { static void TestDiffToTarget(uint64_t diff, string target) { uint256 targetWithoutTable, targetWithTable; - DiffToTarget(diff, targetWithoutTable, false); - DiffToTarget(diff, targetWithTable, true); + BitcoinDifficulty::DiffToTarget(diff, targetWithoutTable, false); + BitcoinDifficulty::DiffToTarget(diff, targetWithTable, true); ASSERT_EQ(targetWithoutTable.ToString(), target); ASSERT_EQ(targetWithTable.ToString(), target); } @@ -186,15 +186,15 @@ TEST(Common, DiffToTargetTable) { uint256 t1, t2; for (uint64_t i = 0; i < 10240; i++) { - DiffToTarget(i, t1, false); - DiffToTarget(i, t2, true); + BitcoinDifficulty::DiffToTarget(i, t1, false); + BitcoinDifficulty::DiffToTarget(i, t2, true); ASSERT_EQ(t1, t2); } for (uint32_t i = 0; i < 64; i++) { uint64_t diff = 1 << i; - DiffToTarget(diff, t1, false); - DiffToTarget(diff, t2, true); + BitcoinDifficulty::DiffToTarget(diff, t1, false); + BitcoinDifficulty::DiffToTarget(diff, t2, true); ASSERT_EQ(t1, t2); } } @@ -203,8 +203,8 @@ TEST(Common, DiffTargetDiff) { for (uint32_t i = 0; i < 64; i++) { uint64_t diff = 1 << i; uint256 target; - DiffToTarget(diff, target); - ASSERT_EQ(diff, TargetToDiff(target)); + BitcoinDifficulty::DiffToTarget(diff, target); + ASSERT_EQ(diff, BitcoinDifficulty::TargetToDiff(target)); } } @@ -239,7 +239,7 @@ TEST(Common, TargetToDiff) { #endif ASSERT_EQ( - TargetToDiff( + BitcoinDifficulty::TargetToDiff( "0x00000000000404CB000000000000000000000000000000000000000000000000"), diff); } @@ -255,7 +255,7 @@ TEST(Common, BitsToDifficulty) { // 0x1b0404cb: https://en.bitcoin.it/wiki/Difficulty double d; - BitsToDifficulty(0x1b0404cbu, &d); // diff = 16307.420939 + BitcoinDifficulty::BitsToDifficulty(0x1b0404cbu, &d); // diff = 16307.420939 ASSERT_EQ((uint64_t)(d * 10000.0), diff); } diff --git a/test/TestStatistics.cc b/test/TestStatistics.cc index f9345dea8..b6988c7d4 100644 --- a/test/TestStatistics.cc +++ b/test/TestStatistics.cc @@ -177,7 +177,7 @@ TEST(ShareStatsDay, ShareStatsDay) { // share -> socre = 1 : 1 // https://btc.com/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f - share.set_blkbits(GetDiff1Bits()); + share.set_blkbits(BitcoinDifficulty::GetDiffOneBits()); // accept for (uint32_t i = 0; i < 24; i++) { // hour idx range: [0, 23] diff --git a/test/TestStratum.cc b/test/TestStratum.cc index 0ccfbcd29..6a43f25b6 100644 --- a/test/TestStratum.cc +++ b/test/TestStratum.cc @@ -86,7 +86,7 @@ TEST(Stratum, Share) { TEST(Stratum, Share2) { ShareBitcoin s; - s.set_blkbits(GetDiff1Bits()); + s.set_blkbits(BitcoinDifficulty::GetDiffOneBits()); s.set_sharediff(1ll); ASSERT_EQ(s.score(), 1ll);