Fabcoin Core  0.16.2
P2P Digital Currency
difficulty.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
23 #include <boost/test/unit_test.hpp>
26 #include <libethashseal/Ethash.h>
29 using namespace std;
30 using namespace dev;
31 using namespace dev::eth;
32 
33 namespace js = json_spirit;
34 std::string const c_testDifficulty = R"(
35  "DifficultyTest[N]" : {
36  "parentTimestamp" : "[PSTAMP]",
37  "parentDifficulty" : "[PDIFF]",
38  "currentTimestamp" : "[СSTAMP]",
39  "currentBlockNumber" : "[CNUM]",
40  "currentDifficulty" : "[CDIFF]"
41  },
42 )";
43 
44 void checkCalculatedDifficulty(BlockHeader const& _bi, BlockHeader const& _parent, Network _n, ChainOperationParams const& _p, string const& _testName = "")
45 {
46  u256 difficulty = _bi.difficulty();
47  u256 frontierDiff = _p.u256Param("homsteadForkBlock");
48 
49  //The ultimate formula (Homestead)
50  if (_bi.number() > frontierDiff)
51  {
52  u256 minimumDifficulty = _p.u256Param("minimumDifficulty");
53  bigint block_diff = _parent.difficulty();
54 
55  bigint a = (_parent.difficulty() / 2048);
56  int b = 1 - int(_bi.timestamp() - _parent.timestamp()) / 10;
57  bigint c = (_bi.number() / 100000) - 2;
58 
59  block_diff += a * max<int>(b, -99);
60  block_diff += u256(1) << (unsigned)c;
61  block_diff = max<bigint>(minimumDifficulty, block_diff);
62 
63  BOOST_CHECK_MESSAGE(difficulty == block_diff, "Homestead Check Calculated diff = " << difficulty << " expected diff = " << block_diff << _testName);
64  return;
65  }
66 
67  u256 durationLimit;
68  u256 minimumDifficulty;
69  u256 difficultyBoundDivisor;
70  switch(_n)
71  {
72  case Network::MainNetwork:
73  case Network::FrontierTest:
74  case Network::HomesteadTest:
75  case Network::Ropsten:
76  case Network::TransitionnetTest:
77  durationLimit = 13;
78  minimumDifficulty = 131072;
79  difficultyBoundDivisor = 2048;
80  break;
81  default:
82  cerr << "testing undefined network difficulty";
83  durationLimit = _p.u256Param("durationLimit");
84  minimumDifficulty = _p.u256Param("minimumDifficulty");
85  difficultyBoundDivisor = _p.u256Param("difficultyBoundDivisor");
86  break;
87  }
88 
89  //Frontier Era
90  bigint block_diff = _parent.difficulty();
91 
92  bigint a = (_parent.difficulty() / difficultyBoundDivisor);
93  bigint b = ((_bi.timestamp() - _parent.timestamp()) < durationLimit) ? 1 : -1;
94  bigint c = (_bi.number() / 100000) - 2;
95 
96  block_diff += a * b;
97  block_diff += u256(1) << (unsigned)c;
98  block_diff = max<bigint>(minimumDifficulty, block_diff);
99 
100  BOOST_CHECK_MESSAGE(difficulty == block_diff, "Check Calculated diff = " << difficulty << " expected diff = " << block_diff << _testName);
101  return;
102 }
103 
104 void fillDifficulty(string const& _testFileFullName, Ethash& _sealEngine)
105 {
106  int testN = 0;
107  ostringstream finalTest;
108  finalTest << "{" << std::endl;
110 
111  for (int stampDelta = 0; stampDelta < 45; stampDelta+=2)
112  {
113  for (u256 blockNumber = 1; blockNumber < 1500000; blockNumber += 25000)
114  {
115  testN++;
117  string testName = "DifficultyTest"+toString(testN);
118  if (!dev::test::TestOutputHelper::passTest(m, testName))
119  continue;
120 
123  u256 cStamp = pStamp + stampDelta;
124  u256 cNum = blockNumber;
125 
126  BlockHeader parent;
127  parent.setTimestamp(pStamp);
128  parent.setDifficulty(pDiff);
129  parent.setNumber(cNum - 1);
130 
131  BlockHeader current;
132  current.setTimestamp(cStamp);
133  current.setNumber(cNum);
134 
135  string tmptest = c_testDifficulty;
136  std::map<string, string> replaceMap;
137  replaceMap["[N]"] = toString(testN);
138  replaceMap["[PDIFF]"] = toCompactHex(pDiff, HexPrefix::Add);
139  replaceMap["[PSTAMP]"] = toCompactHex(pStamp, HexPrefix::Add);
140  replaceMap["[СSTAMP]"] = toCompactHex(cStamp, HexPrefix::Add);
141  replaceMap["[CNUM]"] = toCompactHex(cNum, HexPrefix::Add);
142  replaceMap["[CDIFF]"] = toCompactHex(_sealEngine.calculateDifficulty(current, parent), HexPrefix::Add);
143 
144  dev::test::RandomCode::parseTestWithTypes(tmptest, replaceMap);
145  finalTest << tmptest;
146  }
147  }
148 
149  finalTest << std::endl << "}";
150  string testFile = finalTest.str();
151  testFile = testFile.replace(testFile.find_last_of(","), 1, "");
152  writeFile(_testFileFullName, asBytes(testFile));
153 }
154 
155 void testDifficulty(string const& _testFileFullName, Ethash& _sealEngine, Network _n)
156 {
157  //Test File
158  js::mValue v;
159  string s = contentsString(_testFileFullName);
160  BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of '" << _testFileFullName << "' is empty. Have you cloned the 'tests' repo branch develop?");
161  js::read_string(s, v);
163 
164  for (auto& i: v.get_obj())
165  {
166  js::mObject o = i.second.get_obj();
167  string testname = i.first;
168  if (!dev::test::TestOutputHelper::passTest(o, testname))
169  continue;
170 
171  BlockHeader parent;
172  parent.setTimestamp(test::toInt(o["parentTimestamp"]));
173  parent.setDifficulty(test::toInt(o["parentDifficulty"]));
174  parent.setNumber(test::toInt(o["currentBlockNumber"]) - 1);
175 
176  BlockHeader current;
177  current.setTimestamp(test::toInt(o["currentTimestamp"]));
178  current.setNumber(test::toInt(o["currentBlockNumber"]));
179 
180  u256 difficulty = _sealEngine.calculateDifficulty(current, parent);
181  current.setDifficulty(difficulty);
182  BOOST_CHECK_EQUAL(difficulty, test::toInt(o["currentDifficulty"]));
183 
184  //Manual formula test
185  checkCalculatedDifficulty(current, parent, _n, _sealEngine.chainParams(), "(" + i.first + ")");
186  }
188 }
189 
190 BOOST_AUTO_TEST_SUITE(DifficultyTests)
191 
192 BOOST_AUTO_TEST_CASE(difficultyTestsFrontier)
193 {
194  string testFileFullName = test::getTestPath();
195  testFileFullName += "/BasicTests/difficultyFrontier.json";
196 
197  Ethash sealEngine;
198  sealEngine.setChainParams(ChainParams(genesisInfo(Network::FrontierTest)));
199 
200  if (dev::test::Options::get().filltests)
201  fillDifficulty(testFileFullName, sealEngine);
202 
203  testDifficulty(testFileFullName, sealEngine, Network::FrontierTest);
204 }
205 
206 BOOST_AUTO_TEST_CASE(difficultyTestsRopsten)
207 {
208  string testFileFullName = test::getTestPath();
209  testFileFullName += "/BasicTests/difficultyRopsten.json";
210 
211  Ethash sealEngine;
212  sealEngine.setChainParams(ChainParams(genesisInfo(Network::Ropsten)));
213 
214  if (dev::test::Options::get().filltests)
215  fillDifficulty(testFileFullName, sealEngine);
216 
217  testDifficulty(testFileFullName, sealEngine, Network::Ropsten);
218 }
219 
220 BOOST_AUTO_TEST_CASE(difficultyTestsHomestead)
221 {
222  string testFileFullName = test::getTestPath();
223  testFileFullName += "/BasicTests/difficultyHomestead.json";
224 
225  Ethash sealEngine;
226  sealEngine.setChainParams(ChainParams(genesisInfo(Network::HomesteadTest)));
227 
228  if (dev::test::Options::get().filltests)
229  fillDifficulty(testFileFullName, sealEngine);
230 
231  testDifficulty(testFileFullName, sealEngine, Network::HomesteadTest);
232 }
233 
234 BOOST_AUTO_TEST_CASE(difficultyTestsMainNetwork)
235 {
236  string testFileFullName = test::getTestPath();
237  testFileFullName += "/BasicTests/difficultyMainNetwork.json";
238 
239  Ethash sealEngine;
240  sealEngine.setChainParams(ChainParams(genesisInfo(Network::MainNetwork)));
241 
242  if (dev::test::Options::get().filltests)
243  fillDifficulty(testFileFullName, sealEngine);
244 
245  testDifficulty(testFileFullName, sealEngine, Network::MainNetwork);
246 }
247 
248 BOOST_AUTO_TEST_CASE(difficultyTestsCustomMainNetwork)
249 {
250  string testFileFullName = test::getTestPath();
251  testFileFullName += "/BasicTests/difficultyCustomMainNetwork.json";
252 
253  Ethash sealEngine;
254  sealEngine.setChainParams(ChainParams(genesisInfo(Network::MainNetwork)));
255 
256  if (dev::test::Options::get().filltests)
257  {
258  u256 homsteadBlockNumber = 1000000;
259  std::vector<u256> blockNumberVector = {homsteadBlockNumber - 100000, homsteadBlockNumber, homsteadBlockNumber + 100000};
260  std::vector<u256> parentDifficultyVector = {1000, 2048, 4000, 1000000};
261  std::vector<int> timestampDeltaVector = {0, 1, 8, 10, 13, 20, 100, 800, 1000, 1500};
262 
263  int testN = 0;
264  ostringstream finalTest;
265  finalTest << "{" << std::endl;
266 
267  for (size_t bN = 0; bN < blockNumberVector.size(); bN++)
268  for (size_t pdN = 0; pdN < parentDifficultyVector.size(); pdN++)
269  for (size_t tsN = 0; tsN < timestampDeltaVector.size(); tsN++)
270  {
271  testN++;
272  int stampDelta = timestampDeltaVector.at(tsN);
273  u256 blockNumber = blockNumberVector.at(bN);
274  u256 pDiff = parentDifficultyVector.at(pdN);
275 
277  u256 cStamp = pStamp + stampDelta;
278  u256 cNum = blockNumber;
279 
280  BlockHeader parent;
281  parent.setTimestamp(pStamp);
282  parent.setDifficulty(pDiff);
283  parent.setNumber(cNum - 1);
284 
285  BlockHeader current;
286  current.setTimestamp(cStamp);
287  current.setNumber(cNum);
288 
289  string tmptest = c_testDifficulty;
290  std::map<string, string> replaceMap;
291  replaceMap["[N]"] = toString(testN);
292  replaceMap["[PDIFF]"] = toCompactHex(pDiff, HexPrefix::Add);
293  replaceMap["[PSTAMP]"] = toCompactHex(pStamp, HexPrefix::Add);
294  replaceMap["[СSTAMP]"] = toCompactHex(cStamp, HexPrefix::Add);
295  replaceMap["[CNUM]"] = toCompactHex(cNum, HexPrefix::Add);
296  replaceMap["[CDIFF]"] = toCompactHex(sealEngine.calculateDifficulty(current, parent), HexPrefix::Add);
297 
298  dev::test::RandomCode::parseTestWithTypes(tmptest, replaceMap);
299  finalTest << tmptest;
300  }
301 
302  finalTest << std::endl << "}";
303  string testFile = finalTest.str();
304  testFile = testFile.replace(testFile.find_last_of(","), 1, "");
305  writeFile(testFileFullName, asBytes(testFile));
306  }
307 
308  testDifficulty(testFileFullName, sealEngine, Network::MainNetwork);
309 }
310 
311 BOOST_AUTO_TEST_CASE(basicDifficultyTest)
312 {
313  string testPath = test::getTestPath();
314  testPath += "/BasicTests/difficulty.json";
315 
316  Ethash sealEngine;
317  sealEngine.setChainParams(ChainParams(genesisInfo(Network::MainNetwork)));
318 
319  testDifficulty(testPath, sealEngine, Network::MainNetwork);
320 }
321 
const Object & get_obj() const
std::string toCompactHex(u256 val, HexPrefix prefix=HexPrefix::DontAdd, unsigned _min=0)
Definition: CommonData.h:175
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
void testDifficulty(string const &_testFileFullName, Ethash &_sealEngine, Network _n)
Definition: difficulty.cpp:155
u256 const & number() const
Definition: BlockHeader.h:162
static Options const & get(int argc=0, char **argv=0)
Get reference to options The first time used, options are parsed with argc, argv. ...
Definition: Options.cpp:203
ChainOperationParams const & chainParams() const
Definition: SealEngine.h:75
Network
The network id.
Definition: GenesisInfo.h:34
void fillDifficulty(string const &_testFileFullName, Ethash &_sealEngine)
Definition: difficulty.cpp:104
Encapsulation of a block header.
Definition: BlockHeader.h:95
void writeFile(std::string const &_file, bytesConstRef _data, bool _writeDeleteRename=false)
Write the given binary data into the given file, replacing the file if it pre-exists.
Definition: CommonIO.cpp:107
boost::multiprecision::number< boost::multiprecision::cpp_int_backend<>> bigint
Definition: Common.h:121
#define c(i)
std::hash for asio::adress
Definition: Common.h:323
std::string contentsString(std::string const &_file)
Retrieve and returns the contents of the given file as a std::string.
int Add(word *C, const word *A, const word *B, size_t N)
Definition: integer.cpp:2143
std::string toString(string32 const &_s)
Make normal string from fixed-length string.
Definition: CommonData.cpp:141
BOOST_AUTO_TEST_CASE(difficultyTestsFrontier)
Definition: difficulty.cpp:192
std::string const c_testDifficulty
Definition: difficulty.cpp:34
void setTimestamp(u256 const &_v)
Definition: BlockHeader.h:142
#define a(i)
bool read_string(const String_type &s, Value_type &value)
void setNumber(u256 const &_v)
Definition: BlockHeader.h:146
std::string getTestPath()
Definition: Common.cpp:35
static void parseTestWithTypes(std::string &_test, std::map< std::string, std::string > const &_varMap)
Replace keywords in given string with values.
void checkCalculatedDifficulty(BlockHeader const &_bi, BlockHeader const &_parent, Network _n, ChainOperationParams const &_p, string const &_testName="")
Definition: difficulty.cpp:44
bytes asBytes(std::string const &_b)
Converts a string to a byte array containing the string&#39;s (byte) data.
Definition: CommonData.h:92
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
u256 calculateDifficulty(BlockHeader const &_bi, BlockHeader const &_parent) const
Definition: Ethash.cpp:182
#define b(i, j)
u256 const & timestamp() const
Definition: BlockHeader.h:156
mConfig::Object_type mObject
u256 u256Param(std::string const &_name) const
Convenience method to get an otherParam as a u256 int.
std::string const & genesisInfo(Network _n)
Definition: GenesisInfo.cpp:37
static u256 randomUniInt(u256 _maxVal=0)
Definition: fuzzHelper.cpp:259
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
void setChainParams(ChainOperationParams const &_params)
Definition: SealEngine.h:76
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16
u256 const & difficulty() const
Definition: BlockHeader.h:166
void setDifficulty(u256 const &_v)
Definition: BlockHeader.h:150
u256 toInt(json_spirit::mValue const &_v)
Definition: TestHelper.cpp:195
Helper functions to work with json::spirit and test files.
static void initTest(int _maxTests=1)
static bool passTest(json_spirit::mObject &_o, std::string &_testName)