diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp index 9ccb29eb2..7d1df2656 100644 --- a/src/cpp/ripple/ProofOfWork.cpp +++ b/src/cpp/ripple/ProofOfWork.cpp @@ -2,9 +2,14 @@ #include +#include + #include #include "Serializer.h" +#include "Log.h" + +SETUP_LOG(); const uint256 ProofOfWork::sMinTarget("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); const int ProofOfWork::sMaxIterations(1 << 23); @@ -16,26 +21,38 @@ bool ProofOfWork::isValid() const uint64 ProofOfWork::getDifficulty(const uint256& target, int iterations) { // calculate the approximate number of hashes required to solve this proof of work - if ((iterations > sMaxIterations) || (target < sMinTarget)); + if ((iterations > sMaxIterations) || (target < sMinTarget)) + { + cLog(lsINFO) << "Iterations:" << iterations; + cLog(lsINFO) << "MaxIterat: " << sMaxIterations; + cLog(lsINFO) << "Target: " << target; + cLog(lsINFO) << "MinTarget: " << sMinTarget; throw std::runtime_error("invalid proof of work target/iteration"); + } // more iterations means more hashes per iteration but also a larger final hash uint64 difficulty = iterations * (iterations / 4 + 1); - // Multiply the number of hashes needed by 16 for each leading zero in the hex difficulty - const unsigned char *ptr = target.begin(); + // Multiply the number of hashes needed by 256 for each leading zero byte in the hex difficulty + const unsigned char *ptr = target.end() - 1; while (*ptr == 0) { - difficulty *= 16; - ptr++; + cLog(lsINFO) << "getDif: " << (int) *ptr; + difficulty *= 256; + --ptr; } // If the first digit after a zero isn't an F, multiply - difficulty *= (16 - *ptr); + difficulty *= (256 - *ptr); return difficulty; } +static uint256 getSHA512Half(const std::vector& vec) +{ + return Serializer::getSHA512Half(vec.front().begin(), vec.size() * (256 / 8)); +} + uint256 ProofOfWork::solve(int maxIterations) const { if (!isValid()) @@ -44,23 +61,49 @@ uint256 ProofOfWork::solve(int maxIterations) const uint256 nonce; RAND_bytes(nonce.begin(), nonce.size()); - Serializer s1, s2; - std::vector buf; - buf.reserve((256 / 8) * mIterations); + std::vector buf2; + buf2.resize(mIterations); - while (maxIterations > 8) + std::vector buf1; + buf1.resize(3); + buf1[0] = mChallenge; + + while (maxIterations > 0) { - s1.add256(mChallenge); - s1.add256(nonce); -// uint256 base = s1.getSHA512Half(); - - for (int i = 0; i < mIterations; ++i) + buf1[1] = nonce; + buf1[2] = uint256(); + for (int i = (mIterations - 1); i >= 0; --i) { - // WRITEME + if (buf1.size() != 3) + Log(lsINFO) << "buf1.size=" << buf1.size(); + buf1[2] = getSHA512Half(buf1); + buf2[i] = buf1[2]; } + if (buf2.size() != mIterations) + Log(lsINFO) << "buf2.size=" << buf2.size(); - s1.erase(); - nonce++; + uint256 hash = getSHA512Half(buf2); + if (hash <= mTarget) + return nonce; + + ++nonce; + --maxIterations; } return uint256(); } + +BOOST_AUTO_TEST_SUITE(ProofOfWork_suite) + +BOOST_AUTO_TEST_CASE( ProofOfWork_test ) +{ + ProofOfWork pow("test", 32, uint256(), + uint256("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + cLog(lsINFO) << "Estimated difficulty: " << pow.getDifficulty(); + uint256 solution = pow.solve(16777216); + if (solution.isZero()) + BOOST_FAIL("Unable to solve proof of work"); +} + +BOOST_AUTO_TEST_SUITE_END() + +// vim:ts=4 diff --git a/src/cpp/ripple/ProofOfWork.h b/src/cpp/ripple/ProofOfWork.h index 1391be91c..6540b0713 100644 --- a/src/cpp/ripple/ProofOfWork.h +++ b/src/cpp/ripple/ProofOfWork.h @@ -10,6 +10,15 @@ #include "uint256.h" +enum POWResult +{ + powOK = 0, + powREUSED = 1, + powBADNONCE = 2, + powBADTOKEN = 3, + powEXPIRED = 4, +}; + class ProofOfWork { protected: @@ -48,6 +57,7 @@ protected: int mIterations; uint256 mTarget; time_t mLastDifficultyChange; + int mValidTime; powMap_t mSolvedChallenges; boost::mutex mLock; @@ -64,3 +74,5 @@ public: }; #endif + +// vim:ts=4