From e333a779338ff8bccdc4225fc953d6f4f0226db0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Sep 2016 22:59:03 -0400 Subject: add proof of work to countobjects In this case, an empty string is hashed to generate the PoW. --- HTTP/Client.hs | 2 +- HTTP/ProofOfWork.hs | 23 +++++++++++++++++------ HTTP/RateLimit.hs | 7 +++---- HTTP/Server.hs | 5 +++-- 4 files changed, 24 insertions(+), 13 deletions(-) (limited to 'HTTP') diff --git a/HTTP/Client.hs b/HTTP/Client.hs index 8f81db4..74381be 100644 --- a/HTTP/Client.hs +++ b/HTTP/Client.hs @@ -20,5 +20,5 @@ httpAPI = Proxy motd :: Manager -> BaseUrl -> ClientM Motd getObject :: StorableObjectIdent -> Maybe ProofOfWork -> Manager -> BaseUrl -> ClientM (POWGuarded StorableObject) putObject :: StorableObjectIdent -> Maybe ProofOfWork -> StorableObject -> Manager -> BaseUrl -> ClientM (POWGuarded StoreResult) -countObjects :: Manager -> BaseUrl -> ClientM CountResult +countObjects :: Maybe ProofOfWork -> Manager -> BaseUrl -> ClientM (POWGuarded CountResult) motd :<|> getObject :<|> putObject :<|> countObjects = client httpAPI diff --git a/HTTP/ProofOfWork.hs b/HTTP/ProofOfWork.hs index 04aec57..ef6ecfb 100644 --- a/HTTP/ProofOfWork.hs +++ b/HTTP/ProofOfWork.hs @@ -82,8 +82,19 @@ mkRandomSalt = do instance Raaz.Random Word8 -isValidProofOfWork :: ProofOfWork -> ProofOfWorkRequirement -> StorableObjectIdent -> Bool -isValidProofOfWork (ProofOfWork pow rsalt) req (StorableObjectIdent n) = +class POWIdent p where + getPOWIdent :: p -> B.ByteString + +instance POWIdent StorableObjectIdent where + getPOWIdent (StorableObjectIdent i) = i + +data NoPOWIdent = NoPOWIdent + +instance POWIdent NoPOWIdent where + getPOWIdent NoPOWIdent = B.empty + +isValidProofOfWork :: POWIdent p => ProofOfWork -> ProofOfWorkRequirement -> p -> Bool +isValidProofOfWork (ProofOfWork pow rsalt) req p = samesalts && enoughzeros where samesalts = rsalt == randomSalt req @@ -91,7 +102,7 @@ isValidProofOfWork (ProofOfWork pow rsalt) req (StorableObjectIdent n) = tunable = proofOfWorkHashTunable (addedArgon2Iterations req) salt = Salt $ POWSalt $ encodeUtf8 (fromRandomSalt (randomSalt req)) <> pow - ExpensiveHash _ hash = expensiveHash tunable salt n + ExpensiveHash _ hash = expensiveHash tunable salt (getPOWIdent p) -- Since expensiveHash generates an ascii encoded hash that -- includes the parameters, take the sha256 of it to get the -- bytestring that is what's checked for the neccesary number @@ -109,12 +120,12 @@ instance Encodable POWSalt where toByteString (POWSalt n) = n fromByteString = Just . POWSalt -genProofOfWork :: ProofOfWorkRequirement -> StorableObjectIdent -> ProofOfWork -genProofOfWork req i = go allByteStrings +genProofOfWork :: POWIdent p => ProofOfWorkRequirement -> p -> ProofOfWork +genProofOfWork req p = go allByteStrings where go [] = error "failed to generate Proof Of Work. This should be impossible!" go (b:bs) - | isValidProofOfWork candidate req i = candidate + | isValidProofOfWork candidate req p = candidate | otherwise = go bs where candidate = ProofOfWork b (randomSalt req) diff --git a/HTTP/RateLimit.hs b/HTTP/RateLimit.hs index 9153664..737f7dc 100644 --- a/HTTP/RateLimit.hs +++ b/HTTP/RateLimit.hs @@ -5,7 +5,6 @@ module HTTP.RateLimit where -import Types import Types.Cost import HTTP import HTTP.ProofOfWork @@ -107,8 +106,8 @@ fillRate = 60000000 -- 1 token per minute -- If all buckets are tried and are empty, we must be very overloaded. -- In this case, the request is still processed, since the client has done -- quite a lot of work. -rateLimit :: RateLimiter -> Maybe ProofOfWork -> StorableObjectIdent -> Handler a -> Handler (POWGuarded a) -rateLimit ratelimiter mpow i a = do +rateLimit :: POWIdent p => RateLimiter -> Maybe ProofOfWork -> p -> Handler a -> Handler (POWGuarded a) +rateLimit ratelimiter mpow p a = do validsalt <- liftIO $ checkValidSalt ratelimiter mpow bs <- liftIO $ atomically $ readTMVar (buckets ratelimiter) if validsalt @@ -123,7 +122,7 @@ rateLimit ratelimiter mpow i a = do Just mkreq -> case mpow of Nothing -> assignWork ratelimiter (b:bs) Just pow@(ProofOfWork _ salt) -> - if isValidProofOfWork pow (mkreq salt) i + if isValidProofOfWork pow (mkreq salt) p then checkbucket b bs else assignWork ratelimiter (b:bs) checkbucket b bs = do diff --git a/HTTP/Server.hs b/HTTP/Server.hs index dd35d1c..65d3d32 100644 --- a/HTTP/Server.hs +++ b/HTTP/Server.hs @@ -85,8 +85,9 @@ validObjectsize o = any (sz ==) knownObjectSizes where sz = B.length (fromStorableObject o) -countObjects :: ServerState -> Handler CountResult -countObjects = liftIO . countShares . serverStorage +countObjects :: ServerState -> Maybe ProofOfWork -> Handler (POWGuarded CountResult) +countObjects st pow = rateLimit (rateLimiter st) pow NoPOWIdent $ + liftIO $ countShares $ serverStorage st -- | 1 is a dummy value; the server does not know the actual share numbers. dummyShareNum :: ShareNum -- cgit v1.2.3