diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp index f31723a11..8d8d50b69 100644 --- a/src/cpp/ripple/ProofOfWork.cpp +++ b/src/cpp/ripple/ProofOfWork.cpp @@ -3,7 +3,7 @@ #include #include - +#include #include #include @@ -134,6 +134,60 @@ ProofOfWork ProofOfWorkGenerator::getProof() return ProofOfWork(s, mIterations, challenge, mTarget); } +POWResult ProofOfWorkGenerator::checkProof(const std::string& token, const uint256& solution) +{ // challenge - target - iterations - time - validator + + std::vector fields; + boost::split(fields, token, boost::algorithm::is_any_of("-")); + if (fields.size() != 5) + { + cLog(lsDEBUG) << "PoW " << token << " is corrupt"; + return powCORRUPT; + } + + std::string v = mSecret.GetHex() + fields[0] + "-" + fields[1] + "-" + fields[2] + "-" + fields[3]; + if (fields[4] != Serializer::getSHA512Half(v).GetHex()) + { + cLog(lsDEBUG) << "PoW " << token << " has a bad token"; + return powBADTOKEN; + } + + uint256 challenge, target; + challenge.SetHex(fields[0]); + target.SetHex(fields[1]); + + time_t t = lexical_cast_s(fields[3]); + time_t now = time(NULL); + + { + boost::mutex::scoped_lock sl(mLock); + if ((t * 4) > (now + mValidTime)) + { + cLog(lsDEBUG) << "PoW " << token << " has expired"; + return powEXPIRED; + } + } + + + ProofOfWork pow(token, lexical_cast_s(fields[2]), challenge, target); + if (!pow.checkSolution(solution)) + { + cLog(lsDEBUG) << "PoW " << token << " has a bad nonce"; + return powBADNONCE; + } + + { + boost::mutex::scoped_lock sl(mLock); + if (!mSolvedChallenges.insert(powMap_vt(now, challenge)).second) + { + cLog(lsDEBUG) << "PoW " << token << " has been reused"; + return powREUSED; + } + } + + return powOK; +} + BOOST_AUTO_TEST_SUITE(ProofOfWork_suite) BOOST_AUTO_TEST_CASE( ProofOfWork_test ) @@ -146,6 +200,15 @@ BOOST_AUTO_TEST_CASE( ProofOfWork_test ) BOOST_FAIL("Unable to solve proof of work"); if (!pow.checkSolution(solution)) BOOST_FAIL("Solution did not check"); + + cLog(lsDEBUG) << "A bad nonce error is expected"; + if (gen.checkProof(pow.getToken(), uint256()) != powBADNONCE) + BOOST_FAIL("Empty solution didn't show bad nonce"); + if (gen.checkProof(pow.getToken(), solution) != powOK) + BOOST_FAIL("Solution did not check with issuer"); + cLog(lsDEBUG) << "A reused nonce error is expected"; + if (gen.checkProof(pow.getToken(), solution) != powREUSED) + BOOST_FAIL("Reuse solution not detected"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/cpp/ripple/ProofOfWork.h b/src/cpp/ripple/ProofOfWork.h index 0e9a9337f..a09eec737 100644 --- a/src/cpp/ripple/ProofOfWork.h +++ b/src/cpp/ripple/ProofOfWork.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include "uint256.h" @@ -17,6 +17,7 @@ enum POWResult powBADNONCE = 2, powBADTOKEN = 3, powEXPIRED = 4, + powCORRUPT = 5, }; class ProofOfWork @@ -41,6 +42,9 @@ public: uint256 solve(int maxIterations) const; bool checkSolution(const uint256& solution) const; + const std::string& getToken() const { return mToken; } + const uint256& getChallenge() const { return mChallenge; } + // approximate number of hashes needed to solve static uint64 getDifficulty(const uint256& target, int iterations); uint64 getDifficulty() const { return getDifficulty(mTarget, mIterations); } @@ -49,7 +53,7 @@ public: class ProofOfWorkGenerator { public: - typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::set_of > powMap_t; + typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::unordered_set_of > powMap_t; typedef powMap_t::value_type powMap_vt; protected: @@ -66,11 +70,12 @@ public: ProofOfWorkGenerator(); ProofOfWork getProof(); - bool checkProof(const std::string& token, const uint256& solution); + POWResult checkProof(const std::string& token, const uint256& solution); + uint64 getDifficulty() { return ProofOfWork::getDifficulty(mTarget, mIterations); } void loadHigh(); void loadLow(); - uint64 getDifficulty() { return ProofOfWork::getDifficulty(mTarget, mIterations); } + void sweep(void); }; #endif