diff --git a/modules/ripple_main/ripple_main.cpp b/modules/ripple_main/ripple_main.cpp index 15662fc24..239234f54 100644 --- a/modules/ripple_main/ripple_main.cpp +++ b/modules/ripple_main/ripple_main.cpp @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -44,6 +47,7 @@ #include #include #include +//#include #include #include #include @@ -56,6 +60,7 @@ #include #include +//#include // is this needed? #include #include @@ -126,6 +131,9 @@ #include "src/cpp/ripple/AccountItems.h" #include "src/cpp/ripple/AccountSetTransactor.h" #include "src/cpp/ripple/AccountState.h" +#include "src/cpp/ripple/ripple_ProofOfWork.h" +#include "src/cpp/ripple/ripple_IProofOfWorkFactory.h" +#include "src/cpp/ripple/Peer.h" #include "src/cpp/ripple/Application.h" #include "src/cpp/ripple/AutoSocket.h" #include "src/cpp/ripple/CallRPC.h" @@ -158,9 +166,7 @@ #include "src/cpp/ripple/ParseSection.h" #include "src/cpp/ripple/Pathfinder.h" #include "src/cpp/ripple/PaymentTransactor.h" -#include "src/cpp/ripple/Peer.h" #include "src/cpp/ripple/PeerDoor.h" -#include "src/cpp/ripple/ProofOfWork.h" #include "src/cpp/ripple/RPC.h" #include "src/cpp/ripple/RPCDoor.h" #include "src/cpp/ripple/RPCErr.h" @@ -252,7 +258,8 @@ static DH* handleTmpDh(SSL* ssl, int is_export, int iKeyLength) #include "src/cpp/ripple/Peer.cpp" #include "src/cpp/ripple/PeerDoor.cpp" #include "src/cpp/ripple/PFRequest.cpp" -#include "src/cpp/ripple/ProofOfWork.cpp" +#include "src/cpp/ripple/ripple_ProofOfWork.cpp" +#include "src/cpp/ripple/ripple_ProofOfWorkFactory.cpp" #include "src/cpp/ripple/RegularKeySetTransactor.cpp" #include "src/cpp/ripple/RippleCalc.cpp" #include "src/cpp/ripple/RippleState.cpp" // no log diff --git a/newcoin.vcxproj b/newcoin.vcxproj index 489c5eb3d..140a2170e 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -930,12 +930,6 @@ true true - - true - true - true - true - true true @@ -976,12 +970,6 @@ true true - - true - true - true - true - true true @@ -1036,6 +1024,18 @@ true true + + true + true + true + true + + + true + true + true + true + true true @@ -1673,7 +1673,6 @@ - @@ -1681,7 +1680,6 @@ - @@ -1692,6 +1690,8 @@ + + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index e90414882..59c56148f 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -465,18 +465,12 @@ 1. Modules\ripple_main\_unfactored\types - - 1. Modules\ripple_main\_unfactored\types - 1. Modules\ripple_main\_unfactored\types 1. Modules\ripple_main\_unfactored\types - - 1. Modules\ripple_main\_unfactored\types - 1. Modules\ripple_basics @@ -813,6 +807,12 @@ 1. Modules\ripple_data\protocol + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored + @@ -1136,18 +1136,12 @@ 1. Modules\ripple_main\_unfactored\types - - 1. Modules\ripple_main\_unfactored\types - 1. Modules\ripple_main\_unfactored\types 1. Modules\ripple_main\_unfactored\types - - 1. Modules\ripple_main\_unfactored\types - 1. Modules\ripple_basics @@ -1511,6 +1505,12 @@ 1. Modules\ripple_data\protocol + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored + diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp index d50052a10..291aedba3 100644 --- a/src/cpp/ripple/Application.cpp +++ b/src/cpp/ripple/Application.cpp @@ -47,6 +47,7 @@ Application::Application () , mHashRouter (IHashRouter::New (IHashRouter::getDefaultHoldTime ())) , mValidations (IValidations::New ()) , mUNL (IUniqueNodeList::New (mIOService)) + , mProofOfWorkFactory (IProofOfWorkFactory::New ()) // VFALCO: End new stuff // VFALCO: TODO replace all NULL with nullptr , mRpcDB (NULL) diff --git a/src/cpp/ripple/Application.h b/src/cpp/ripple/Application.h index 457163a5b..33172a3f0 100644 --- a/src/cpp/ripple/Application.h +++ b/src/cpp/ripple/Application.h @@ -12,12 +12,10 @@ #include "LedgerAcquire.h" #include "TransactionMaster.h" #include "Wallet.h" -#include "Peer.h" #include "NetworkOPs.h" #include "WSDoor.h" #include "SNTPClient.h" #include "RPCHandler.h" -#include "ProofOfWork.h" #include "LoadManager.h" #include "TransactionQueue.h" #include "OrderBookDB.h" @@ -31,6 +29,7 @@ class IHashRouter; class ILoadFeeTrack; class IValidations; class IUniqueNodeList; +class IProofOfWorkFactory; class RPCDoor; class PeerDoor; @@ -54,7 +53,6 @@ class Application SLECache mSLECache; SNTPClient mSNTPClient; JobQueue mJobQueue; - ProofOfWorkGenerator mPOWGen; LoadManager mLoadMgr; TXQueue mTxnQueue; OrderBookDB mOrderBookDB; @@ -66,6 +64,7 @@ class Application beast::ScopedPointer mHashRouter; beast::ScopedPointer mValidations; beast::ScopedPointer mUNL; + beast::ScopedPointer mProofOfWorkFactory; // VFALCO: End Clean stuff DatabaseCon *mRpcDB, *mTxnDB, *mLedgerDB, *mWalletDB, *mNetNodeDB, *mPathFindDB, *mHashNodeDB; @@ -111,7 +110,6 @@ public: HashedObjectStore& getHashedObjectStore() { return mHashedObjectStore; } JobQueue& getJobQueue() { return mJobQueue; } boost::recursive_mutex& getMasterLock() { return mMasterLock; } - ProofOfWorkGenerator& getPowGen() { return mPOWGen; } LoadManager& getLoadManager() { return mLoadMgr; } TXQueue& getTxnQueue() { return mTxnQueue; } PeerDoor& getPeerDoor() { return *mPeerDoor; } @@ -123,6 +121,7 @@ public: IFeeVote& getFeeVote() { return *mFeeVote; } IHashRouter& getHashRouter() { return *mHashRouter; } IValidations& getValidations() { return *mValidations; } + IProofOfWorkFactory& getProofOfWorkFactory() { return *mProofOfWorkFactory; } // VFALCO: TODO, Move these to the .cpp bool running() { return mTxnDB != NULL; } // VFALCO: TODO, replace with nullptr when beast is available diff --git a/src/cpp/ripple/ConnectionPool.cpp b/src/cpp/ripple/ConnectionPool.cpp index 00564c779..38da9be9b 100644 --- a/src/cpp/ripple/ConnectionPool.cpp +++ b/src/cpp/ripple/ConnectionPool.cpp @@ -8,7 +8,6 @@ #include #include -#include "Peer.h" #include "PeerDoor.h" #include "Application.h" diff --git a/src/cpp/ripple/ConnectionPool.h b/src/cpp/ripple/ConnectionPool.h index af1305a96..503eccc42 100644 --- a/src/cpp/ripple/ConnectionPool.h +++ b/src/cpp/ripple/ConnectionPool.h @@ -6,8 +6,6 @@ #include #include -#include "Peer.h" - // // Access to the Ripple network. // diff --git a/src/cpp/ripple/LedgerAcquire.h b/src/cpp/ripple/LedgerAcquire.h index 88b96172f..df2470fa6 100644 --- a/src/cpp/ripple/LedgerAcquire.h +++ b/src/cpp/ripple/LedgerAcquire.h @@ -14,7 +14,6 @@ #include #include "Ledger.h" -#include "Peer.h" // How long before we try again to acquire the same ledger #ifndef LEDGER_REACQUIRE_INTERVAL diff --git a/src/cpp/ripple/LedgerConsensus.h b/src/cpp/ripple/LedgerConsensus.h index 7237c5128..a6686766e 100644 --- a/src/cpp/ripple/LedgerConsensus.h +++ b/src/cpp/ripple/LedgerConsensus.h @@ -11,7 +11,6 @@ #include "Transaction.h" #include "LedgerAcquire.h" #include "LedgerProposal.h" -#include "Peer.h" #include "CanonicalTXSet.h" #include "TransactionEngine.h" diff --git a/src/cpp/ripple/LedgerMaster.h b/src/cpp/ripple/LedgerMaster.h index 90e4ee7d0..ff88376c9 100644 --- a/src/cpp/ripple/LedgerMaster.h +++ b/src/cpp/ripple/LedgerMaster.h @@ -3,7 +3,6 @@ #include "Ledger.h" #include "LedgerHistory.h" -#include "Peer.h" #include "LedgerAcquire.h" #include "Transaction.h" #include "TransactionEngine.h" diff --git a/src/cpp/ripple/Peer.cpp b/src/cpp/ripple/Peer.cpp index ab84bd444..35bbefee5 100644 --- a/src/cpp/ripple/Peer.cpp +++ b/src/cpp/ripple/Peer.cpp @@ -6,7 +6,6 @@ #include #include "Version.h" -#include "Peer.h" #include "Application.h" #include "SerializedTransaction.h" @@ -1319,7 +1318,7 @@ void Peer::recvProofWork(ripple::TMProofWork& packet) } uint256 response; memcpy(response.begin(), packet.response().data(), 256 / 8); - POWResult r = theApp->getPowGen().checkProof(packet.token(), response); + POWResult r = theApp->getProofOfWorkFactory().checkProof(packet.token(), response); if (r == powOK) { // credit peer diff --git a/src/cpp/ripple/Peer.h b/src/cpp/ripple/Peer.h index 6cc2da0e4..53995ca99 100644 --- a/src/cpp/ripple/Peer.h +++ b/src/cpp/ripple/Peer.h @@ -10,7 +10,6 @@ #include "Ledger.h" #include "Transaction.h" -#include "ProofOfWork.h" #include "LoadManager.h" typedef std::pair ipPort; diff --git a/src/cpp/ripple/PeerDoor.h b/src/cpp/ripple/PeerDoor.h index 93b7f7619..8a7bd6f7c 100644 --- a/src/cpp/ripple/PeerDoor.h +++ b/src/cpp/ripple/PeerDoor.h @@ -4,8 +4,6 @@ #include #include -#include "Peer.h" - /* Handles incoming connections from other Peers */ diff --git a/src/cpp/ripple/ProofOfWork.h b/src/cpp/ripple/ProofOfWork.h deleted file mode 100644 index 994f2ac7a..000000000 --- a/src/cpp/ripple/ProofOfWork.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef PROOF_OF_WORK__H -#define PROOF_OF_WORK__H - -#include - -#include -#include -#include -#include - -enum POWResult -{ - powOK = 0, - powREUSED = 1, // already submitted - powBADNONCE = 2, // you didn't solve it - powEXPIRED = 3, // time is up - powCORRUPT = 4, - powTOOEASY = 5, // the difficulty increased too much while you solved it -}; - -bool powResultInfo(POWResult powCode, std::string& strToken, std::string& strHuman); - -class ProofOfWork -{ -public: - static const int sMaxDifficulty; - - typedef boost::shared_ptr pointer; - - ProofOfWork(const std::string& token, int iterations, const uint256& challenge, const uint256& target) : - mToken(token), mChallenge(challenge), mTarget(target), mIterations(iterations) - { ; } - - ProofOfWork(const std::string& token); - - bool isValid() const; - - uint256 solve(int maxIterations = 2 * sMaxIterations) 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); } - - static bool validateToken(const std::string& strToken); - -private: - std::string mToken; - uint256 mChallenge; - uint256 mTarget; - int mIterations; - - static const uint256 sMinTarget; - static const int sMaxIterations; -}; - -class ProofOfWorkGenerator -{ -public: - typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::unordered_set_of > powMap_t; - typedef powMap_t::value_type powMap_vt; - -public: - ProofOfWorkGenerator(); - - ProofOfWork getProof(); - POWResult checkProof(const std::string& token, const uint256& solution); - uint64 getDifficulty() { return ProofOfWork::getDifficulty(mTarget, mIterations); } - void setDifficulty(int i); - - void loadHigh(); - void loadLow(); - void sweep(void); - - const uint256& getSecret() const { return mSecret; } - void setSecret(const uint256& secret) { mSecret = secret; } - - static int getPowEntry(const uint256& target, int iterations); - -private: - uint256 mSecret; - int mIterations; - uint256 mTarget; - time_t mLastDifficultyChange; - int mValidTime; - int mPowEntry; - - powMap_t mSolvedChallenges; - boost::mutex mLock; -}; - -#endif - -// vim:ts=4 diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 7931afefd..bdb891947 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -20,7 +20,6 @@ #include "NicknameState.h" #include "Offer.h" #include "PFRequest.h" -#include "ProofOfWork.h" SETUP_LOG (RPCHandler) @@ -889,7 +888,7 @@ Json::Value RPCHandler::doProofCreate(Json::Value jvRequest, int& cost, ScopedLo if (jvRequest.isMember("difficulty") || jvRequest.isMember("secret")) { - ProofOfWorkGenerator pgGen; + ProofOfWorkFactory pgGen; if (jvRequest.isMember("difficulty")) { @@ -913,7 +912,7 @@ Json::Value RPCHandler::doProofCreate(Json::Value jvRequest, int& cost, ScopedLo jvResult["token"] = pgGen.getProof().getToken(); jvResult["secret"] = pgGen.getSecret().GetHex(); } else { - jvResult["token"] = theApp->getPowGen().getProof().getToken(); + jvResult["token"] = theApp->getProofOfWorkFactory().getProof().getToken(); } return jvResult; @@ -971,7 +970,7 @@ Json::Value RPCHandler::doProofVerify(Json::Value jvRequest, int& cost, ScopedLo POWResult prResult; if (jvRequest.isMember("difficulty") || jvRequest.isMember("secret")) { - ProofOfWorkGenerator pgGen; + ProofOfWorkFactory pgGen; if (jvRequest.isMember("difficulty")) { @@ -999,7 +998,7 @@ Json::Value RPCHandler::doProofVerify(Json::Value jvRequest, int& cost, ScopedLo else { // XXX Proof should not be marked as used from this - prResult = theApp->getPowGen().checkProof(strToken, uSolution); + prResult = theApp->getProofOfWorkFactory().checkProof(strToken, uSolution); } std::string sToken; diff --git a/src/cpp/ripple/ripple_IProofOfWorkFactory.h b/src/cpp/ripple/ripple_IProofOfWorkFactory.h new file mode 100644 index 000000000..bdedd663e --- /dev/null +++ b/src/cpp/ripple/ripple_IProofOfWorkFactory.h @@ -0,0 +1,54 @@ +#ifndef RIPPLE_IPROOFOFWORKFACTORY_H +#define RIPPLE_IPROOFOFWORKFACTORY_H + +enum POWResult +{ + powOK = 0, + powREUSED = 1, // already submitted + powBADNONCE = 2, // you didn't solve it + powEXPIRED = 3, // time is up + powCORRUPT = 4, + powTOOEASY = 5, // the difficulty increased too much while you solved it +}; + +// VFALCO: TODO move this to the class as a static member and rename it +bool powResultInfo (POWResult powCode, std::string& strToken, std::string& strHuman); + +class IProofOfWorkFactory +{ +public: + typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::unordered_set_of > powMap_t; + typedef powMap_t::value_type powMap_vt; + +public: + static IProofOfWorkFactory* New (); + + virtual ~IProofOfWorkFactory () { } + + // VFALCO: TODO which members can be const? + + virtual ProofOfWork getProof () = 0; + + virtual POWResult checkProof (const std::string& token, const uint256& solution) = 0; + + virtual uint64 getDifficulty() = 0; + + virtual void setDifficulty (int i) = 0; + + virtual void loadHigh () = 0; + + virtual void loadLow () = 0; + + virtual void sweep () = 0; + + virtual const uint256& getSecret () const = 0; + + virtual void setSecret (const uint256& secret) = 0; + +public: + static int getPowEntry (const uint256& target, int iterations); +}; + +#endif + +// vim:ts=4 diff --git a/src/cpp/ripple/ripple_ProofOfWork.cpp b/src/cpp/ripple/ripple_ProofOfWork.cpp new file mode 100644 index 000000000..84bde9870 --- /dev/null +++ b/src/cpp/ripple/ripple_ProofOfWork.cpp @@ -0,0 +1,172 @@ + +#include + +#include +#include +#include +#include + +#include + +SETUP_LOG (ProofOfWork) + +bool powResultInfo(POWResult powCode, std::string& strToken, std::string& strHuman) +{ + static struct { + POWResult powCode; + const char* cpToken; + const char* cpHuman; + } powResultInfoA[] = { + { powREUSED, "powREUSED", "Proof-of-work has already been used." }, + { powBADNONCE, "powBADNONCE", "The solution does not meet the required difficulty." }, + { powEXPIRED, "powEXPIRED", "Token is expired." }, + { powCORRUPT, "powCORRUPT", "Invalid token." }, + { powTOOEASY, "powTOOEASY", "Difficulty has increased since token was issued." }, + + { powOK, "powOK", "Valid proof-of-work." }, + }; + + int iIndex = NUMBER(powResultInfoA); + + while (iIndex-- && powResultInfoA[iIndex].powCode != powCode) + ; + + if (iIndex >= 0) + { + strToken = powResultInfoA[iIndex].cpToken; + strHuman = powResultInfoA[iIndex].cpHuman; + } + + return iIndex >= 0; +} + +const uint256 ProofOfWork::sMinTarget("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); +const int ProofOfWork::sMaxIterations(1 << 23); +const int ProofOfWork::sMaxDifficulty(30); + +ProofOfWork::ProofOfWork (const std::string& token, + int iterations, + const uint256& challenge, + const uint256& target) + : mToken (token) + , mChallenge (challenge) + , mTarget (target) + , mIterations (iterations) +{ +} + +ProofOfWork::ProofOfWork (const std::string& token) +{ + std::vector fields; + boost::split(fields, token, boost::algorithm::is_any_of("-")); + if (fields.size() != 5) + throw std::runtime_error("invalid token"); + + mToken = token; + mChallenge.SetHex(fields[0]); + mTarget.SetHex(fields[1]); + mIterations = lexical_cast_s(fields[2]); +} + +bool ProofOfWork::isValid() const +{ + if ((mIterations <= sMaxIterations) && (mTarget >= sMinTarget)) + return true; + WriteLog (lsWARNING, ProofOfWork) << "Invalid PoW: " << mIterations << ", " << mTarget; + return false; +} + +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)) + { + WriteLog (lsINFO, ProofOfWork) << "Iterations:" << iterations; + WriteLog (lsINFO, ProofOfWork) << "MaxIterat: " << sMaxIterations; + WriteLog (lsINFO, ProofOfWork) << "Target: " << target; + WriteLog (lsINFO, ProofOfWork) << "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 / 8); + + // Multiply the number of hashes needed by 256 for each leading zero byte in the difficulty + const unsigned char *ptr = target.begin(); + while (*ptr == 0) + { + difficulty *= 256; + ++ptr; + } + difficulty = (difficulty * 256) / (*ptr + 1); + + 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()) + throw std::runtime_error("invalid proof of work target/iteration"); + + uint256 nonce; + RandomNumbers::getInstance ().fill (&nonce); + + std::vector buf2; + buf2.resize(mIterations); + + std::vector buf1; + buf1.resize(3); + buf1[0] = mChallenge; + + while (maxIterations > 0) + { + buf1[1] = nonce; + buf1[2].zero(); + for (int i = (mIterations - 1); i >= 0; --i) + { + buf1[2] = getSHA512Half(buf1); + buf2[i] = buf1[2]; + } + + if (getSHA512Half(buf2) <= mTarget) + return nonce; + + ++nonce; + --maxIterations; + } + return uint256(); +} + +bool ProofOfWork::checkSolution(const uint256& solution) const +{ + if (mIterations > sMaxIterations) + return false; + + std::vector buf1; + buf1.push_back(mChallenge); + buf1.push_back(solution); + buf1.push_back(uint256()); + + std::vector buf2; + buf2.resize(mIterations); + for (int i = (mIterations - 1); i >= 0; --i) + { + buf1[2] = getSHA512Half(buf1); + buf2[i] = buf1[2]; + } + return getSHA512Half(buf2) <= mTarget; +} + +bool ProofOfWork::validateToken(const std::string& strToken) +{ + static boost::regex reToken("[[:xdigit:]]{64}-[[:xdigit:]]{64}-[[:digit:]]+-[[:digit:]]+-[[:xdigit:]]{64}"); + boost::smatch smMatch; + + return boost::regex_match(strToken, smMatch, reToken); +} + +// vim:ts=4 diff --git a/src/cpp/ripple/ripple_ProofOfWork.h b/src/cpp/ripple/ripple_ProofOfWork.h new file mode 100644 index 000000000..9a5872ab6 --- /dev/null +++ b/src/cpp/ripple/ripple_ProofOfWork.h @@ -0,0 +1,48 @@ +#ifndef RIPPLE_PROOFOFWORK_H +#define RIPPLE_PROOFOFWORK_H + +class ProofOfWork +{ +public: + static const int sMaxDifficulty; + + typedef boost::shared_ptr pointer; + + ProofOfWork (const std::string& token, + int iterations, + const uint256& challenge, + const uint256& target); + + explicit ProofOfWork (const std::string& token); + + bool isValid() const; + + uint256 solve(int maxIterations = 2 * sMaxIterations) const; + bool checkSolution(const uint256& solution) const; + + const std::string& getToken() const { return mToken; } + const uint256& getChallenge() const { return mChallenge; } + + uint64 getDifficulty() const + { + return getDifficulty(mTarget, mIterations); + } + + // approximate number of hashes needed to solve + static uint64 getDifficulty (const uint256& target, int iterations); + + static bool validateToken (const std::string& strToken); + +private: + std::string mToken; + uint256 mChallenge; + uint256 mTarget; + int mIterations; + + static const uint256 sMinTarget; + static const int sMaxIterations; +}; + +#endif + +// vim:ts=4 diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ripple_ProofOfWorkFactory.cpp similarity index 63% rename from src/cpp/ripple/ProofOfWork.cpp rename to src/cpp/ripple/ripple_ProofOfWorkFactory.cpp index 2d8a1e9fe..805080e4b 100644 --- a/src/cpp/ripple/ProofOfWork.cpp +++ b/src/cpp/ripple/ripple_ProofOfWorkFactory.cpp @@ -1,171 +1,44 @@ -#include "ProofOfWork.h" - #include - #include -#include -#include -#include -#include - -SETUP_LOG (ProofOfWork) - -bool powResultInfo(POWResult powCode, std::string& strToken, std::string& strHuman) +class ProofOfWorkFactory : public IProofOfWorkFactory { - static struct { - POWResult powCode; - const char* cpToken; - const char* cpHuman; - } powResultInfoA[] = { - { powREUSED, "powREUSED", "Proof-of-work has already been used." }, - { powBADNONCE, "powBADNONCE", "The solution does not meet the required difficulty." }, - { powEXPIRED, "powEXPIRED", "Token is expired." }, - { powCORRUPT, "powCORRUPT", "Invalid token." }, - { powTOOEASY, "powTOOEASY", "Difficulty has increased since token was issued." }, +public: + ProofOfWorkFactory (); - { powOK, "powOK", "Valid proof-of-work." }, - }; + ProofOfWork getProof(); + POWResult checkProof(const std::string& token, const uint256& solution); + uint64 getDifficulty() { return ProofOfWork::getDifficulty(mTarget, mIterations); } + void setDifficulty(int i); - int iIndex = NUMBER(powResultInfoA); + void loadHigh(); + void loadLow(); + void sweep(void); - while (iIndex-- && powResultInfoA[iIndex].powCode != powCode) - ; + const uint256& getSecret() const { return mSecret; } + void setSecret(const uint256& secret) { mSecret = secret; } - if (iIndex >= 0) - { - strToken = powResultInfoA[iIndex].cpToken; - strHuman = powResultInfoA[iIndex].cpHuman; - } + static int getPowEntry (const uint256& target, int iterations); - return iIndex >= 0; -} +private: + uint256 mSecret; + int mIterations; + uint256 mTarget; + time_t mLastDifficultyChange; + int mValidTime; + int mPowEntry; -const uint256 ProofOfWork::sMinTarget("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); -const int ProofOfWork::sMaxIterations(1 << 23); -const int ProofOfWork::sMaxDifficulty(30); + powMap_t mSolvedChallenges; + boost::mutex mLock; +}; -ProofOfWork::ProofOfWork(const std::string& token) -{ - std::vector fields; - boost::split(fields, token, boost::algorithm::is_any_of("-")); - if (fields.size() != 5) - throw std::runtime_error("invalid token"); - - mToken = token; - mChallenge.SetHex(fields[0]); - mTarget.SetHex(fields[1]); - mIterations = lexical_cast_s(fields[2]); -} - -bool ProofOfWork::isValid() const -{ - if ((mIterations <= sMaxIterations) && (mTarget >= sMinTarget)) - return true; - WriteLog (lsWARNING, ProofOfWork) << "Invalid PoW: " << mIterations << ", " << mTarget; - return false; -} - -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)) - { - WriteLog (lsINFO, ProofOfWork) << "Iterations:" << iterations; - WriteLog (lsINFO, ProofOfWork) << "MaxIterat: " << sMaxIterations; - WriteLog (lsINFO, ProofOfWork) << "Target: " << target; - WriteLog (lsINFO, ProofOfWork) << "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 / 8); - - // Multiply the number of hashes needed by 256 for each leading zero byte in the difficulty - const unsigned char *ptr = target.begin(); - while (*ptr == 0) - { - difficulty *= 256; - ++ptr; - } - difficulty = (difficulty * 256) / (*ptr + 1); - - 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()) - throw std::runtime_error("invalid proof of work target/iteration"); - - uint256 nonce; - RandomNumbers::getInstance ().fill (&nonce); - - std::vector buf2; - buf2.resize(mIterations); - - std::vector buf1; - buf1.resize(3); - buf1[0] = mChallenge; - - while (maxIterations > 0) - { - buf1[1] = nonce; - buf1[2].zero(); - for (int i = (mIterations - 1); i >= 0; --i) - { - buf1[2] = getSHA512Half(buf1); - buf2[i] = buf1[2]; - } - - if (getSHA512Half(buf2) <= mTarget) - return nonce; - - ++nonce; - --maxIterations; - } - return uint256(); -} - -bool ProofOfWork::checkSolution(const uint256& solution) const -{ - if (mIterations > sMaxIterations) - return false; - - std::vector buf1; - buf1.push_back(mChallenge); - buf1.push_back(solution); - buf1.push_back(uint256()); - - std::vector buf2; - buf2.resize(mIterations); - for (int i = (mIterations - 1); i >= 0; --i) - { - buf1[2] = getSHA512Half(buf1); - buf2[i] = buf1[2]; - } - return getSHA512Half(buf2) <= mTarget; -} - -bool ProofOfWork::validateToken(const std::string& strToken) -{ - static boost::regex reToken("[[:xdigit:]]{64}-[[:xdigit:]]{64}-[[:digit:]]+-[[:digit:]]+-[[:xdigit:]]{64}"); - boost::smatch smMatch; - - return boost::regex_match(strToken, smMatch, reToken); -} - -ProofOfWorkGenerator::ProofOfWorkGenerator() : mValidTime(180) +ProofOfWorkFactory::ProofOfWorkFactory() : mValidTime(180) { setDifficulty(1); RandomNumbers::getInstance ().fillBytes (mSecret.begin(), mSecret.size()); } -ProofOfWork ProofOfWorkGenerator::getProof() +ProofOfWork ProofOfWorkFactory::getProof() { // challenge - target - iterations - time - validator static boost::format f("%s-%s-%d-%d"); @@ -184,7 +57,7 @@ ProofOfWork ProofOfWorkGenerator::getProof() return ProofOfWork(s, mIterations, challenge, mTarget); } -POWResult ProofOfWorkGenerator::checkProof(const std::string& token, const uint256& solution) +POWResult ProofOfWorkFactory::checkProof(const std::string& token, const uint256& solution) { // challenge - target - iterations - time - validator std::vector fields; @@ -245,7 +118,7 @@ POWResult ProofOfWorkGenerator::checkProof(const std::string& token, const uint2 return powOK; } -void ProofOfWorkGenerator::sweep() +void ProofOfWorkFactory::sweep() { time_t expire = time(NULL) - mValidTime; @@ -261,7 +134,7 @@ void ProofOfWorkGenerator::sweep() } while(1); } -void ProofOfWorkGenerator::loadHigh() +void ProofOfWorkFactory::loadHigh() { time_t now = time(NULL); @@ -274,7 +147,7 @@ void ProofOfWorkGenerator::loadHigh() mLastDifficultyChange = now; } -void ProofOfWorkGenerator::loadLow() +void ProofOfWorkFactory::loadLow() { time_t now = time(NULL); @@ -335,7 +208,7 @@ PowEntry PowEntries[ProofOfWork::sMaxDifficulty + 1] = { "00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 77309411328, 8 MB }; -int ProofOfWorkGenerator::getPowEntry(const uint256& target, int iterations) +int ProofOfWorkFactory::getPowEntry(const uint256& target, int iterations) { for (int i = 0; i < 31; ++i) if (PowEntries[i].iterations == iterations) @@ -348,7 +221,7 @@ int ProofOfWorkGenerator::getPowEntry(const uint256& target, int iterations) return -1; } -void ProofOfWorkGenerator::setDifficulty(int i) +void ProofOfWorkFactory::setDifficulty(int i) { assert((i >= 0) && (i <= ProofOfWork::sMaxDifficulty)); time_t now = time(NULL); @@ -360,11 +233,16 @@ void ProofOfWorkGenerator::setDifficulty(int i) mLastDifficultyChange = now; } +IProofOfWorkFactory* IProofOfWorkFactory::New () +{ + return new ProofOfWorkFactory; +} + BOOST_AUTO_TEST_SUITE(ProofOfWork_suite) BOOST_AUTO_TEST_CASE( ProofOfWork_test ) { - ProofOfWorkGenerator gen; + ProofOfWorkFactory gen; ProofOfWork pow = gen.getProof(); WriteLog (lsINFO, ProofOfWork) << "Estimated difficulty: " << pow.getDifficulty(); uint256 solution = pow.solve(16777216);