diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp index 9ccb29eb25..7d1df26567 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 1391be91c3..6540b07130 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 diff --git a/src/cpp/ripple/uint256.h b/src/cpp/ripple/uint256.h index 3e2ab10e62..e7e5e449ee 100644 --- a/src/cpp/ripple/uint256.h +++ b/src/cpp/ripple/uint256.h @@ -23,7 +23,7 @@ #endif // These classes all store their values internally -// in little-endian form +// in big-endian form inline int Testuint256AdHoc(std::vector vArg); @@ -36,7 +36,7 @@ protected: enum { WIDTH=BITS/32 }; // This is really big-endian in byte order. - // We use unsigned int for speed. + // We sometimes use unsigned int for speed. unsigned int pn[WIDTH]; public: @@ -73,7 +73,7 @@ public: zero(); // Put in least significant bits. - ((uint64_t *) end())[-1] = htobe64(uHost); + ((uint64_t *) end())[-1] = htobe64(uHost); return *this; } @@ -105,10 +105,12 @@ public: base_uint& operator++() { // prefix operator - int i = WIDTH; - - while (i-- && !++pn[i]) - ; + for (int i = WIDTH - 1; i >= 0; --i) + { + pn[i] = htobe32(be32toh(pn[i]) + 1); + if (pn[i] != 0) + break; + } return *this; } @@ -124,10 +126,13 @@ public: base_uint& operator--() { - int i = WIDTH; - - while (i-- && !pn[i]--) - ; + for (int i = WIDTH - 1; i >= 0; --i) + { + uint32 prev = pn[i]; + pn[i] = htobe32(be32toh(pn[i]) - 1); + if (prev != 0) + break; + } return *this; } @@ -169,10 +174,14 @@ public: const unsigned char* pAEnd = a.end(); const unsigned char* pB = b.begin(); - while (pA != pAEnd && *pA == *pB) - pA++, pB++; + while (*pA == *pB) + { + if (++pA == pAEnd) + return 0; + ++pB; + } - return pA == pAEnd ? 0 : *pA < *pB ? -1 : *pA > *pB ? 1 : 0; + return (*pA < *pB) ? -1 : 1; } friend inline bool operator<(const base_uint& a, const base_uint& b)