difficulty.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file difficulty.cpp
  15. * @author Christoph Jentzsch <cj@ethdev.com>
  16. * @date 2015
  17. * difficulty calculation tests.
  18. */
  19. #include <boost/test/unit_test.hpp>
  20. #include <test/TestHelper.h>
  21. #include <test/fuzzTesting/fuzzHelper.h>
  22. #include <libethashseal/Ethash.h>
  23. #include <libethashseal/GenesisInfo.h>
  24. #include <libethereum/ChainParams.h>
  25. using namespace std;
  26. using namespace dev;
  27. using namespace dev::eth;
  28. namespace js = json_spirit;
  29. std::string const c_testDifficulty = R"(
  30. "DifficultyTest[N]" : {
  31. "parentTimestamp" : "[PSTAMP]",
  32. "parentDifficulty" : "[PDIFF]",
  33. "currentTimestamp" : "[СSTAMP]",
  34. "currentBlockNumber" : "[CNUM]",
  35. "currentDifficulty" : "[CDIFF]"
  36. },
  37. )";
  38. void checkCalculatedDifficulty(BlockHeader const& _bi, BlockHeader const& _parent, Network _n, ChainOperationParams const& _p, string const& _testName = "")
  39. {
  40. u256 difficulty = _bi.difficulty();
  41. u256 frontierDiff = _p.u256Param("homsteadForkBlock");
  42. //The ultimate formula (Homestead)
  43. if (_bi.number() > frontierDiff)
  44. {
  45. u256 minimumDifficulty = _p.u256Param("minimumDifficulty");
  46. bigint block_diff = _parent.difficulty();
  47. bigint a = (_parent.difficulty() / 2048);
  48. int b = 1 - int(_bi.timestamp() - _parent.timestamp()) / 10;
  49. bigint c = (_bi.number() / 100000) - 2;
  50. block_diff += a * max<int>(b, -99);
  51. block_diff += u256(1) << (unsigned)c;
  52. block_diff = max<bigint>(minimumDifficulty, block_diff);
  53. BOOST_CHECK_MESSAGE(difficulty == block_diff, "Homestead Check Calculated diff = " << difficulty << " expected diff = " << block_diff << _testName);
  54. return;
  55. }
  56. u256 durationLimit;
  57. u256 minimumDifficulty;
  58. u256 difficultyBoundDivisor;
  59. switch(_n)
  60. {
  61. case Network::Frontier:
  62. case Network::FrontierTest:
  63. case Network::HomesteadTest:
  64. case Network::Ropsten:
  65. case Network::Test:
  66. durationLimit = 13;
  67. minimumDifficulty = 131072;
  68. difficultyBoundDivisor = 2048;
  69. break;
  70. default:
  71. cerr << "testing undefined network difficulty";
  72. durationLimit = _p.u256Param("durationLimit");
  73. minimumDifficulty = _p.u256Param("minimumDifficulty");
  74. difficultyBoundDivisor = _p.u256Param("difficultyBoundDivisor");
  75. break;
  76. }
  77. //Frontier Era
  78. bigint block_diff = _parent.difficulty();
  79. bigint a = (_parent.difficulty() / difficultyBoundDivisor);
  80. bigint b = ((_bi.timestamp() - _parent.timestamp()) < durationLimit) ? 1 : -1;
  81. bigint c = (_bi.number() / 100000) - 2;
  82. block_diff += a * b;
  83. block_diff += u256(1) << (unsigned)c;
  84. block_diff = max<bigint>(minimumDifficulty, block_diff);
  85. BOOST_CHECK_MESSAGE(difficulty == block_diff, "Check Calculated diff = " << difficulty << " expected diff = " << block_diff << _testName);
  86. return;
  87. }
  88. void fillDifficulty(string const& _testFileFullName, Ethash& _sealEngine)
  89. {
  90. int testN = 0;
  91. ostringstream finalTest;
  92. finalTest << "{" << std::endl;
  93. dev::test::TestOutputHelper::initTest(900);
  94. for (int stampDelta = 0; stampDelta < 45; stampDelta+=2)
  95. {
  96. for (u256 blockNumber = 1; blockNumber < 1500000; blockNumber += 25000)
  97. {
  98. testN++;
  99. json_spirit::mObject m;
  100. string testName = "DifficultyTest"+toString(testN);
  101. if (!dev::test::TestOutputHelper::passTest(m, testName))
  102. continue;
  103. u256 pStamp = dev::test::RandomCode::randomUniInt();
  104. u256 pDiff = dev::test::RandomCode::randomUniInt();
  105. u256 cStamp = pStamp + stampDelta;
  106. u256 cNum = blockNumber;
  107. BlockHeader parent;
  108. parent.setTimestamp(pStamp);
  109. parent.setDifficulty(pDiff);
  110. parent.setNumber(cNum - 1);
  111. BlockHeader current;
  112. current.setTimestamp(cStamp);
  113. current.setNumber(cNum);
  114. string tmptest = c_testDifficulty;
  115. std::map<string, string> replaceMap;
  116. replaceMap["[N]"] = toString(testN);
  117. replaceMap["[PDIFF]"] = toCompactHex(pDiff, HexPrefix::Add);
  118. replaceMap["[PSTAMP]"] = toCompactHex(pStamp, HexPrefix::Add);
  119. replaceMap["[СSTAMP]"] = toCompactHex(cStamp, HexPrefix::Add);
  120. replaceMap["[CNUM]"] = toCompactHex(cNum, HexPrefix::Add);
  121. replaceMap["[CDIFF]"] = toCompactHex(_sealEngine.calculateDifficulty(current, parent), HexPrefix::Add);
  122. dev::test::RandomCode::parseTestWithTypes(tmptest, replaceMap);
  123. finalTest << tmptest;
  124. }
  125. }
  126. finalTest << std::endl << "}";
  127. string testFile = finalTest.str();
  128. testFile = testFile.replace(testFile.find_last_of(","), 1, "");
  129. writeFile(_testFileFullName, asBytes(testFile));
  130. }
  131. void testDifficulty(string const& _testFileFullName, Ethash& _sealEngine, Network _n)
  132. {
  133. //Test File
  134. js::mValue v;
  135. string s = contentsString(_testFileFullName);
  136. BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of '" << _testFileFullName << "' is empty. Have you cloned the 'tests' repo branch develop?");
  137. js::read_string(s, v);
  138. dev::test::TestOutputHelper::initTest(v);
  139. for (auto& i: v.get_obj())
  140. {
  141. js::mObject o = i.second.get_obj();
  142. string testname = i.first;
  143. if (!dev::test::TestOutputHelper::passTest(o, testname))
  144. continue;
  145. BlockHeader parent;
  146. parent.setTimestamp(test::toInt(o["parentTimestamp"]));
  147. parent.setDifficulty(test::toInt(o["parentDifficulty"]));
  148. parent.setNumber(test::toInt(o["currentBlockNumber"]) - 1);
  149. BlockHeader current;
  150. current.setTimestamp(test::toInt(o["currentTimestamp"]));
  151. current.setNumber(test::toInt(o["currentBlockNumber"]));
  152. u256 difficulty = _sealEngine.calculateDifficulty(current, parent);
  153. current.setDifficulty(difficulty);
  154. BOOST_CHECK_EQUAL(difficulty, test::toInt(o["currentDifficulty"]));
  155. //Manual formula test
  156. checkCalculatedDifficulty(current, parent, _n, _sealEngine.chainParams(), "(" + i.first + ")");
  157. }
  158. }
  159. BOOST_AUTO_TEST_SUITE(DifficultyTests)
  160. BOOST_AUTO_TEST_CASE(difficultyTestsFrontier)
  161. {
  162. string testFileFullName = test::getTestPath();
  163. testFileFullName += "/BasicTests/difficultyFrontier.json";
  164. Ethash sealEngine;
  165. sealEngine.setChainParams(ChainParams(genesisInfo(Network::Frontier)));
  166. if (dev::test::Options::get().fillTests)
  167. fillDifficulty(testFileFullName, sealEngine);
  168. testDifficulty(testFileFullName, sealEngine, Network::Frontier);
  169. }
  170. BOOST_AUTO_TEST_CASE(difficultyTestsRopsten)
  171. {
  172. string testFileFullName = test::getTestPath();
  173. testFileFullName += "/BasicTests/difficultyRopsten.json";
  174. Ethash sealEngine;
  175. sealEngine.setChainParams(ChainParams(genesisInfo(Network::Ropsten)));
  176. if (dev::test::Options::get().fillTests)
  177. fillDifficulty(testFileFullName, sealEngine);
  178. testDifficulty(testFileFullName, sealEngine, Network::Ropsten);
  179. }
  180. BOOST_AUTO_TEST_CASE(difficultyTestsHomestead)
  181. {
  182. string testFileFullName = test::getTestPath();
  183. testFileFullName += "/BasicTests/difficultyHomestead.json";
  184. Ethash sealEngine;
  185. sealEngine.setChainParams(ChainParams(genesisInfo(Network::HomesteadTest)));
  186. if (dev::test::Options::get().fillTests)
  187. fillDifficulty(testFileFullName, sealEngine);
  188. testDifficulty(testFileFullName, sealEngine, Network::HomesteadTest);
  189. }
  190. BOOST_AUTO_TEST_CASE(difficultyTestsCustomHomestead)
  191. {
  192. string testFileFullName = test::getTestPath();
  193. testFileFullName += "/BasicTests/difficultyCustomHomestead.json";
  194. Ethash sealEngine;
  195. sealEngine.setChainParams(ChainParams(genesisInfo(Network::HomesteadTest)));
  196. if (dev::test::Options::get().fillTests)
  197. {
  198. u256 homsteadBlockNumber = 1000000;
  199. std::vector<u256> blockNumberVector = {homsteadBlockNumber - 100000, homsteadBlockNumber, homsteadBlockNumber + 100000};
  200. std::vector<u256> parentDifficultyVector = {1000, 2048, 4000, 1000000};
  201. std::vector<int> timestampDeltaVector = {0, 1, 8, 10, 13, 20, 100, 800, 1000, 1500};
  202. int testN = 0;
  203. ostringstream finalTest;
  204. finalTest << "{" << std::endl;
  205. for (size_t bN = 0; bN < blockNumberVector.size(); bN++)
  206. for (size_t pdN = 0; pdN < parentDifficultyVector.size(); pdN++)
  207. for (size_t tsN = 0; tsN < timestampDeltaVector.size(); tsN++)
  208. {
  209. testN++;
  210. int stampDelta = timestampDeltaVector.at(tsN);
  211. u256 blockNumber = blockNumberVector.at(bN);
  212. u256 pDiff = parentDifficultyVector.at(pdN);
  213. u256 pStamp = dev::test::RandomCode::randomUniInt();
  214. u256 cStamp = pStamp + stampDelta;
  215. u256 cNum = blockNumber;
  216. BlockHeader parent;
  217. parent.setTimestamp(pStamp);
  218. parent.setDifficulty(pDiff);
  219. parent.setNumber(cNum - 1);
  220. BlockHeader current;
  221. current.setTimestamp(cStamp);
  222. current.setNumber(cNum);
  223. string tmptest = c_testDifficulty;
  224. std::map<string, string> replaceMap;
  225. replaceMap["[N]"] = toString(testN);
  226. replaceMap["[PDIFF]"] = toCompactHex(pDiff, HexPrefix::Add);
  227. replaceMap["[PSTAMP]"] = toCompactHex(pStamp, HexPrefix::Add);
  228. replaceMap["[СSTAMP]"] = toCompactHex(cStamp, HexPrefix::Add);
  229. replaceMap["[CNUM]"] = toCompactHex(cNum, HexPrefix::Add);
  230. replaceMap["[CDIFF]"] = toCompactHex(sealEngine.calculateDifficulty(current, parent), HexPrefix::Add);
  231. dev::test::RandomCode::parseTestWithTypes(tmptest, replaceMap);
  232. finalTest << tmptest;
  233. }
  234. finalTest << std::endl << "}";
  235. string testFile = finalTest.str();
  236. testFile = testFile.replace(testFile.find_last_of(","), 1, "");
  237. writeFile(testFileFullName, asBytes(testFile));
  238. }
  239. testDifficulty(testFileFullName, sealEngine, Network::HomesteadTest);
  240. }
  241. BOOST_AUTO_TEST_CASE(basicDifficultyTest)
  242. {
  243. string testPath = test::getTestPath();
  244. testPath += "/BasicTests/difficulty.json";
  245. Ethash sealEngine;
  246. sealEngine.setChainParams(ChainParams(genesisInfo(Network::Frontier)));
  247. testDifficulty(testPath, sealEngine, Network::Frontier);
  248. }
  249. BOOST_AUTO_TEST_SUITE_END()